MVC SelectList combining multiple columns in text field

asp.netasp.net Mvcasp.net Mvc-3Razor

asp.net Problem Overview


How would I generate a select list, where the text field, is made up of two or more text columns, eg: Where I have a Description and Rate field in my database, I want to combine these to show:

Large--£200
Medium--£150
Small--£100

Controller code is:

 var stands = db.Stands.Where(s => s.ExhibitorID == null).ToList();
 ViewBag.StandID = new SelectList(stands,"StandID", "Description" + "-- £" + "Rate");

...and my view is (currently):

    <div class="editor-field"> 
        @Html.DropDownList("StandID", "--Select--") 
    </div> 

...but the "Description" + "-- £" + "Rate"); won't run:

> DataBinding: > 'System.Data.Entity.DynamicProxies.Stand_63F8C9F623B3C0E57D3008A57081AFCD9C39E1A6B79B0380B60840F1EFAE9DB4' > does not contain a property with the name 'Description--£Rate'.

Thanks for any help,

Mark

asp.net Solutions


Solution 1 - asp.net

You could create a new anonymous class using a simple LINQ projection, and then use the SelectList(IEnumerable, string, string) constructor overload to specify the value and text fields to be used for the <option> elements i.e.:

var stands = 
  db.Stands
    .Where(s => s.ExhibitorID == null)
    .Select(s => new 
     { 
       StandID = s.StandID,
       Description = string.Format("{0}-- £{1}", s.Description, s.Rate) 
     })
    .ToList();

ViewBag.StandID = new SelectList(stands, "StandID", "Description")

Edit

In C#6 and later, string interpolation makes for better reading than string.Format

   ...
   Description = $"{s.Description}-- £{s.Rate}"

If you project to a strong ViewModel class name (instead of to an anonymous class), you will undoubtedly want to replace the magic strings with the safety of the nameof operator:

ViewBag.StandID = new SelectList(stands, nameof(Stand.StandID), nameof(Stand.Description));

Solution 2 - asp.net

var stands = db.Stands.Where(s => s.ExhibitorID == null).ToList();
IEnumerable<SelectListItem> selectList = from s in stands
                                         select new SelectListItem
                                                    {
                                                      Value = s.StandID,
                                                      Text = s.Description + "-- £" + s.Rate.ToString()
                                                    };
ViewBag.StandID = new SelectList(selectList, "Value", "Text");

Solution 3 - asp.net

You can create a partial Model class

public partial class Stand
{
    public string DisplayName
    {
        get
        {
            return this.Description + "-- £" + this.Rate.ToString();
        }
    }

}

Then in your View

var stands = db.Stands.Where(s => s.ExhibitorID == null).ToList();
ViewBag.StandID = new SelectList(stands,"StandID", "DisplayName");

Solution 4 - asp.net

The Format of the constructor that you are using is SelectList(IEnumerable items, string dataValueField, string dataTextField).

So when you use it the way you have you are actually telling it to bind to the TextField called "Description-- £Rate" and if this is not what the field is called coming in the from the DB it won't know what you are indicating.

Either of the two methods described above will work as long as the value you have in your dataValueField matches the name of the property you put the Value in and the dataTextField matches the property name of where you put the Text, perhaps a mix of the two solutions above. (Only because I prefer lambda expressions over linq.) and using a selectlist item prevents it from have to do a ToList on the collection after the transform. you are actually creating the objects that naturally bind to a select list.

You also may want to put in checks on the description or rate to make sure they aren't empty before putting them into the list

var stands = db.Stands.Where(s => s.ExhibitorID == null)
                  .Select(s => new SelectListItem
                {
                    Value = s.StandID.ToString(),
                    Text = s.Description + "-- £" + s.Rate.ToString()
                });
                  

ViewBag.StandID = new SelectList(stands, "Value", "Text");

Solution 5 - asp.net

I did this by modifying my View Model, here are my code:

The View Model

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MvcEsosNew.Models;
using System.Web.Mvc;

namespace MvcEsosNew.ViewModels
{
    public class EntitlementViewModel
    {
        public int EntitlementCount { get; set; }
        public Entitlement Entitlement { get; set; }
        public SelectList Member { get; set; }
        public SelectList Job_Grade { get; set; }
        public SelectList Department { get; set; }
        public SelectList Esos_Batch { get; set; }
    }

    public class department_FullName
    {
        public int deptID { get; set; }
        public string deptCode { get; set; }
        public string deptName { get; set; }
        public string fullName { get { return deptCode + " - " + deptName; } }
    }
}

The Controller

public void getAllDepartment(EntitlementViewModel entitlementVM)
        {
            var department = from Department in db.Departments.Where(D => D.Status == "ACTIVE").ToList()
                             select new department_FullName
                             {
                                 deptID   = Department.id,
                                 deptCode = Department.department_code,
                                 deptName = Department.department_name
                             };
            entitlementVM.Department = new SelectList(department, "deptID", "fullName");
        }

The View

     <div class="form-group row">
                <div class="col-sm-2">
                    @Html.LabelFor(model => model.Entitlement.department_id)
                </div>
                <div class="col-sm-10">
                     @Html.DropDownListFor(model => model.Entitlement.department_id, Model.Department, new { @class="form-control" })
                     @Html.ValidationMessageFor(model => model.Entitlement.department_id)
                </div>
            </div>

The result:

The Result

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMarkView Question on Stackoverflow
Solution 1 - asp.netStuartLCView Answer on Stackoverflow
Solution 2 - asp.netchridamView Answer on Stackoverflow
Solution 3 - asp.netGuishView Answer on Stackoverflow
Solution 4 - asp.netDRobertEView Answer on Stackoverflow
Solution 5 - asp.netRessa_PandaView Answer on Stackoverflow