views:

1067

answers:

2

Sorry if this is a repeated question, I scanned the related questions and didn't see anything obvious.

I'm using an EditModel with an Entity object, along with two SelectLists in it. The problem is, once I reach my POST action, the SelectedValues for both drop downs are still the same default values I set in the constructor for the model, no matter what I actually select on the browser.

My constructor sets some default values for the SelectedValues, but they are just 0 and "" (which aren't valid values in the dropdowns). I have a feeling the problem revolves around that somehow, but I'll give more details.

Here is a stripped down version of the model:

public class UserAccountModel 
{

    public UserAccount UserAccountData { get; set; } // Entity from EF
    public SelectList Organizations { get; set; }
    public SelectList Roles { get; set; }

    public UserAccountModel() : this(null)
    {
    }


    public UserAccountModel(UserAccount obj)
    {
        UserAccountData = (obj == null) ? new UserAccount() : obj;

        // default selected value
        int orgChildId = (UserAccountData.Organization == null) ? 0 : UserAccountData.Organization.ID;
        string roleChildId = (UserAccountData.Role == null) ? "" : UserAccountData.Role.Name;

        // go get the drop down options and set up the property binding
        using (UserAccountRepository rep = new UserAccountRepository())
        {
            Organizations = new SelectList(rep.GetOrganizationOptions(), "ID", "ID", orgChildId);
            Roles = new SelectList(rep.GetRoleOptions(), "ID", "Name", roleChildId);
        }
    }

    public void UpdateModel()
    {
        UserAccountData.Organization = Organizations.SelectedValue as Organization;
        UserAccountData.Role = Roles.SelectedValue as Role;
    }
}

This is the Dropdowns portion of the view:

                <div class="field">
                <label for="ID">Organization:</label>
                <%= Html.DropDownList("ID", Model.Organizations) %>
   </div>

            <div class="field">
                <label for="Name">Role:</label>
                <%= Html.DropDownList("Name", Model.Roles) %>
   </div>

I might have done something stupid and obvious here. The examples are much more straight forward when using the ViewData dictionary, but I couldn't find too many examples trying to use straight model binding for SelectLists.

Any help is greatly appreciated!

Chris

+1  A: 

You simply forgot the navigational path to the ID property :)

<%= Html.DropDownList("Organization.ID", Model.Organizations) %>
mhenrixon
I thought it might be this simple too, but I have confirmed the path and I think it is right. "Organizations" (plural) is actually a SelectList of "Organization" objects, so ID doesn't exist as a member of Organizations. I think I would need to cast the Organizations.SelectedValue to be type Organization, but I'm not sure how that would work (if at all) in a View. I'm open to suggestions though, as it just doesn't seem right to me that SelectedValue would not be set properly somehow!
Chris
+2  A: 

Select elements only post back the actual value of the selected it. In this case, the parameters will be received back at the server/controller as ID (organization) and Name (role). The model you use for the update action should either contain these as properties or your controller action should accept them directly as parameters. The lists on the model won't be repopulated -- and the names don't match in any event.

Modify your model by adding:

public int ID { get; set; }
public string Name { get; set; }

with controller action as:

public ActionResult Update( UserAccountModel userAccount )
{
    ...
}

Note that if there is a validation error, you'll need to repopulate the SelectList properties (reconstituting the menus).

tvanfosson
So, the SelectList properties on the model don't get updated? I was expecting to see the SelectedValue on the SelectList updated with the actual selected value from the view, and then I would pull that value out of the SelectList and update my UserAccountData. If that isn't the case, then I will take your advice and add the explicit Properties to be updated.
Chris
No. Since only the selected values are returned in the form post, it doesn't even have the data to use to repopulate the select lists. I always put in properties for both the enumeration (I use IEnumerable<SelectListItem>) and the selected value in my models.
tvanfosson
My only problem with this is that I am using Entity Framework behind a repository. I am actually querying for the complete objects to be listed in the SelectLists because they are very small. As a result, I have already gotten the entire Object from the DB. Do you just then do a lookup in your select list for the SelectedValue ID to get the complete data?
Chris
If you have the list cached, then yes, otherwise you'll need to requery. If you want to reconstitute the entire object, then you'll need to put all of the data on the form for each object in the select list and post it back as well. The only thing the model binder has to work with is the posted data. If you use caching and, perhaps, a custom model binder, then you could reconstitute the entire list from there. I'd say that's an optimization and I would probably just requery until I knew that would be a performance problem.
tvanfosson
Custom binding might be a good alternative (this was just mentioned to me by a co-worker too).I think I'll play with that a bit, otherwise I'll go with your more simple option above. Thanks again!
Chris