Question

I have a controller responding to a URL like:

http://localhost:64121/BrowseNode/Create/1016?nodeTypeId=Category

Bug: The NodeTypeId dropdown list does not select the desired element (id of 3).

Action method (fails to select item 3):

    public ActionResult Create([Bind(Prefix = "id")]int? parentBrowseNodeId, Enums.eNodeType? nodeTypeId)
    {
        int typeId = (int)nodeTypeId.GetValueOrDefault(Enums.eNodeType.Category);
        // 3 is hard-wired to test this bug - still does not work
        ViewBag.NodeTypeId = new SelectList(db.NodeType, "NodeTypeId", "LabelEN", 3);
        ViewBag.OwnerUserId = new SelectList(db.User, "UserId", "EmailAddress", 3);
        return View(new CreateItemVM()
        {
            OwnerUserId = 3,
            NodeTypeId = (int)nodeTypeId
        });
    }

If I debug the real code the nodeTypeId parameter has a value of "Category" which then becomes 3 but I am using hard-wired values and it still fails.

Then if I use an int parameter, instead of enum, with this URL:

http://localhost:64121/BrowseNode/Create/1016?nodeTypeId=3

Action method with int parameter (works):

    // GET: /BrowseNode/Create
    public ActionResult Create([Bind(Prefix = "id")]int? parentBrowseNodeId, int  nodeTypeId)
    {
        ViewBag.NodeTypeId = new SelectList(db.NodeType, "NodeTypeId", "LabelEN", 3);
        ViewBag.OwnerUserId = new SelectList(db.User, "UserId", "EmailAddress", 3);
        return View(new CreateItemVM()
        {
            OwnerUserId = 3,
            NodeTypeId = 3
        });
    }

The view Create.cshtml has two drop downs like:

   <div class="form-group">
        @Html.LabelFor(model => model.NodeTypeId, "NodeTypeId", new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownList("NodeTypeId")
            @Html.ValidationMessageFor(model => model.NodeTypeId)
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.OwnerUserId, "OwnerUserId", new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownList("OwnerUserId")
            @Html.ValidationMessageFor(model => model.OwnerUserId)
        </div>
    </div>

The question:

Why does the code work with an int parameter, but fail with the enum even when the actual selection values for the lists are hard-wired to 3?

Update:

This problem is purely down to using the name nodeTypeId as the parameter name of the enum. If I rename it to nodetype and change the url to http://localhost:64121/BrowseNode/Create/1016?nodeType=Category it works!

It looks like the parameter name is somehow being passed into the view and overriding the default. I was not aware of parameters being automatically passed to MVC views from controllers. Can anyone explain why?

Was it helpful?

Solution

Okay, so it is not widely publicised (or I just missed it over my many years of MVC programming), but querystring parameters are automatically used by at least certain controls in a view, in preference to ViewBag values of the same name.

So basically what was happening was my querystring nodeTypeId string parameter was taking precedence over both my ViewBag SelectList's current value property of the same name and my ViewModel property of the same name.

A DropDownList can apparently take it's current value from the ViewModel, the selected property of SelectList (in a matching ViewBag property), or from a querystring parameter.

The key being that the querystring has precedence and can be used to override default value (might come in very useful).

Ya learn something new every day :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top