(ASP.NET Core) Master Slave Cascading Dropdowns with Ajax

In nutshell: The selection change event of the master dropdown is used to send the "id" of the selected item to the server, which sends back a collection of items for the slave dropdown. A javascript based Ajax GET request is used for this communication with the server.
(Rev. 19-Mar-2024)

Categories | About |     |  

Parveen,

Create an ASP.NET Core project by using the empty template, and add a folder called "Pages" to hold the razor pages. Then right click the Pages folder to add a razor page called Index.

The Markup for Index.cshtml file

Write this markup in the index.cshtml razor page -

@page

@using MasterSlaveAjax.Pages

@model IndexModel

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<style type="text/css">
  td {
    padding: 4px;
  }
</style>

@{

  // for the dropdown select tag 
  // usually filled by querying a database 
  var masterList = new SelectListItem[] {

        new SelectListItem(){ Value = "",  Text = "[-Select-]"},

        new SelectListItem(){ Value = "1",  Text = "Desktop"},

        new SelectListItem(){ Value = "2", Text = "Laptop"}

      };

}

<h1>Ajax Master Slave Dropdown</h1>

<table>

  <tr>
    <td>
      <label>Master: </label>
    </td>
    <td>
      <select id="master" asp-items="@masterList" required></select>
    </td>
  </tr>

  <tr>
    <td>Slave: </td>
    <td>
      <select id="slave" required>
        <option value="">[-Select-]</option>
      </select>
    </td>
  </tr>

</table>

<span id="pw" style="color:red;"></span>

<script type="text/javascript">

  (function () {

    // attach on selection change event 
    master.addEventListener("change", async function (event) {

      // show please wait 
      pw.innerHTML = "please wait...";

      slave.innerHTML = "<option>[-Select-]</option>";

      // aysnchronous fetch ajax 
      fetch("/?handler=SlaveData&id=" + master.value,
        {
          method: "GET"
        }
      )
        // if any exceptions - log them 
        .catch(err => console.log("network error: " + err))

        .then(response => {

          // read json from the response stream 
          response.json().then(data => {

            // decode json and get the list 
            // then run a foreach 
            JSON.parse(data).forEach(item => {

              // create an <option> DOM element 
              var opt = document.createElement("option");

              opt.setAttribute("value", item.ID);

              opt.innerHTML = item.Name;

              // append to the slave dropdown 
              slave.append(opt);

            });

            // hide the please wait message 
            pw.innerHTML = "";

          });

        })
    });

  })();

</script>

Following is a brief explanation of the code:

var masterList = ...
masterList is an array/collection of SelectListItem type. We have hard-coded it, but an SQL query or something like that can be used to obtain the items in a real project.
select id="master" asp-items
This is a select tag to which the masterList has been attached by using ASP.NET Core tag helpers.
addEventListener("change" ...
addEventListener has been used to hook the change event of the master drop down. The value of the selected item is sent as a query string parameter for the GET URL. The GET request is sent with the fetch method of javascript.
JSON .parse(data) .forEach
The JSON received from the server is first parsed to obtain the array of items sent by the server. Then a forEach is used to construct option items and append them to the slave dropdown.

Video Explanation

The Index.cshtml.cs backing class

Write this code in the IndexModel backing class of the csharp file:

There is a naming rule for the C# GET handler - the method should be prefixed with OnGet. So, if the handler is MakeUpper, then the C# method should be OnGetMakeUpper(string param)
using Microsoft.AspNetCore.Mvc;

using Microsoft.AspNetCore.Mvc.RazorPages;

using System.Collections.Generic;

using System.Text.Json;

using System.Threading.Tasks;

namespace MasterSlaveAjax.Pages
{

  // should be in a separate file 
  // of models folder, i kept it 
  // here for convenience of tutorial 
  public class SlaveItem
  {

    public string ID { get; set; }
    public string Name { get; set; }
  }

  public class IndexModel : PageModel
  {

    // handler is GetSlaveData 
    // name is: OnGet[handler] 
    public async Task<JsonResult> OnGetSlaveData(string id)
    {

      // artifical delay 
      await Task.Delay(500);

      // some database query can be 
      // run to obtain a collection 
      // of slave items 
      IList<SlaveItem> data = new List<SlaveItem>();

      switch (id)
      {

      case "1":
        {

          data.Add(new SlaveItem() { ID = "1", Name = "Giga" });

          data.Add(new SlaveItem() { ID = "2", Name = "Zebro" });

        }

        break;

      case "2":
        {

          data.Add(new SlaveItem() { ID = "3", Name = "Dell" });

          data.Add(new SlaveItem() { ID = "4", Name = "Sony" });

        }

        break;

      }

      return new JsonResult(JsonSerializer.Serialize(data));

    }

  }

}

Here is the explanation of the above code:

class SlaveItem
This class represents the data for an option in the slave dropdown. The ID is attached for further processing, if any, and the Name is the display text of the dropdown option.
OnGetSlaveData(string id)
This is the function that handles the Ajax GET request that comes from the selection change event of the master dropdown. It receives an ID as a parameter, which is used to query the items for the slave.
switch (id)
This switch is just a simulation of some database query for obtaining the items for the slave dropdown.
JsonResult ( JsonSerializer. Serialize (data))
This serializes the collection of items into a string of JSON format, and sends it to the javascript ajax callback on the client side, where it is processed as explained above.

Run the project to see that the data is indeed sent as an Ajax GET call. It shows a "please wait" message and then displays the same input string converted to uppercase.


This Blog Post/Article "(ASP.NET Core) Master Slave Cascading Dropdowns with Ajax" by Parveen is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.