Search code examples
asp.netasp.net-corerazordropdownmulti-select

How to Change a Single Select Dropdown to a Multi-Select Dropdown?


Still in learning stages and want to learn how to create a multi-select dropdown.

I currently have a single select dropdown working. Here is the code for that:

Snip from Municipality Model:

        [Display(Name = "Associated Agencies")]
        public string? AssocAgencies { get; set; }

Snip from Municipality Create.cs:

public class CreateModel : PageModel
{
    private readonly ApplicationDbContext _db;
    public Municipality Municipality { get; set; }
    public CreateModel(ApplicationDbContext db)
    {
        _db = db;
    }

    public IEnumerable<Agency> DisplayAgencyData { get; set; }

    public async Task OnGet()
    {
        await _db.Agency.Select(a => a.AgencyName).ToListAsync();
        DisplayAgencyData = await _db.Agency.ToListAsync();
    }

    public async Task<IActionResult> OnPost()
    {
        if (ModelState.IsValid)
        {
            _db.Municipality.Add(Municipality);
            await _db.Municipality.AddAsync(Municipality);
            await _db.SaveChangesAsync();
            TempData["success"] = "Municipality added successfully.";
            return RedirectToPage("Index");
        }
        return Page();
    }

Snip from Municipality Create.cshtml:

    <table class="table table-bordeless" style="width:100%">
        <tr>
                <td style="width: 25%">
                    <div class="mb-3">
                        <label asp-for="Municipality.AssocAgencies"></label>
                        <select asp-for="Municipality.AssocAgencies" id="Select2" class="form-select" asp-items="@(new SelectList(Model.DisplayAgencyData.OrderBy(x => x.AgencyName),"AgencyName", "AgencyName"))"><option value="" selected disabled>---Select Agency---</option></select>
                    </div>
                </td>
        </tr>
    </table>

Values from the Agency model are: | Id | AgencyName | |:--:|:--------------------| |1 |N/A | |2 |Board of Appeals | |3 |City Council | |4 |Planning Board | |5 |Planning Commission | |6 |Town Board |

Since I have not done a multi-select before - Is the stored result in the data table cell a comma delimited value?

Ie, if the user selects options 2, 4 and 6 is the value "Board of Appeals, Planning Board, Town Board" OR "2, 4, 6" if someone were to bind the Ids rather than the values?

Also, is there an advantage to doing it this way OR is it more advantageous to have multiple separate single select dropdowns? I'm thinking it could be either way depending on how you wanted to pull the data.

Thanks in advance for your help!


Solution

  • 1.If you want to make dropdown multiple you need change string? to List<string>?.

    2.Then if you want to pass the Ids instead of name, you need change the second parameter of new SelectList:

    new SelectList(Model.DisplayAgencyData.OrderBy(x => x.AgencyName),"Id", "AgencyName")
    

    Whole working demo below

    Model:

    public class Municipality
    {
        [Display(Name = "Associated Agencies")]
        public List<string>? AssocAgencies { get; set; }
    }
    public class Agency
    {
        public int Id { get; set; }      //be sure your model contains id property
        public string AgencyName { get; set; }
    }
    

    Page:

    @page
    @model CreateModel
    <form method="post">
        <table class="table table-bordeless" style="width:100%">
            <tr>
                <td style="width: 25%">
                    <div class="mb-3">
                        <label asp-for="Municipality.AssocAgencies"></label>
                        <select asp-for="Municipality.AssocAgencies" id="Select2" class="form-select" asp-items="@(new SelectList(Model.DisplayAgencyData.OrderBy(x => x.AgencyName),"Id", "AgencyName"))"><option value="" selected disabled>---Select Agency---</option></select>
                    </div>
                </td>
            </tr>
        </table>
        <input type="submit" value="Post"/>
    </form>
    

    PageModel:

    [BindProperty]         //be sure add this....
    public Municipality Municipality { get; set; }
    public IEnumerable<Agency> DisplayAgencyData { get; set; }
    public void OnGet()
    {
        DisplayAgencyData = await _db.Agency.ToListAsync();
    }
    public async Task<IActionResult> OnPost()
    {
        //do your stuff....
    }
    

    Note:

    If you do not want to change string? to List<string>?, you can add an extra property which receives the multiple selected value and set the value forAssocAgencies by adding Quotes around string in a comma delimited list of strings.

    Page:

    <form method="post">
        <table class="table table-bordeless" style="width:100%">
            <tr>
                <td style="width: 25%">
                    <div class="mb-3">
                        <label asp-for="SelectedAgency"></label>
                 //don't forget change here asp-for .......
                        <select asp-for="SelectedAgency" id="Select2" class="form-select" asp-items="@(new SelectList(Model.DisplayAgencyData.OrderBy(x => x.AgencyName),"Id", "AgencyName"))"><option value="" selected disabled>---Select Agency---</option></select>
                    </div>
                </td>
            </tr>
        </table>
        <input type="submit" value="Post"/>
    </form>
    

    PageModel:

        [BindProperty]
        public Municipality Municipality { get; set; }
        public IEnumerable<Agency> DisplayAgencyData { get; set; }
        [BindProperty]
        public List<string> SelectedAgency { get; set; } //add this .
        public void OnGet()
        {
            DisplayAgencyData = await _db.Agency.ToListAsync();
        }
        public void OnPost()
        {
            Municipality.AssocAgencies = string.Join(",", SelectedAgency.Select(x => string.Format("'{0}'", x.Replace("'", "''"))));
    
        }