I have a site that was using ASP.Net MVC Beta 5, and I have just upgraded it to ASP.Net MVC 1.0. I am having trouble with the selected item in a drop down list.
The follow person has a similar question (Html.DropDownList in ASP.NET MVC RC (refresh) not pre-selecting item) but I there is no answer (other than it might be a bug)
My Controller method looks as follows:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult View(Guid id)
{
IntegrationLogic logic = new IntegrationLogic(new IntegrationLinq());
CompanyLogic companyLogic = new CompanyLogic(new CompanyLinq());
IntegrationContainer container = new IntegrationContainer();
container.Sources = logic.GetImportSource(id);
container.Companies = companyLogic.GetCompanies(); // Returns a IList<company>
container.SourceActions = logic.GetAllSourceActions(); // Returns an IList<SourceAction>
container.SinkActions = logic.GetAllSinkActions();
container.SuccessActions = logic.GetAllSuccessActions();
container.FailureActions = logic.GetAllFailureActions();
container.Actions = logic.GetAllActions();
container.Watchers = logic.GetAllWatcherActions();
container.ChainActions = logic.GetAllChainActions();
return View("View", container);
}
The view is a strongly typed against the Model as follows
public partial class View : ViewPage<IntegrationContainer> {}
The problem area in the view template is :
<label for="Companies">Company: </label><%=Html.DropDownList("Companies",
new SelectList(ViewData.Model.Companies, "id", "name", item.CompanyID))%>
I am creating a Dropdown List, the selected item never actually gets selected - and that is the problem. "item.CompanyID" is a Guid, "id" is a Guid and "name" is a string on the company object supplied in the IList that is held in the ViewData.Model.Companies instance.
Is this actually a bug ?- I find it hard to understand why this is still present in ASP.Net MVC... I would be totally happy if it is something I have done.
Regardless, what would be the suggested work around?
Thanks
It turns out that if the name of your control via Html.DropDownList is the same name as the collection object it causes an issue with ASP.Net MVC.
So if I change the following code:
<label for="Companies">Company: </label><%=Html.DropDownList("Companies",
new SelectList(ViewData.Model.Companies, "id", "name", item.CompanyID))%>
to:
<label for="Companies">Company: </label><%=Html.DropDownList("company",
new SelectList(ViewData.Model.Companies, "id", "name", item.CompanyID))%>
all now works. This is because the name of collection on the model was Model.Companies.... bonkers... also note, that changing the case of the name of the control from "Companies" to "companies" does not work either (which makes sense I suppose).
I could change the Model, but as most of it is built using Linq-to-SQL I think it is easier to change the names of the Html elements.
Related
I am new to MVC so probably confused . can somebody please explain me the dropdown in razor.my questions are-
What is the difference in dropdownlist and dropdownlistfor
how do i Pass ID column of my database table as value and NAME column as text.
How do i add "other" to the dropdownlist.
how do i access the selectedlistitem in code behind.
if possible please explain with an example.
DropDownList is generated by code like this:
#Html.DropDownList("PersonId", new SelectList(Model.People, "Id", "Text");
On the other hand, DropDownListFor is generated like this:
#Html.DropDownListFor(m => m.PersonId, new SelectList(Model.People, "Id", "Text")
Problem with DropDownList is that it has a magic string and if you decide to refactor the model later on, there's a high change you'll forget to change the magic string too.
You could do a LINQ query like this:
var datalist = New SelectList(from x in _peopleService
select new SelectListItem { Text = x.Name, Value = x.Id});
If you don't have a service or an ORM between it you need to apply it to your situation, but you can generate a list like that.
After nr 2, you can
datalist.Add(new SelectListItem() { Text = "Other", Value = "-1"});
Also you have to put that datalist in your viewmodel/model that is passed to the View, so you can generate a selectlist item with that. In this case you could just do:
#Html.DropDownListFor(x => x.PersonId, Model.PersonList);
if you stored the list as PersonList in Model.
In your Viewmodel (Well, model in mvc) you have a property where the selected item will be stored, look at the 1st question - In this instance the selected item's id will be stored in the PersonId property.
I have never asked a question on StackOverflow before, and never wanted to, but I am desperate, so here we go: I cannot get a saved value to show up as the default value/display in a dropdown.
I set up the list in my controller:
public ActionResult Index()
{
//User Dropdown List
var users = Roles.GetUsersInRole("Manager");
SelectList list = new SelectList(users);
ViewBag.Users = list;
return View();
}
Then in the view an admin can then select one of these users and save it to my database via EF:
#Html.DropDownList("Users", ViewBag.Users as SelectList, "--Select Manager--")
This all works great, however, when you edit this entry, I want the dropdown list to show the current saved manager, not the first name in the list. I was hoping on my edit action that I could pull the current manager out of the database and pass it back into the dropdown as the default selected item, but no go:
public ActionResult Edit(int id = 0)
{
var theOwner = (from v in _db.Location where v.LocationID == id select v.Owner).FirstOrDefault();
var users = Roles.GetUsersInRole("Manager");
SelectList list = new SelectList(users, theOwner);
ViewBag.Users = list;
From all the examples I have read over the last 2 weeks, everyone has had 3 different values to work within their dropdowns, making it possible to use all the overloads in the SelectList method. However, my problem is that I just have this string list with only one item in it, so I can't utilize the overloads as I want.
So does anyone have an idea on how I can get this to work? Thanks a lot in advance for your time on this!
I'm pretty sure that if you modify the second parameter on the line where you create your SelectList, it should work -- it does for me.
Here is what I think the trouble is: Currently you are specifying the second parameter as 'theOwner', which is an object reference from the earlier Linq statement. But the SelectList contains a bunch of strings (the UserNames of the users which match the specified rolename). As a result, the SelectList doesn't 'know' how to match what you specified as the SelectedItem to something in the list of strings it contains.
But if you refine that second parameter so it specifies the USERNAME of the Owner that you just looked up, it should work. However I do not know what the correct property name is from your Location table. If the field you are currently selecting (v.Owner) contains the UserName itself rather than some Key then the syntax would be:
SelectList list = new SelectList(users, theOwner.Owner);
If that column actually contains a key for the User like an int or a Guid then you will have query for the UserName using the key, but the nature of the fix is the same.
Hope that helps.
A quick workaround is not to use #Html.DropDownList but plain html code.
As an example for your case, use the following html code in your View instead of Html.DropDownList helper:
<!-- NOTE: the ID and name attributes of "select" tag should be the same as
the name of the corresponding property in your Model in order for ASP.NET MVC
to edit your Model correctly! -->
<select id="User" name="User">
#foreach (var user in (SelectList)ViewBag.Users)
{
if (user == ViewBag.TheOwner)
{
<option value="#user" text="#user" selected = "selected" />
}
else
{
<option value="#user" text="#user" />
}
}
</select>
Also , for this to work you need to add one more line to your Edit method:
ViewBag.TheOwner = theOwner;
Another solution is also possible using #Html.DropDownListFor() however you haven't shown your model so I can't tell you what exactly to use. When DropDownListFor is used, ASP.NET MVC will select an option automatically based on the value in your model.
Im wondering if anyone can explain the following disparity in functionality between two ASP.Net MVC 3 projects.
In both projects I have a view model which contains the following:
public List<int> Questions;
And in both projects I have the following ListBoxFor code:
#Html.ListBoxFor(x => x.Questions, new MultiSelectList(ViewBag.Questions as List<MyStandardLib.Mvc.Attribute>, "Id", "Name", #Model.Questions), new { #class = "ui-field-multiselect", style = "width: 250px;" })
The difference in functionality is that when run, one project binds the existing selected Questions correctly, the other does not and shows all Questions as unselected. Stepping through the code, the List is populated in the view and is correctly passed to the MultiSelectList constructor, but it isn't setting the values as selected.
This is really frustrating.
Change your ViewBag.Questions variable name to ViewBag.AvailableQuestions. Sometimes the renderer gets confused about what you are referring to.
I have a controller action UpdateCustomer(CustomerDto customer) that returns a PartialViewResult with a model that is also a CustomerDto:
[HttpPost]
public PartialViewResult UpdateCustomer(CustomerDto customer)
{
CustomerDto updatedCustomer = _customerService.UpdateCustomer(customer);
updatedCustomer.Name = "NotThePostedName";
return PartialView("CustomerData", updatedCustomer);
}
In my view, I have the following line:
#Html.TextBoxFor(model => model.Name)
So far, so good. In my view I do an asynchronous post to this action method, the model binder does its work and I can update a customer in the database. Then I want to render the updated customer to the client. For example, I'd like to change the customer name in my controller. However, what gets rendered is always the properties from the posted customer, not the properties from updatedCustomer.
I decided to include the MVC3 source code in my project to see what really happens. It appears to be a feature (bug?) of MVC3 that it always takes the value from ViewData.ModelState instead of the value from ViewData.Model.
This happens at lines 366-367 of System.Web.Mvc.Html.InputExtensions:
string attemptedValue =
(string) htmlHelper.GetModelStateValue(fullName, typeof(string));
tagBuilder.MergeAttribute("value",
attemptedValue ?? ((useViewData)
? htmlHelper.EvalString(fullName)
: valueParameter), isExplicitValue);
As you can see, attemptedValue comes from ModelState. It contains the old value for CustomerDto.Name (the value that was posted to the controller action).
If this is a feature, why does it work this way? And is there a way to work around it? I would expect that if I update my model, the update gets rendered, not the old value I posted.
Well yes it's a feature (ModelState is always checked before actual Model), you can clear the ModelState, or update just the value you need:
ModelState["Name"].Value = updatedCustomer.Name;
I build a drop down list in my aspx page as following
<%= Html.DropDownList("SelectedRole", new SelectList((IEnumerable)Model.roles, "RoleId", "RoleName", Model.SelectedRole), "")%>
it works fine for first Get and the first default value is selected; then I select item from the drop down list and submit the form.
the controller bind the values correctly,
public ActionResult About([Bind] Roles r)
{
//r.SelectedRole = the selected value in the page.
//Roles r = new Roles();
r.roles = new List<Role>();
r.roles.Add(new Role(1, "one"));
r.roles.Add(new Role(2, "two"));
r.roles.Add(new Role(3, "three"));
r.roles.Add(new Role(4, "four"));
r.SelectedRole = null;
return View(r)
}
Then I nullify the selected item and return my view, but still the previous selected Item is selected (although I did nullify it)
Any Idea if I am doing something wrong or it is a bug in MVC?
I am using ASP.NET MVC 1
Thanks
This is the normal behavior of all html helpers: they will look at the POSTed values to perform the binding. This means that you cannot change the value in your controller action and expect it to reflect on the view if you use the standard helpers. If there's a value SelectedRole in the POST it will always be this value used and the last parameter of the drop down completely ignored.
You could write your own helper to achieve this or redirect after the POST.