I'm new to ASP.NET MVC so this could have an obvious answer. Right now I have a form in my view with a lot of input controls, so I have an action that looks like this:
public ActionResult MyAction(string formItemOne, int? formItemTwo, etc...)
It has like a dozen parameters, which is pretty ugly. I'm trying to change it to this:
public ActionResult MyAction(FormCollection formItems)
and then parse the items dynamically. But when I change to a FormCollection, the form items no longer "automagically" remember their values through postbacks. Why would changing to a FormCollection change this behavior? Anything simple I can do to get it working automagically again?
Thanks for the help,
~ Justin
Another solution is to use models instead of manipulating the raw values. Like this:
class MyModel
{
public string ItemOne { get; set; }
public int? ItemTwo { get; set; }
}
Then use this code:
public ActionResult MyAction(MyModel model)
{
// Do things with model.
return this.View(model);
}
In your view:
<%# Page Inherits="System.Web.Mvc.ViewPage<MyModel>" %>
<%= Html.TextBox("ItemOne", Model.ItemOne) %>
<%= Html.TextBox("ItemTwo", Model.ItemTwo) %>
To replace your big list of parameters with a single one, use a view model. If after the POST you return this model to your view, then your view will remember the values posted.
A view model is simply an class with your action parameters as public properties. For example, you could do something like this, replacing:
public ActionResult MyAction(string formItemOne, int? formItemTwo, etc...)
with
public ActionResult MyAction(FormItems formItems)
{
//your code...
return View(formItems);
}
where FormItems is
public class FormItems
{
public property string formItemOne {get; set;}
public property int? formItemTwo {get; set;}
}
You may see a complete example in Stephen Walter's post ASP.NET MVC Tip #50 – Create View Models.
Maybe because they aren't magically inserted into the ModelState dictionary anymore. Try inserting them there.
If you use UpdateModel() or TryUpdateModel() I think the values are gonna be persisted.
Related
Alright...this may be a bit backwards but, I only need to do it in one spot.
I have a Model
public class LoginModel : xxx.Models.PageVars
{
public Item.LoginAttempt LoginAttempt { get; set; }
public LoginModel()
{
// does a bunch of stuff here...mainly to set the layout properties from PageVar
this.LoginAttempt = new Item.LoginAttempt();
}
}
Login Attempt is a simple obj (for now)
// login attempt
public class LoginAttempt
{
public string Email { get; set; }
public string Password { get; set; }
}
My controller
public ActionResult Login()
{
return View("Login", new Models.LoginModel());
}
[HttpPost]
public ActionResult LoginAttempt(LoginAttempt model)
{
return View("Login", model);
}
In my view
#model xxx.Models.LoginModel
Is there a way to use the property of the obj/model from LoginModel for the #model.
I can get the values from FormCollection or request but...that's not optimal.
thoughts???
tnx
The model for your GET should match the model for your POST. Otherwise, you're not playing on the same field. In order to allow the binding of data from a POST to a model, the HTML Helpers will generate a name that matches the access path of the property in the view's model. In other words, in your form, based on the model being LoginModel, your field names will be LoginAttempt.Email and LoginAttempt.Password. But, in the POST action, you're accepting just LoginAttempt, so the modelbinder is expecting to see data for Email and Password, which it won't find.
There's actually not even any need for this nested class. Just put your Email and Password fields directly on LoginModel and use that for both your view and your POST parameter. Then, you won't have any issues because everything will match up.
Why don't you have the form post controller action accept the parent model LoginModel instead of LoginAttempt? That way, the default MVC model binding should automatically parse the submitted values into the LoginModel and you'll have acces to LoginAttempt.
If it isn't then your form needs to use the prefix values in the names of the properties on the form. This is done automatically when you use TextboxFor, DropdownListFor etc.
In your example, the names of the form fields should start with LoginAttempt.Email etc
I've seen it work 2 ways. First way would be to rename your LoginAttempt model parameter to be
[HttpPost]
public ActionResult LoginAttempt(LoginAttempt loginModel)
{
return View("Login", model);
}
But i would use the Bind(Prefix) option
[HttpPost]
public ActionResult LoginAttempt([Bind(Prefix="LoginModel")] LoginAttempt model)
{
return View("Login", model);
}
you can't really return model of type LoginAttempt to the view though so you'd have to do even more work to get it to work if you're set on doing it this way. You should probably be redirecting to a different page instead of returning the Login view if it succeeds. Other wise return new LoginModel() {LoginAttempt = model}
My main view uses
#model IEnumerable<Ortund.Models.Reward>
I'm trying to allow the user to do several things on this view without having to navigate away.
Specifically, I want the user to be able to do the following:
View rewards he/she has already claimed (rewards that this user is eligible to redeem)
Claim a new receipt and in so doing, add the reward associated with that receipt to his/her current rewards
Redeem part of the rewards that he/she is eligible for, or all of them at once
I'm using partial views to achieve this as I can set a new model for each partial.
It looks something like this:
/Home/Index
if (Request.Cookies["Ortund"] == null)
{
// render a login form
}
else
{
<p>#String.Format("Welcome, {0}!", Convert.ToString(Request.Cookies["Ortund"]["username"])) <a id="claim-link">Claim New</a> | <a id="redeem-link">Redeem</a></p>
#Html.Partial("_RewardsView")
<!-- Render the new claim and redemption views as well -->
<div class="claim-new">
#Html.Partial("_ClaimsView")
</div>
<div class="redemption">
#Html.Partial("_RedemptionView")
</div>
_RewardsView
#model IEnumerable<Ortund.Models.Reward>
....
_ClaimsView
#model Ortund.Models.Receipt
....
_RedemptionView
#model IEnumerable<Ortund.Models.Reward>
....
I understand that view models are the preferred approach, but as I haven't yet worked out how to correctly use one, I'm going with this approach.
I've done this on another project, but this time I'm getting an error saying that the dictionary time that the view requires is different to the one being supplied (in this specific instance, we're getting confusion between Receipts and Rewards).
I'm not exactly sure what to do about this except to build the forms manually with no associations to the models, but rather to post to the correct controller...
What if you use one model, but build like this:
public class MainModel{
public fakeOneModel fakeModelOneView{get; set;}
public fakeTwomodel fakeModelTwoView{get; set;}
public fakeThreemodel fakeModelThreeView{get; set;}
}
public class fakeOneModel{
public string objectA1 {get; set;}
public string objectA2 {get; set;}
public string objectA3 {get; set;}
}
public class fakeTwoModel{
public string objectB1 {get; set;}
public string objectB2 {get; set;}
public string objectB3 {get; set;}
}
public class fakeThreeModel{
public string objectC1 {get; set;}
public string objectC2 {get; set;}
public string objectC3 {get; set;}
}
Then from your views, you can access all classes from one models like:
#Html.LabelFor(m=>m.fakeModelOneView.objectA1 )
#Html.TextBoxFor(m=>m.fakeModelOneView.objectA1 )
#Html.LabelFor(m=>m.fakeModelTwoView.objectB1 )
#Html.TextBoxFor(m=>m.fakeModelTwoView.objectB1 )
#Html.LabelFor(m=>m.fakeModelThreeView.objectC1 )
#Html.TextBoxFor(m=>m.fakeModelThreeView.objectC1 )
By default, a partial view rendered by calling #Html.Partial("PartialViewName") takes the view model of the parent view.
The model for your main page should include the models that you'll pass on to the partial views:
Model:
public class IndexModel
{
public Ortund.Models.Receipt Receipt { get; set; }
public IEnumerable<Ortund.Models.Reward> ClaimedRewards { get; set; }
public IEnumerable<Ortund.Models.Reward> EligibleRewards { get; set; }
}
View:
When you call the partial view, specify the model you'll pass to it, such as
#model IndexModel
#Html.Partial("_RewardsView", Model.ClaimedRewards)
#Html.Partial("_ClaimsView", Model.Receipt)
#Html.Partial("_RedemptionView", Model.EligibleRewards)
Having multiple forms on the single page is another issue. See
Multiple Forms in same page ASP.net MVC
So, in short: use a viewmodel?
Yes, essentially. There's so many times that view models will simply be required to achieve what you need that you might as well just learn to use them.
However, in this one circumstance, you can hold out just a bit longer as you can also achieve what you're looking for using child actions. Essentially, that would look something like this:
Controller
[ChildActionOnly]
public ActionResult Rewards()
{
// fetch rewards
return PartialView("_Rewards", rewards)
}
View
#Html.Action("Rewards")
If you want to use ajax to update the Views, then you can try MultiPartials. With the added benefit that they will update any elements you define with Ids, this means you can update multiple divs with data and not have to worry about managing complicated view Models.
#Ajax.ActionLink("ActionLink", "ActionLinkClick", new AjaxOptions { OnSuccess = "MultipartialUpdate" })
public ActionResult ActionLinkClick()
{
MultipartialResult result = new MultipartialResult(this);
result.AddView("_Div1", "Div1", new Div1Model("ActionLink clicked"));
result.AddView("_Div2", "Div2", new Div2Model("ActionLink clicked"));
result.AddContent("ActionLink", "LastClickedSpan");
result.AddScript("alert ('ActionLink clicked');");
return result;
}
Then in view
#using(Ajax.BeginForm("FormSubmit", new AjaxOptions { OnSuccess = "MultipartialUpdate" }))
{
<input type="submit" value="Submit">
}
This code snippet is from the above mentioned link, and you can create as many partials as possible without having to create complicated code to manage all of them.
Is there anyway in a MVC strongly typed View to find out which ActionResult in the controller passed the Model? I do not want to add extra fields in the Model at this stage or add anything in my querystring? Is it even possible?
Sorry this may be a noob question. Any help is appreciated.
Never mind mumbling about validation of the principles of the MVC Architecture ;)
Place this code in your view:
string action = #ViewContext.Controller.ValueProvider.GetValue("action").RawValue.ToString();
In the view you can acess the Context, then you can retrieve the action/controller from the current request like this:
#{
string controller = RequestContext.RouteData.Values["controller"].ToString();
string action = RequestContext.RouteData.Values["action"].ToString();
}
Then you can use it at the view to make some conditional
#if(action.Equals("some name"))
{
//Do stuff here
}
The Action should tell the View. Instead of adding extra fields to your model you could wrap it in a ViewModel:
public class MyViewModel
{
public MyModel InnerModel {get; set; }
public string ActionName {get; set; }
}
Or use ViewBag:
ViewBag.ActionName = "MyActionName";
Maybe the title is not so explicitly. Let me explain you my situation
I've got a get and post method in my controller. In the GET method, gets the entities from the database context
[HttpGet]
public ActionResult RecheckAssignment(short id)
{
var assignment = db.Assignments.Find(id);
Session["QuestionList"] = QuestionRepositoryManager.GetAllPossibleQuestionsFromJson(assignment.Content); // it's a list!
return View(Session["QuestionList"]);
}
Assignment entity contains as 10 properties. When I show this entities in the model, it shows uses all the properties, but when the user does post should get only two properties from it (Id string, Changed bool) in the POST METHOD.
I do not what to put inside of the method parameters.
[HttpPost]
public ActionResult RecheckAssignment(...)
{
return View();
}
I put everything in a session variable because later I must have to get the entities again, I guess this is a good option using Session but I'm not sure.
So, what should I have to write inside of the method to get only the Id and Changed properties to updated the entities.
When ASP.NET MVC maps a <form> back to the Action during a POST it will fill in what it can. Consider a class like this:
public class Car
{
public string Make { get; set; }
public string Model { get; set; }
public int Year { get; set; }
}
and now consider this form:
#using (Html.BeginForm("ActionName", "ControllerName", FormMethod.Post))
{
Html.TextBoxFor(m => m.Make)
}
and now consider this Action:
public ActionResult ActionName(Car model)
{
// the values of Car will look like this
model.Make // this will be what was in the text box
model.Model // this will be null
model.Year // this will be 0
}
and take note that null and 0 are the default values for those types. So, if I wanted to POST the property Model I need to get it in the form. I can do that with #Html.TextBoxFor, but what if I don't want the user to see it? Well, I can do that too:
Html.HiddenFor(m => m.Model);
and so now when the form is POSTed it will populate the Model with the value it was downloaded with. So, just make sure that all the properties you need are in the form in some way.
I'm new to asp.net mvc. Basically i'm from php programmer. In my php file i can display what are all the values coming from html page or form using echo $_POST; or print_r($_POST); or var_dump($_POST). But in asp.net how can i achieve this to check what are all the values are coming from UI Page to controller.
You may take a look at the Request.Form property:
public ActionResult SomeAction()
{
var values = Request.Form;
...
}
You could put a breakpoint and analyze the values. Or simply use a javascript development toolbar in your browser (such as FireBug or Chrome Developer Toolbar) to see exactly what gets sent to the server.
But normally you are not supposed to directly access the raw values. In ASP.NET MVC there's a model binder which could instantiate some model based on the values sent to the server.
For example you could have the following model:
public class MyViewModel
{
public int Age { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
and then have your controller action take this model as parameter:
public ActionResult SomeAction(MyViewModel model)
{
... you could use the model properties here
}
and now you could invoke this controller action either wityh a GET request passing the parameters in the query string (/someaction?age=10&firstname=foo&lastname=bar) or using a POST and sending them in the body.
You can check the raw data via Request.Form.
But this is not he spirit of the ASP.NET MVC. It is preferd that you expect a model into your controller. You have all type safety mapping already done by special module called model binder.
So unless you work on some special case, you just add a model to the controller action:
public ActionResult SomeAction(SomeModel model)
{
//Handle SomeModel data further ...
}
You can create an action which will accept the parameters from the UI page like the following:
[HttpPost]
public ActionResult SomeAction(string param1, int param2)
{
//Now you can access the values here
}
or make an action which will accept the model
public ActionResult SomeAction(SomeModel model)
{
//Access the model here
}