0

I have successfully gotten Visual Studio to generate a drop-down list based on a foreign key between two Models. Each of my "Products" has a "Supplier" value, and so the Products-Create-View now has a SuppliersID drop-down list in it. My classes are:

public class Product
{
    public int ProductID { get; set; }
    public string Name { get; set; }
    public float Price { get; set; }
    public int SupplierID { get; set; }
    public virtual Supplier Supplier { get; set; }
}

public class Supplier
{
    public int SupplierID { get; set; }

    public string Name { get; set; }
    public string Email { get; set; }
    public bool IsActive { get; set; }
    public virtual ICollection<Product> Product { get; set; }
}

In my create view for Products, there is the bit of code that creates the HTML select tag and populates it with the SupplierIDs from the database table:

<div class="form-group">
    <label asp-for="SupplierID" class="control-label"></label>
    <select asp-for="SupplierID" class ="form-control" asp-items="ViewBag.SupplierID"></select>
</div>

The drop down list contains "1", "2", "3", etc., showing only the SupplierID field from the Supplier table, but I want to show the Supplier.Name value instead. This way, when adding a new product, the user can select the Supplier by name, rather than the SupplierID. Obvious user-friendliness change.

To be absolutely clear, The value of the tag should remains as the SupplierID, only the content of the tag should be the Supplier Name:

<option value="1">Meat Store</option>
<option value="2">Vegetable Store</option>
<option value="3">Another Supplier</option>
etc.

(I'm sure this is very simple, but I just can't find the syntax I need.)


[Edit] What about a class field attribute that indicates that the Name field is to be the Visible text for the drop down selection? Does that exist?

  • Show how you generate the `SelectList` (`ViewBag.SupplierID`) in the controller. And note that the name of the `ViewBag` property should not be the same as the name of the property your binding to - refer [Can the ViewBag name be the same as the Model property name in a DropDownList?](https://stackoverflow.com/questions/37161202/can-the-viewbag-name-be-the-same-as-the-model-property-name-in-a-dropdownlist/37162557#37162557) –  Oct 10 '17 at 22:41
  • 1
    Instead of having `asp-items="ViewBag.SupplierID"`, you can put asp-items="ViewBag.Suppliers" where `ViewBag.Suppliers` contains list of `SelectListItem` which has `Text= SupplierName` and `Value=SupplierId` – Akash KC Oct 10 '17 at 22:43

3 Answers3

1

Take a look at https://learn.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms#the-select-tag-helper for tips on using the select tag helpers.

In that reference, they point out that you can bind to a List of SelectListItems to get the behavior you are looking for.

So in your model (or viewbag if you use your current pattern) assign something like this: (I'd aim for an IEnumerable from a LINQ query here.)

ViewBag.SupplierOptions = new List<SelectListItem>
        {
            new SelectListItem { Value = "1", Text = "Meat Store" },
            new SelectListItem { Value = "2", Text = "Vegetable Store" },
            new SelectListItem { Value = "3", Text = "Another Supplier"  },
        };

and then this for your select:

<select asp-for="SupplierID" class ="form-control" asp-items="ViewBag.SupplierOptions"></select>

(As mentioned in the linked reference, the ViewBag probably isn't the best spot for this, but that's another question.)

Jamie F
  • 23,189
  • 5
  • 61
  • 77
  • No, the 'Test' values MUST come from the database, not hard-coded. I have see the ViewBag solution all over the place, but not sure why people keep suggesting it when the whole point of coming from a database table is that it is dynamic, NOT hard-coded. – Jack Thomson Oct 10 '17 at 22:57
  • You misunderstand me. Yes, you need to set the options in your model, but you probably would be better off with a strongly typed model, not the ViewBag, which is sort of a catch-all "bag" for random stuff. (I understand the need for the DB, that's why I suggest the LINQ query.) – Jamie F Oct 10 '17 at 23:00
  • I'm having trouble finding a reference for syntax to perform a query to populate a list. Example of how to populate the ViewBag.SupplierOptions with the values from a database table? – Jack Thomson Oct 11 '17 at 17:24
  • There are many ways to query a database in .NET, such as Entity Framework, or ADO.NET. Depending on which of these you are currently using, you will want to query the database with a different method. If you are using EF, you might have something like `ViewBag.SupplierOptions = databaseContext.Suppliers.Select(s => new SelectListItem { Text = s.Name, Value = s.SupplierId.ToString() }).ToList();` See https://stackoverflow.com/questions/19140812/asp-net-binding-linq-query-results-to-html-dropdownlist-using-mvc – Jamie F Oct 11 '17 at 20:36
1

In your controller:

ViewBag.Suppliers = new SelectList(db.Supplier.ToList(), "Id", "Name");

In your view:

@Html.DropDownList("SupplierID", (SelectList)ViewBag.Suppliers, "Suppliers...", new { @class = "form-control" })
Ricky Sett
  • 59
  • 7
  • The code to put into the controller is not working quite right...It has trouble with "db.Supplier.ToList()" in the sense that "db" is not an object. I have a _context working for the connection to the database, but when I change it to that, it has a problem with "Supplier". The code for the View seems to work, but still showing the ID columns instead of the name. – Jack Thomson Oct 11 '17 at 17:19
  • Are you using Entity to get your values? If not how do you get them? – Ricky Sett Oct 12 '17 at 17:34
1

In the ProductsController class, in the Create() method, I found a line that created the SelectList and put it into the ViewData array:

ViewData["SupplierID"] = new SelectList(_context.Suppliers, "SupplierID", "SupplierID");

All I had to do to get the Name to show in the tags was to make one tiny change; the third parameter is the DataTextField:

ViewData["SupplierID"] = new SelectList(_context.Suppliers, "SupplierID", "Name");

I knew it had to be something simple. And here I was about to give up on it.