UpdateModel is not updating "deep" property - c#

I have an ASP.NET MVC application. At a certain point I get a FormCollection in a Controller method that I want to use to update a model. In the collection not all of the values are properties of that model and the property to be updated is an item from a list, and that list is also an item from another list. Something like this (I hope this is clear):
propertyToUpdate --> model.Items[0].Subitems[0].SomePropertyClass.Value;
I tried this in my Controller:
UpdateModel(model);
The problem is that this is not working and I assume it has something to do with the fact that the reflection is not working. I went searching and stumbled upon this article. So I understand that using the prefix-parameter solves the problem. But not in my case, as the properties lie "deeper" in the model as items from a list.
Does anyone know how I can solve this?
Update:
Here's the EditorTemplate for the property:
#model Q95.Domain.Property
<li>
#Html.DisplayFor(p => p.Description) :
#Html.DisplayFor(p => p.Quantity.Value)
#Html.DisplayFor(p => p.Quantity.Unit.Description)
<br />
#Html.TextBoxFor(p => p.Quantity.Value)
</li>
This template is called like this:
<ul>
#Html.EditorFor(model => model.SegmentRequirement.MaterialRequirements[j].Properties)
</ul>
Is this enough code or is there something still missing?
Update2:
Ok, in all the sub-properties I defined parameterless constructors and now I call:
UpdateModel(segmentRequirement, "SegmentRequirement", form.ToValueProvider());
This updates the model, but everything from MaterialRequirements is re-instantiated... :S

UpdateModel works fine on "Deep properties".
The problem is probably the data in the collection you get isn't equal to the properties names.
Check 3 places to see the values you get from the page
The form values.
The route data
The query string
In exact that order.
The keys should match you model properties names.
Update:
How to match the keys to properties names?
The input id will be the key you will get, change the the ids to match your properties names, or even better, use the HtmlTextBoxFor helper: see this article:

Maybe you should create flattened ViewModel and then use that to populate the view, and later synchronize it with the real model.

Can you show us your model and your view, if you are not using htmlhelper, you then have to understand the naming convention very well in order to make the model binding work with your model. so the first thing in first is to show us your model and view.

Related

Retain DropDownList Value asp.net MVC [duplicate]

I am working on an ASP.NET MVC-4 web application. I'm defining the following inside my action method to build a SelectList:
ViewBag.CustomerID = new SelectList(db.CustomerSyncs, "CustomerID", "Name");
Then I am rendering my DropDownListFor as follow inside my View:
#Html.DropDownListFor(model => model.CustomerID, (SelectList)ViewBag.CustomerID, "please select")
As shown I am naming the ViewBag property to be equal to the Model property name which is CustomerID. From my own testing, defining the same name didn't cause any problem or conflict but should I avoid this ?
You should not use the same name for the model property and the ViewBag property (and ideally you should not be using ViewBag at all, but rather a view model with a IEnumerable<SelectListItem> property).
When using #Html.DropDownListFor(m => m.CustomerId, ....) the first "Please Select" option will always be selected even if the value of the model property has been set and matches one of the options. The reason is that the method first generates a new IEnumerable<SelectListItem> based on the one you have supplied in order to set the value of the Selected property. In order to set the Selected property, it reads the value of CustomerID from ViewData, and the first one it finds is "IEnumerable<SelectListItem>" (not the value of the model property) and cannot match that string with any of your options, so the first option is selected (because something has to be).
When using #Html.DropDownList("CustomerId", ....), no data-val-* attributes will be generated and you will not get any client side validation
Refer this DotNetFiddle showing a comparison of possible use cases. Only by using different names for the model property and the ViewBag property will it all work correctly.
There is not harm to use it. You will not get any error. but best practice is to bind model property.

ASP.NET MVC : DropDownList to model field

My model is a rpg character. He has a field "Game", that is a strongly types object containing "Careers" fields, themselves strongly types object.
Model must choose a career amidst multiple choices.
I currently display it as is :
#Html.DropDownListFor(model => model.career,
new SelectList(Model.game.professions, "name", "name"),
)
(where professions is of type List[career]).
However, this does not bind the selected value of the dropdownlist to the career field of my character.
Any hint? I've been searching for a while, but I only find way to populate a dropdownlist from a model, and nothing on how to ensure the selected value is passed back to the model.
Thank you
Edit = I accepted RedGoodBreaker's answer even though it wasn't what I expected because it helped me find the solution.
Point is : you can't select an object via DDL in mvc, you can only select a basic type that references to that object (in my case, I chose the string field "name" of my career).
#Html.DropDownListFor generates html like
<select id="CarType" name="CarType">
<option value="a">Volvo</option>
<option value="b">Saab</option>
<option value="c">Mercedes</option>
<option value="d">Audi</option>
</select>
so as you can see they are simple strings(in your case both value and text are the same). when you select one posting form will produce something like that:
...
CarType="a"
...
You can do several tricks but question is it worth doing it and do you really need it.
Normally your model should have field CarrerName and dropdownlist should be bound to it. In Controller Action which accepts form submission you should rehydrate Carrer from database or other store using CarrerName (this is why we asked about id).
I understand that Skills are some kind of dictionary that does not change much. Options for storing are(there maybe some others that i am not aware):
save your dictionary to Session before presenting form or better after logon if this dictionary does not change. You can access it after form submission and find apropriate key (best int or guid)
System.Web.Caching.Cache.
TempData.
Database.
this options have its cons and pros about which you must read because i don't know your application specification.
If you need this data before submission in view or javascript you have to do it yourself ( there is no simple one-liner). I can help but i dont know what do you want to achieve.
Your career object should have Id field and you need to pass it to DropDownListFor
Please refer the below link
MVC DropDownList
and then in the Razor view
#Html.DropDownListFor(m => model.career, new SelectList(Model.game.professions, "Value", "Text"), "Career")
Of course the model needs to be passed into the view with the values in the List already populated

Displaying results in View linq to sql mvc 4

I have been reading and reading , and I can't seem to get this to work at all. I am very very new to asp.net MVC - after all the tutorials I read I finally got this much accomplished.
public class EventsController : Controller
{
private EventsDBDataContext db = new EventsDBDataContext();
public ActionResult Index()
{
var a = (from x in db.tblEvents
where x.StartDate >= DateTime.Now
select x).Take(20).ToList();
return View(a);
}
}
This is successfully finding 20 rows (like it is supposed to). Now how do I display these in the view ?? Does it have to be a strongly typed view?? It doesn't seem like it should have to be... I have tried both , I tried typing a whole view, but for now it would be nice to just get one property of tblEvents to show up in the view. This is not working, I have tried many many variations.
#{foreach( var item in Model){
#Html.DisplayFor( item.ID)
}
}
How do I get the results from the controller displayed in the view? Just the ID is good for now - I can go from there.
The problem is that your View doesn't know what type your Model is. Use the #model syntax to define the type of your model.
#model List<YourEventClass>
#foreach( var item in Model )
{
#item.ID<br />
}
See i.e. here for more information
from the root of the web project you should have a directory called Views. Within the views folder create a new folder named Events. In the Events folder create a razor view named Index. put your markup and template code in this file.
You are correct, views do not need to be strongly typed. I find it's a good idea to do so because it provides another compile time check, but it's not required.
when you run the application you will navigate from the root (typically home/index) to Events/Index. there you should see the list of 20 items rendered in the view.
I guess you can not do something like this:
#{foreach( var item in Model){
#Html.DisplayFor(modelItem => item.ID)
}
unless the view knows what Type Model is returned as (still seems weird that .Net can't figure that out on its own. So I fixed the problem and got the ID displayed properly by adding this to the View.
#model IEnumerable<GetEvents.Models.tblEvent>
This works fine for this example - I am returning one table , so the Model type is just the class for the table. But this doesn't seem right - what if I wanted to query and join tables then what would the Model Type be?? Adding this fixed my problem , but if someone has a better answer for this then I will accept that.

MVC Strongly typed IQueryable<IGrouping<TKey, TElement>> model

I'm trying to create a strongly typed model for one of my Views in MVC. The model is the result of a LINQ GroupBy query so it is the type shown below (grouping employees by first letter of surname).
#model IQueryable<IGrouping<string, Employee>>
I'm unsure why but it doesn't let me have a model of this type. The error message I get is:
An opening "<" is missing the corresponding closing ">". Which is incorrect.
I know I can create a view specific model and populate that instead but I'd like to know why this model doesn't seem to work?
By default, a very limited set of namespaces are available for direct use in razor views. Try to expand it to fully qualified names and see if the problem persists:
#model System.Linq.IQueryable<System.Linq.IGrouping<string, Name.Space.Employee>>
I don't know why you'd be getting this error, since you appear to be using correct Razor code. It's possible that there's actually a bug elsewhere in the page that is being made manifest through this incorrect error message.
A workaround, which may help you determine the real source of the bug, would be to create your own strongly-typed model class, which could have this data as its property:
public class EmployeeListViewModel
{
public IQueryable<IGrouping<string, Employee>> EmployeesByCompanyTitle {get;set;}
}
(There are those who would argue that this is a better approach anyway, since you can now add information to your view model more easily.)

MVC View POST calls new constructor instead of passing back model

I've got a view which is adding a bunch of data into a bound EditModel. However, when it is POSTed, for some reason a parameterless constructor is called before calling the POST Action, instead of just passing back the model that was bound to the view.
I thought all I had to do was to make sure I reference the model in the "Inherits" tag at the top of the view, but for some reason all of the filled in data just gets thrown away on POST and a new instance of the model is instantiated. The View certainly seems to be able to see the model, as I can use Visual Studio Intellisense to access the model fields.
I'm sure it is something simple I am missing, so any pointers as to where to look would help. I can paste in some code if it helps.
Thanks!
As Omu says it will always call the parameterless constructor with a default modelbinder. Basically the modelbinder populate public memberes from the form collection based on the element names (plus maybe a prefix if defined). You need to make sure your element names (not Ids) match the public members you want populating on the model.
This is not how MVC works. When form is posted, MVC constructs new EditModel object and populates it with values provided in form. It doesn't preserve EditModel with was used to populate view in GET action. You have to make sure that every value that you want to use in POST method is set in html inputs in GET.
The constructor it is called, because that's what it should happen, now to see why is your model not filled with data it would be very helpful if would post the code of the view and post action.

Categories

Resources