In my ASP.NET MVC application I want to just update two variables in my Register method.
My register method in my controller looks like this(it hasn't got its own view, so im not sure what to return in this case):
[HttpPost]
public ActionResult Register(Container c)
{
String email = c.register.Email.ToString();
String password = c.register.Password.ToString();
return view();
}
My index view looks like this;
#model VoterMvcTest.Models.Container
#using(Html.BeginForm("Register", "Default1"))
{
#Html.LabelFor(o => o.register.Email)
#Html.EditorFor(o => o.register.Email)
#Html.LabelFor(o => o.register.Password)
#Html.EditorFor(o => o.register.Password)
<input class="button" type="submit" value="Register" />
}
And my model looks like this;
public class Container
{
public Login login { get; set; }
public Register register { get; set; }
}
public class Login
{
public string Email { get; set; }
public string Password { get; set; }
}
public class Register
{
public string Email { get; set; }
public string Password { get; set; }
}
When you click the button, I want the two variables email and password to be set, and available to use in another method. I'm not sure what I should return(The goal would be to stay in the same view). I've tried to redirect to the same view i'm currently at (index view), but it seems like that causes a postback and the variables are lost.
ASP.NET MVC does not have ViewState as you would have when using WebForms. So if you
perform a post and do not persist the data in either a database or a temporary memory
(session object for instance) you'll lose that data as soon as the request has finished.
If you do some kind of validation and determine that the user was well registered you
could redirect him to another view using:
return RedirectToAction("Index")
Try this one
return View("Index",c)
it will work
Related
I am having a twitter bootstraper tab, with 3 simples tabs (Caracteristiques, Certificat and Contrats)
the tabs are ajax load with asp.net mvc partialviews, they are tied with modelViews:
the partials views strongly tied to the type ViewModel:
// Load Certificat
public ActionResult Certificat()
{
var modelStaffs = _twitterTabsModel.GetStaffs();
return PartialView("_Certificat", modelStaffs);
}
// load Contrats
public ActionResult Contrats()
{
var modelJoueur = _twitterTabsModel.GetFirstJoueur();
return PartialView("_Contrats", modelJoueur );
}
the models:
public class TwitterTabModel
{
public ModelJoueur JoueurVM { get; set; }
public IEnumerable<ModelStaff> StaffVM { get; set; }
}
public class ModelStaff
{
public string NomStaff { get; set; }
public string FonctionStaff { get; set; }
}
public class ModelJoueur
{
public string NomJoueur { get; set; }
public string PrenomJoueur { get; set; }
}
the Caracteristiques Tab views:
#model Controls.Models.ViewModel.TwitterTabModel
<h2>Caracteristiques</h2>
#using (Html.BeginForm())
{
.... the tabs code ...
<p>
<input type="submit" value="Save" />
</p>
}
The tabs load fines, what I want to do is to include a submit button on the first razor view tab, it submit all the other models if loaded, however, when I get the post call, all the others models, JoueurVM and StaffVM are empty even though they are loaded. Why is it according to you ?
edit: This is the controller post code, nothing special, just trying to get the twitterTabModel:
[HttpPost]
public ActionResult Tabs(TwitterTabModel model)
{
return View();
}
Thanks
I figure a workaround, I pass the input values back as formcollection, instead of the overall model, well it it' s not clean, but well, it works as i can get all the values posted
I have a "New user" form both for admins and for regular users. Both form use the RegisterModel
public class RegisterModel
{
[Required]
public string Name { get; set; }
public string Email { get; set; }
[Required]
public string Password { get; set; }
}
The difference is that on my front end "New user" page I want users to provide their own password. But in back end, I want the system to generate the password.
Since I use the same RegisterModel for both forms, I get a validateion error in the back end saying Password is required..
I thought, I could solve this by adding this to my controller:
[HttpPost]
public ActionResult New(RegisterModel model)
{
model.Password = Membership.GeneratePassword(6, 1);
if (TryValidateModel(model))
{
// Do stuff
}
return View(model);
}
But I still get the error message Password is required.. Why is this the issue when I do call TryValidate in my controller?
What would be best practice for this issue, create a separate RegisterModelBackEnd or are there any other solutions to this?
When updating model manually, you do not need to use it as parameter in Action. Also, use this overload that lets you specify only the properties on which binding will occur.
protected internal bool TryUpdateModel<TModel>(
TModel model,
string[] includeProperties
)
where TModel : class
So, the working code will be
[HttpPost]
public ActionResult New()
{
RegisterModel model = new RegisterModel();
model.Password = Membership.GeneratePassword(6, 1);
if (TryValidateModel(model, new string[] {"Name", "Email"}))
{
// Do stuff
}
return View(model);
}
You can make this even simpler, using BindAttribute
[HttpPost]
public ActionResult New([Bind(Exlude="Password")]RegisterModel model)
{
if(ModelState.IsValid)
{
model.Password = Membership.GeneratePassword(6, 1);
// Do Stuff
}
return View(model);
}
And finally simplest and the best way
Define separate view models
I wonder if there is a way to validate just one of my models in the viewmodel send it to my action? I use the DataAnnotations as validate rules.
Like the if (!ModelState.IsValid)
let me know if the question is unclear and I will edit for a better explination
EDIT
my viewmodel looks like this
public class CompaniesViewModel
{
public Core.Model.Customer Company { get; set; }
public IEnumerable<SelectListItem> Items { get; set; }
public Core.Model.Meeting Meeting { get; set; }
}
What I want to do in this particular situation is to validate just Customer. I cant do the ModelState.IsValid then all get validated. So how can I do to just validate one of them like customer in this case. Hope this was more clear
There are a number of different ways you can do this. The first is to add a property called IsValid that checks the property. So something like:
public class Company
{
public bool IsValid
{
get { return GetValid() }
}
private bool IsValid()
{
if ( Some check here )
return false;
}
}
[HttpPost]
public ActionResult SomeAction(CompaniesViewModel model)
{
if (model.Company.IsValid)
{
}
}
However a better solution IMO would be just to post the Company to your controller rather than your entire view model. Just because your passing a view model to a view it doesn't mean that you need to post the entire view model back. When you create your HTML form specify only the properties you want to post back to your controller. So for example your controller would become:
[HttpPost]
public ActionResult SomeAction(Company company)
{
if (Model.IsValid)
{
}
}
Now when you check if Model.IsValid it just check company as that is all you've passed back to the controller.
At server side, you can try the ValidateModel(object) method, like in TryValidateModel(CompaniesViewModel.Company).
If you have enabled client sided validation, you need to post only the relevant entity. If you want to post all entities, but you need to validate only one, you can consider the following:
either removing the rules, using javascript ASP .NET MVC Disable Client Side Validation at Per-Field Level
or creating a Data-Transfer-Object, ie a View Model which has NO link to the Model, but reproduces the entities you want with the validation rules you want having applied in this scenario. Of course, then, you'll need in your controller or a model binder some way to bind from your ViewModel to your Model entities.
You can separate Customer Model to another class in your ViewModel and map that in Controller to a existing/new Customer:
public class CompaniesViewModel
{
public Company Company { get; set; }
public IEnumerable<SelectListItem> Items { get; set; }
public Core.Model.Meeting Meeting { get; set; }
}
//Validations for Company go here:
public class Company
{
public string CompanyId { get; set; }
[Required]
public string CompanyName { get; set; }
}
I have the folowing code in my view, however, I can see that I don`t have the values in the controller. What is wrong?
In the view I have,
<%
using (Html.BeginForm())
{%>
<%=Html.TextBox("Addresses[0].Line1") %>
<%=Html.TextBox("Addresses[0].Line2")%>
<%=Html.TextBox("Addresses[1].Line1")%>
<%=Html.TextBox("Addresses[1].Line2")%>
<input type="submit" name="submitForm" value="Save products" />
<%
}
%>
My classes are as follows:
public class Customer
{
public string FirstName { get; set; }
public string Lastname { get; set; }
public List<Address> Addresses { get; set; }
public Customer()
{
Addresses = new List<Address>();
}
}
public class Address
{
public int Line1 { get; set; }
public int Line2 { get; set; }
}
My controller as follows:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(Customer customer)
{
return View();
}
The parameter for your ActionResult is named customer, so the default model binder will be looking for that name in the form by default. I believe if you modify your code to the following it should pick it up:
<%=Html.TextBox("customer.Addresses[0].Line1") %>
<%=Html.TextBox("customer.Addresses[0].Line2")%>
<%=Html.TextBox("customer.Addresses[1].Line1")%>
<%=Html.TextBox("customer.Addresses[1].Line2")%>
Check to ensure your View is bound to the Customer model.
Also, when viewing the web page containing the form, view the source generated by the View to see if the fields are being properly named.
Finally, if none of the above helps, change the parameter in your Index action like so:
public ActionResult Index(FormCollection form)
then you can use the debugger to inspect the FormCollection object that is passed in to see exactly what the View is sending you.
In my MVC application I have a problem with passing data from view to controller. I have fairly complex domain classes:
public class TaskBase : PersistableObject
{
public virtual TaskCategory Category { get; set; }
public virtual IList<TaskNote> Notes { get; set; }
public virtual string TaskTitle { get; set; }
public virtual string TaskBody { get; set; }
public virtual DateTime? CreationTime { get; set; }
public virtual User CreatedBy { get; set; }
public virtual int CompletionRatio { get; set; }
}
public class MainTask : TaskBase
{
public virtual IList<TaskBase> ChildTasks { get; set; }
public virtual User AssignedTo { get; set; }
public virtual IList<TaskHistory> History { get; set; }
}
public class TaskFormModel : ViewDomainBase
{
public MainTask Task { get; set; }
public LoginForm LoginInfo { get; set; }
}
And in my view I want to pass an instance of TaskFormModel to the controller.
<%= Html.ActionLink<TaskController>("Edit Task", (x) => x.Edit(new TaskFormModel() { Task = item, LoginInfo = Model.LoginInfo }))%>
And here is the controller action:
public ActionResult Edit (TaskFormModel taskInfo)
{
return View(ViewPageName.TaskDetailsForm, task.Task);
}
In this action method taskInfo comes null even if I pass non-null instance from view. I think I have a binding problem here. I think, writing custom model binder requires every property to be converted and also when new fields added then binder class should also be changed, so I don't want custom model binder to do this. Is there any other way to pass data to controller in this scenario? Or could custom model binder can be coded so that less code written and also when new properies are added binder class will not need to be changed?
Edit After Comments: What I am trying to achieve is basically to pass an instance from one view to another view, without querying repository/db in my controller's action.
First version of answer:
Your GET edit method should be like:
public ActionResult Edit (int id)
{
var model = taskRepository.GetTaskEditModel(id);
return View(ViewPageName.TaskDetailsForm, model);
}
and ActionLink:
<%= Html.ActionLink("Edit Task", "Edit", "Task", new { model.Task.id })%>
If you want to pass complex objects to controller, you should wrap them up in html form and pass to POST action.
In my opinion you are doing something wrong.
As I understand: you are trying to instantiate a new object, pass it to browser and get it back.
well you cant.
If object you want to edit exists already in your storage, then you should alter your ActionLink to reference it by id, and instantiate it inside your Edit action.
Take a look at default strongly typed index views created by tooling.