I'm fairly new to asp.net mvc and I have a question. Example model:
public class FooModel
{
public string StrA {get; set;}
public string StrB {get; set;}
}
How can I do something like this: pass model to view (model with StrA filled, StrB empty), update StrB of my model (StrA filled, StrB filled) and then submit it to my action with both StrA and StrB filled (by default I will pass new instance of model with only StrB filled and my previous value of StrA will vanish).
I know I can use HiddenFor, but is there any other way to do that?
I know I can use HiddenFor, but is there any other way to do that?
In your POST action you could fetch the value of the StrA property from the same place you fetched it in your GET action. This way you don't need to use a hidden field to persist it.
For example:
public ActionResult Index()
{
var model = new FooModel
{
StrA = PopulateStrAFromSomewhere()
};
return View(model);
}
[HttpPost]
public ActionResult Index(string strB)
{
var model = new FooModel
{
StrA = PopulateStrAFromSomewhere(),
StrB = strB
}
... do something with the model
}
Now in the view you could only have an input field for StrB inside the form which will allow the user to modify its value:
#model FooModel
#using (Html.BeginForm())
{
#Html.LabelFor(x => x.StrB)
#Html.EditorFor(x => x.StrB)
<button type="submit">OK</button>
}
You can build your own POST using e.g. jQuery AJAX ( http://api.jquery.com/jQuery.post/ ) or construct a form manually and submit it ( http://api.jquery.com/submit/ ). This means you won't have to create a visible form on the page (if that is what you want to avoid).
However you will need to pass the data to the DOM and persist it in some way (e.g. with a hidden field). Since HTML is stateless you can't magically save the StrA somewhere if you actually want to get it back to the server somehow - unless it isn't meant to change between requests, which means you wont need to get it to the client and back any way (see Darin's response for an example of how to handle it in this case).
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}
I have a ViewModel like this:
public class MyViewModel
{
public string SelectedItem { get; set; }
public List<MyClass> Items { get; set; }
}
I fill these items on screen with a #Html.DropDownListFor(m => m.SelectedItem, new SelectList(...)).
Ok, but when I call any action which receives this ViewModel, I got this collection empty.
Is there a way to get back the DropDownList values when I call any action?
That's a normal behavior and it's how HTML works. Only the selected value of a <select> element is sent to the server, not the entire collection. In your POST action if you want to retrieve the collection all you have to do is exactly the same you did in your GET action to retrieve it in the first place. That's usually a database call. And if you are afraid that you might be hitting your database quite often, just cache the collection.
In a tag form you can only send the value selected in the tag select, in this case the value of SelectedItem.
If you need also send the list of values of Items, you have to create something like this:
#{
var ind = 0;
foreach(var item in Model.Items)
{
<input type="hidden" name="Items[#ind].Id" value="#item.Id"/>
ind++;
}
}
But id you can send the data by Ajax, in this case is mode simple, because you can create the data to send. See this plugin toDictionary
One way is to have the List<SelectListItem> as part of the view model and populate it via a method called from the controller and pass it to the view, e.g.
View model:
public List<SelectListItem> SelectList { get; set; }
And in the view:
#Html.DropDownListFor(model => model.SelectedItem, Model.SelectList)
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.
hejdig.
In Aspnetmvc2 I have a model object that I send to a View. A control in the view isn't updated with the value. Why? What obvious trap have I fallen in?
The View:
<%:Html.TextBox(
"MyNumber",
null == Model ? "1111" : Model.MyNumber ) %>
<%:Model.MyNumber%>
is first fetched trough a Get. The "1111" value in the textbox is manually updated to "2222". We post the form to the controller which appends "2222" to the Model object and sends it to the view again.
The Controller:
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index( MyModel myModel)
{
myModel.MyNumber += " 2222";
return View(myModel);
}
Alltogether we get an output like:
<input id="MyNumber" type="text" value="1111">
1111 2222
As you can see the control doesn't use the Model's attribute but instead falls back to thew viewstate that doesn't exist in Aspnetmvc.
(The same happens with Razor.)
That's normal and it is how HTML helpers work : they look first in the model state and then in the model when binding a value. So if you intend to modify some property in the POST action you need to remove it from the model state first or you will always get the old value:
[HttpPost]
public ActionResult Index(MyModel myModel)
{
ModelState.Remove("MyNumber");
myModel.MyNumber += " 2222";
return View(myModel);
}
i'm having a textbox inside a form.
[View]
<%=html.textbox("name") %>
[Controller]
Index(string name)
{
name = "something";
return View();
}
On Form Submit
In this case without sending any ViewData the textbox value is maintained.But the value "something" is not setting up.
But whn i change the Action to
[Controller]
Index()
{
string name="something";
return view();
}
the value is not maintained.
Really wat happening on that parameter.
If you want to set data for html.textbox("name") in the Controller use ViewData["name"] = "something"
Your question is not very clear and your code example is not actually adding anything to ViewData or the view Model - here's a shot at what i think your trying to do...
Assuming you want to re-populate the form and your View is Strongly Typed, You would do something like this:
public ActionResult Index(String name)
{
MyModel model = new MyModel;
model.Name = name;
ViewData.Model = model;
return View();
}
A textbox in your view with the same name would then have the value auto populated from the Model
<%= html.textbox("Name") %>
Posting the form would then post the model object to your controller like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(MyModel model)
{
// do something with the model
ViewData.Model = model;
return View();
}
and then re-populate the form with the model data.
string name in your Index action in the controller, is mapped to the FormValue, if you change this, MVC understands that it needs to add the value from the FormValueCollection to the textbox, and you have changed that in your Index action. If you declare a variable by yourself this doesn't work because there is no binding to the formvalues.