ASP.NET MVC : DropDownList to model field - c#

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

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.

MVC Customizing display template: Model.Value vs #ViewData.Model

I've seen two "Display templates customezing" examples.
In the 1. example programmer use Model.Value and in the 2. example he use #ViewData.Model.- See below
Exampel 1 (DateTime view:)
#model DateTime?
#Html.TextBox("", Model.HasValue ? Model.Value.ToString("dd/MM/yyyy") : "", new { #class = "ka_" })
Example 2:
<a href="#ViewData.Model" target="_blank">#ViewData.Model<a/>
What is the difference between them ?
What to select ?
In most cases you use both in your views. The model specifies the data for you're main view. It's the data that is created by the controller action. The ViewData dictionary is normally populated by other components.
Let's take for example an Product (view)model. A product would have a price, a description, a sku and in most cases a stock indication.
You're Product (view)model does not contain data any user information, website navigational data. That data is placed in the ViewData dictionary by other components and can be used by (parent) views to render the full page.
A bit offtopic, but at our company we have a very strict rules about what a view is allowed to do. In short is it not allowed to change/modify any data (not even the page title!) or to retrieve any data. The only code allowed in our views are conditional constructs and calls to helper methods. It helps if new developers on the team start with view engines that have no an 'eval' constructs like SuperSimpleViewEngine (from NancyFx) or XsltViewEngine. Razor and WebForms make it to easy to 'cheat'..

Object with items : View-Controller communication

So, I have no clue how to search for an answer to this problem, mainly because there are several aspects to it which I don't know how to solve. So - here it is.
I have an object, let's call it ObjectWithItems which has a List<Item> of Item objects. Both have separate Views and Controllers (which seems logical to me, but I can't be sure).
What I'm trying to achieve is this – go to Create action of ObjectWithItemsController and fill the necessary information specific to it. Then, I click an ActionLink "Add item", which takes me to the Create action of the ItemController. The View is rendered and I enter information for that specific Item.
What I don't know how to do is the following: when I submit the current Item, it should be passed to the former Create view of the ObjectWithItems and added to the List<Item>. Furthermore, it should contain the information inputted before calling the Item Create method and the rendering of the corresponding View.
I know this is a bit blurry description, but that is because I have just started learning ASP MVC and still don't know what's what. Any tested approaches for this?
Using Session["key"] object allow you to store any kind of object, Ex :
List<Table> Rows = db.Table.Where(t => t.id < 100).ToList(); // 100 first rows
Session["TableRows"] = Rows;
And later when you want to retreive them :
List<Table> Rows = (List<Table>)Session["TableRows"] // don't forget to cast it
Your objects will exist in Session as long as you don't reach the ASP timeout
Communication between View-controller is done through HTTP Post of the form.
< form class="form-horizontal" method="post" >
or #using (Html.BeginForm())
More info here with example

How can I hold a collection of strings to post back?

From my controller I send a ViewModel with a collection of strings to be used in a <select> tag like so...
Controller:
var model = new InviteViewModel
{
SelectItems = new SelectViewModel
{
Companies = _companyRepository.GetCompanyNames()
}
};
Razor View:
<select class="form-control company_select" asp-for="Company" asp-items="#(new SelectList(Model.SelectItems.Companies))"></select>
This works perfectly and will display all the items in the drop down box. However when I go to submit the form the Companies object will be null and when the View is sent back I get a null reference exception. Normally I would create a hidden <input> tag to hold the value, but how can I do this with a collection?
There are so many ways to do this.
It seems like you may have a fundamental misunderstanding of the disconnect between Razor and html. Razor executes server side, and its result is simply a string that gets written to the response stream. Once written, razor's scope is gone and cannot hold data.
One option would be to store the collection in the application cache or session cache with a guid as the dictionary key, and then use a hidden input for the cache key. When the view is being recreated you would then have access to the server and could gather the collection.
This makes the assumption that the collection hasn't changed during the time the view was active, which given some user habits could have been a long time. There should also be some sort of metrics used when caching to invalidate old data, if this is the route you take.
Another option is to simply regenerate the collection from wherever (database?) it came from.
Lastly, you mention that the view is being returned with the empty collection, are you returning a view from a post method? That is bad practice. Look up the "post-redirect-get pattern" for why and how to avoid it.

UpdateModel is not updating "deep" property

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.

Categories

Resources