1

I'm working with a SelectList, and populating it with the data from a table. I'm trying to bind it to the ID of another object.

EDIT Updated the Schema to Reflect something I neglected. I have updated it to show the exact names of each item. I think the problem comes in the fact that each Unit has a sheet, and each sheet has a product. (The sheet will hold more information for the product, but a Unit will have a great deal of other information, so I wanted to separate them in order to keep it clear what was what.)

I think something is happening and the "Sheet" isn't being initialized as an object, and when the binding occurs, it doesn't have an object to bind to, since it is one-level deep. Tell me if this makes sense, or if I am just completely off base.

**Unit**
UnitID (PK)

**ProductSheet**
UnitId (FK)(PK)
ItemId (FK)

**Items**
ItemId (PK)
ItemTitle

It just ...isn't working though. I have this code.

DatabaseDataContext db = new DatabaseDataContext();
Unit unit = new Unit();
ViewData["Items"] = new SelectList( db.Items, "Id", "ItemTitle", unit.ProductSheet.ItemId);

But in the postback, the selectList is always null and empty! This is the View code. I'm really getting lost here, I've followed a lot of examples and it still comes up with bunk.

<%= Html.DropDownList("Items") %>
Ciel
  • 17,312
  • 21
  • 104
  • 199
  • It will obviously house more items in the future, 10 is just the test data. It keeps posting back null on create. – Ciel Sep 21 '09 at 20:52
  • Stacey: check the edit made to the question in post http://stackoverflow.com/questions/1434734/asp-net-mvc-dropdownlist-selected-value-problem. The MVC engine has a specific order it uses to obtain values. Unfortunately, this can sometimes gets in the way. – David Andres Sep 21 '09 at 20:53
  • As strange as this sounds, please change ViewData["Items"] to ViewData["MyItems"] or something similar. I want to rule out name clashes. – David Andres Sep 21 '09 at 20:57
  • The UnitItemId is in the Model. And to David Andres, If I use Request.Form["Items"], I get the proper Id returned as a string. But I know for certain this is not how it is intended to be used, I should be able to explicitly bind right to the model. – Stacey 0 secs ago – Ciel Sep 21 '09 at 21:02
  • @Stacey, What happens when you change the name of the Items key to ViewData["MyItems"]? – David Andres Sep 21 '09 at 21:04
  • I have changed the field and it gives the same result, but I did realize something about my schema that may make a difference. I've updated it to reflect. – Ciel Sep 21 '09 at 21:07
  • Stacey, I've posted a possible answer. Please let me know if it helps you. – David Andres Sep 21 '09 at 21:11

3 Answers3

3

Your view code should read:

<% var selectItems = ViewData["Items"] as SelectList; %>
<%= Html.DropDownList("ProductSheet.ItemId", selectItems) %>
David Andres
  • 31,351
  • 7
  • 46
  • 36
  • Sorry, that doesn't even compile. – Ciel Sep 21 '09 at 21:12
  • DropDownList will only accept a string as it's first parameter. – Ciel Sep 21 '09 at 21:13
  • With your edit, it compiles and runs but the result is the same. It still comes out null on the model after posting. – Ciel Sep 21 '09 at 21:14
  • Stacey: just so I'm clear, what do you mean by "comes out null on the model after posting?" – David Andres Sep 21 '09 at 21:17
  • I run it, type in the values, pick the item from the dropdown. I hit "submit". Break into the debugger. The model.Sheet.ItemId is simply null. But, if I do Request.Form["Items"], I'll get the ID of the item that was selected in the dropdown. – Ciel Sep 21 '09 at 21:21
  • Can you please post the action method the is fired when the submit button is clicked? Also, I recommend naming your DropDownList Sheet.ItemId to match the model property. – David Andres Sep 21 '09 at 21:23
  • isn't the entity in your model named ProductSheet? – mhenrixon Sep 21 '09 at 22:18
  • <%= Html.DropDownList("ProductSheet.ItemId", selectItems) %> is what you should use with that approach. – mhenrixon Sep 21 '09 at 22:19
  • Yes, I will post more. Please give me a few moments to get all of that for you. – Ciel Sep 22 '09 at 13:33
  • I've included a sample of the whole project at www.developer-network.net/downloads/DropDownListErrors.zip. I'll post the ViewCode in a separate answer below. You can use the setup controller to install/initialize the database. – Ciel Sep 22 '09 at 13:52
  • Is there any way to do this and not have the property be the name of the HTML control on the output? – Ciel Sep 23 '09 at 01:10
  • There is, but I believe you're trying to have this property automatically populate a ProductSheet parameter when posted. For this to work, the names you choose must be enough for the MVC engine to figure out where all the form elements go on a newly instantiated ProductSheet. Otherwise, you can name it what you want and add a parameter to your action method to take the data in. – David Andres Sep 23 '09 at 11:28
  • I'm not entirely sure I understand. I can just add a parameter? How will MVC know to pass that(what) through to the ActionResult? – Ciel Sep 23 '09 at 13:31
  • Stacey, MVC will try to match form input element names to the parameter names passed to an action method. – David Andres Sep 23 '09 at 14:49
  • So I have to match the ids of the form elements to the model names? Isn't this really insecure, because it exposes information about my model to the view source? – Ciel Sep 23 '09 at 15:05
  • I don't think it's any more or less secure than knowing what form posts with a submit button click and where it goes. That's HTML/HTTP for you. – David Andres Sep 23 '09 at 18:01
0

An entire sample of the project is available at this url

These are the action methods.

public ActionResult Create()
{
        DatabaseDataContext database = new DatabaseDataContext();
        Unit u = new Unit();
        u.Sheet = new Sheet();
        ViewData["ProductListing"] = new SelectList(database.Products, "ProductId", "ProductName", u.Sheet.ProductId);
    return View();
} 

//
// POST: /Home/Create

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Unit u)
{
    try
        {
            DatabaseDataContext database = new DatabaseDataContext();
            database.Units.InsertOnSubmit(u);
            database.SubmitChanges();
        // TODO: Add insert logic here

        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

Here is the Create View.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MVC.Models.Contexts.Unit>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Create
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Create</h2>

    <%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %>

    <% using (Html.BeginForm()) {%>

        <fieldset>
            <legend>Fields</legend>
            <%= Html.DropDownList("ProductListing") %>
            <p>
                <input type="submit" value="Create" />
            </p>
        </fieldset>

    <% } %>

    <div>
        <%=Html.ActionLink("Back to List", "Index") %>
    </div>

</asp:Content>

<asp:Content ID="Content3" ContentPlaceHolderID="ScriptContent" runat="server">
</asp:Content>
Ciel
  • 17,312
  • 21
  • 104
  • 199
0

I've marked the answer that seems to have made some progress now, I think I'm starting to understand it better.

When I passed the 'path' of the object to assign as a string in the name field of DropDownList, it seems to work. But this doesn't really make a lot of sense to me. Can you explain what is going on any better?

Ciel
  • 17,312
  • 21
  • 104
  • 199
  • By path, do you mean ProductSheet.ItemId? I think it helps to understand what happens when you post a form item whose name is ProductSheet.ItemId. Let's say you have an action method that takes a productsheet parameter. MVC will automatically equate the ProductSheet.ItemId form field with the productSheet action method parameter, and which this form data will try to fill the parameter's ItemId property (if it exists). This will work even if ProductSheet is a property of the paraemter itself, as in myParam.ProductSheet.ItemId. It's confusing, I know. – David Andres Sep 22 '09 at 15:14
  • I think the biggest problem is that field name and object name are sharing the same parameter, and it's a simple string. It isn't very clear to the programmer that that parameter needs to match the property you want to associate with in your model, and that you can reference the object itself (i.e. "Sheet.ProductId" instead of just being limited to "Sheet" or "ProductId"). – Ciel Sep 22 '09 at 15:26
  • Is there any way to do this and control the id field of the html output? – Ciel Sep 22 '09 at 19:49