I'm kind of a noob so please forgive me if this is a dumb question.
I am loading a page successfully using Model Binding in ASP.NET MVC 2. Now I want to use Model Binding to submit the results of a form, but I want to use a different Model that the one I loaded with. Is this possible? Or should I just use the same ViewModel for both purposes?
Yes it's definitely possible.
The only thing to remember is the name attributes on your form inputs must be the same as the properties in the viewmodel.
Currently I have a hand crafted form (no strongly typed helpers) which once posted binds to a view model.
Yes, that is possible. Your details controller action and create controller action are different methods so you can make them accept whatever types you want.
//
// GET /Test/12
public ActionResult Details(int id)
{
return View(new ViewModel{/*properties init*/});
}
//
// POST: /Test/Update
[HttpPost]
public ActionResult Update(UpdateModel model)
{
//Do something with the model
return RedirectToAction("Index");
}
Related
What is the most effective method in order to make all the fields on an MVC4 Razor empty when loading it (for example first loading or after backing to the page again)? If it is possible could you please suggest me a way with the help of Razor properties instead of using Javascript/jQuery.
It's a little difficult to make out what you're trying to do, but let's see if I can help.
Firstly, if you simply wanted to clear out a form's values after it's been posted, you can do that like so:
[HttpPost]
public ActionResult Index(ViewModel model)
{
ModelState.Clear();
model = new ViewModel();
return View(model);
}
Simply creating a new ViewModel isn't enough, as the ModelState dictionary will try to repopulate the form with the old values. This does what you want, but isn't really leveraging MVC to do what you want.
The better way to do it would be to redirect back to the action you use to display your form. Something like this:
public ActionResult Create()
{
var model = new ViewModel();
return View(model);
}
This is simply passing in an empty model to your form. Once the user fills out the form, and it's posted back to the server, you can handle it like so:
[HttpPost]
public ActionResult Create(ViewModel model)
{
if (ModelState.IsValid)
{
// Form data is valid so redirect back to display the form again
return RedirectToAction("Create");
}
// If we get here, redisplay the form with the fields filled in
// and errors shown
return View(model);
}
Simply calling a ModelState.Clear() will do the trick. You shouldn't have to instantiate the view model again.
A view displays (or collect) information about a Model.
So, if you pass an Empty model (that is: properties in null or blank or default values) it will "clear all fields".
All you have to do is invoking again the Action that displays the view, now passing an empty model.
EDIT:
You can do it in javascript, but then you have to duplicate and maintain the logic of what are default values.
In the process of updating a C# MVC 2.0 application!
I have a view “Signup” and another view “ForgotPassword”.
Each view have a with a submit button.
Each form is submitted to the same Controller but to two different ActionResult:
[HttpPost]
public ActionResult Signup(SignupModel signupModel)
{…}
[HttpPost]
public ActionResult ForgotPwd(ForgotPasswordModel forgotPasswordModel)
{…}
Upon completion my goal is to redirect the user to a “thankyou” page but based on where the user is coming from (either Signup or ForgotPassword) I wish to display a particular message (or a different UI).
Inside the same Controller, I created a “Thankyou” ActionResult:
public ViewResult Thankyou()
{
return View();
}
I was thinking of adding a parameter to my Thankyou() method which would allow me to know where the user is coming from (Signup or ForgotPwd). From there, make the “thankyou” page display the appropriate UI/message.
I’m looking for a clean and simple solution.
Should I create two View User Controls and show the appropriate one based on the parameter being passed?
In addition, instead of having an “ActionResult” for my Thankyou() method couldn’t I use a “PartialViewResult” ?
EDIT:
I was actually considering something along those lines…
Where ThankyouType is an Enum.
[HttpPost]
public ActionResult Signup(SignupModel signupModel)
{
//Validation code...
return View("Thankyou", ThankyouType.SignupDone);
}
[HttpPost]
public ActionResult ForgotPassword(ForgotPasswordModel forgotPasswordModel)
{
//Validation code...
return View("Thankyou", ThankyouType.ForgotPasswordDone);
}
And then have my “Thankyou” ViewResult like this:
public ViewResult Thankyou(ThankyouType type)
{
return View(type);
}
Doesn’t seem like I can create a strongly typed view based on Enum (unless I’m wrong).
Perhaps I’ll read more on PartialViewResults and/or find examples…but then again, I could be completely wrong.
I would personally give the ThankYou view a model that has the message you want to display, and have your two controller actions render the ThankYou view directly on success rather than calling a ThankYou action.
However, if you're sure you want a redirect, you may consider using the TempData collection to store a message or a key of some kind. The ThankYou controller can then retrieve this value and pass it to the View. This situation is what TempData was made for.
Edit
There's no reason you shouldn't be able to use an enum value as your model type, but if that gives you trouble you should at least be able to create a model type that has an enum property on it.
The strategy of sending the ThankYouType as part of the redirect request would work just fine, if that's what you prefer. The only potential downside is that it would look like this in the URL:
http://domain.com/controller/ThankYou?type=ForgotPasswordDone
I have no real arguments against it. There are lots of options. Use the one that feels best to you.
I have a login screen. When the login fails I don't want to return to that same screen with something like this:
return View(model);
What I would like to use is the following to take me to another screen:
return RedirectToAction("Index", "Home");
But how can I pass the model? I see some suggestions but these are related to MVC2. Is there some new feature with MVC3 that would allow me to do this?
Using the RedirectToAction method is basically calling Repsonse.Redirect(Server.Transfer, I always got those mixed up...but anyways). In order to get the ViewModel to that redirected action, you would have to send the parameters of the model in the URL string
return RedirectToAction("Index", "Home", new {prop1 = something, prop2 = something...etc});
However, there is no reason you cannot leverage off of TempData dictionary to maintain the ViewModel and not pass it in the URL parameters.
TempData["ViewModelItem"] = myViewModel;
Return RedirectToAction("Index", "Home");
public ActionResult Index(){
var model = (ViewModelType)TempData["ViewModelItem"];
}
NOTE The above code does not take into account null reference or type checking on the TempData item, which you would want to do.
You can use the MVCContrib strongly typed redirect to action: link
public ActionResult PayWithCreditCard(int id, Buyer user)
{
return this.RedirectToAction<AuctionController>(x => x.Pay(user, id));
}
There is no need to pass the model to RedirectToAction, as all this method does is to generate HTTP 301. This is NOT an equivalent of Server.Transfer.
You can use Html.Partial() to render a common control passing a certain model, or Html.Action() [see: http://haacked.com/archive/2009/11/18/aspnetmvc2-render-action.aspx]
It is considered outside of the proper design to call a controller method directly from another controller method. If you have some common functionality you want to reuse in multiple controllers then you should refactor it out to a separate entity (a service, maybe).
You might also want to taker a look at 13. Use PRG Pattern for Data Modification:
http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx
Update following initial comments
The model has an object in it called 'Account', of which there is an int propety (Account.AccountID)
ViewB has a form which collects some additional information - but also has a textbox which is populated with Model.Account.AccountID.
When I submit ViewB however, Model.Account becomes null.
Its probably easier to show a simplified version of what I have before I explain the issue:
[HttpGet]
public ActionResult ViewA()
{
return View(new BlahModel());
}
[HttpPost]
public ActionResult ViewA(BlahModel model)
{
if(there_was_a_problem)
return View("ViewA", model);
else
return View("ViewB", model);
}
// have tried both httppost, httpget and no attribute here
public ActionResult ViewB(BlahModel model)
{
return View(model);
}
I load up ViewA via a GET, fill in the strongly-typed form and submit - then the following View (either ViewA again or ViewB if the request had no problems) is fine ... it has full access to the whole model and can display the properties within it.
The problem is that if I then submit a form in ViewB (which posts to the ActionResult ViewB) - the model suddenly has null properties throughout, even though its using the same model - and prior to the post has picked up all the values sucessfully.
Any ideas?
Many thanks
Most likely - ViewB view does not render enough and model binder can't find values to bind.
Action argument is binded from form values. It does not matter if You pass model to view correctly. Rendering things out is what matters (or passing through query string/cookies).
Complementing Arnis L.'s answer, you can use a tool like Firebug to check that your model's parameters (or any parameters at all) are being sent along the request.
Just wondering, I strongly type these views in ASP.NET MVC and then use Request.Form on the submit controller to get the data out, validate it, put it in an object, send to database. Is there a way I can just send the object back from the View page since it is strongly typed instead of doing all this crap to just end up with an object again since I just started with one anyways?
You mean, model binding?
[AcceptVerbs (HttpVerbs.Post)]
public ActionResult UpdateUser (User user)
{
SaveUpdates ();
return View();
}
This will automatically initialize the User properties with the form values with the same names.
Look at this answer: ASP.Net MVC Custom Model Binding explanation
(source: odetocode.com)