Saturday, July 15, 2023

ASP.NET Core - Cascading dropdowns in Razor Page form using Fetch API

Objective. To learn about JavaScript fetch API, .NET SelectListItem and JsonSerializer. The fetch method takes two parameters. First parameter is the handler method which is defined in the Razor application and is invoked by the fetch API. The second parameter is all about the action method such as Get or Post and the resource is in the body or header etc.
Project
  • Open the Visual Studio. 
  • Create web project using ASP.NET Core Empty template.
  • Project name: CascadingDropdownsRP
  • Solution name: CascadingDropdownsRP
  • .NET Core version: 5.0
  • Add the AddRazorPages() into the IServiceCollection in Startup class.
  • Use MapRazorPages() as terminal middleware in Startup class.
Look at the below updated code in Startup class.
Startup.cs

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace CascadingDropdownsRP
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapRazorPages();
            });
        }
    }
}

  • Add a New Folder and rename it Pages.
  • Add a Razor Page in Pages folder and name it Index. Two files are generated which are Index.cshtml and Index.cshtml.cs
Next step. Update the Index.cshtml to create a simple table. Add the JavaScript code to handle the event occured due to selection change in the dropdown. Note that the handler is ChangedCountry and method is GET, so we have OnGetChangedCountry action in the code behind Index.cshtml.cs file. The name of parameter is name. The name must be the same in handler action method as well.   
Index.cshtml


@page
@model CascadingDropdownsRP.Pages.IndexModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
    List<string> list = new List<string>()
    {
        "India", "France","Pakistan","Germany"
    };
    IEnumerable<SelectListItem> countries = list.ConvertAll(x =>
    {
        return new SelectListItem()
                {
                    Text = x,
                    Value = x.ToLower(),
                    Selected = false
                };
    });
}
<style>
    .tbl {
        border: solid red 5px;
        margin: auto;
        width: 25%;
        padding: 10px;
    }
</style>
<div class="tbl">
    <span id="msg" style="text-align:center"></span>
    <table border="0" cellpadding="5">
        <tr>
            <td>
                <select id="ddl" asp-items="@countries"></select>
            </td>
        </tr>
        <tr>
            <td>
                <select id="targetddl" required></select>
            </td>
        </tr>
    </table>
</div>

<script type="text/javascript">
    (function () {
        ddl.addEventListener("change", async function (event) {
            document.getElementById("msg").innerHTML = "<h3>You selected " + ddl.value.toUpperCase() + "</h3>";
            console.log("changed the selection...");
            targetddl.options.length = 0; // remove all items
            fetch("/?handler=ChangedCountry&name=" + ddl.value,
                {
                    method: "GET"
                }
            ).catch("Error in the catch")
                .then(response => {
                    response.json().then(data => JSON.parse(data).forEach(x => {
                        // create an <option> DOM element
                        var opt = document.createElement("option");
                        opt.setAttribute("value", x);
                        opt.innerHTML = x;
                        targetddl.append(opt);
                    }));
                })

        });
    })();
</script>
  • We can remove all options from the select element by setting the length equal to zero. In the above example, note it. targetddl.options.length = 0;
  • We have created list of SelectListItem by creating List of string first but we can create list of SelectListItem in one step as well.
  • Note that despite the method being named json(), the result is not JSON but is instead the result of taking JSON as input and parsing it to produce a JavaScript object. This is why in server side code we use JsonResult as return type. The json() method of the Response interface takes a Response stream and reads it to completion. It returns a promise which resolves with the result of parsing the body text as JSON.
Index.cshtml.cs The handler method must return JSON object as it is handled by the fetch API. So, the handler return type is JsonResult.

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;

namespace CascadingDropdownsRP.Pages
{
    public class IndexModel : PageModel
    {
        public async Task<JsonResult> OnGetChangedCountry(string name)
        {
            await Task.Delay(500);
            List<string> states = new List<string>();
            switch(name) {
                case "india":
                    {
                        states.Add("India1");
                        states.Add("India2");
                        states.Add("India3");
                        states.Add("India4");
                    }
                    break;
                case "france":
                    {
                        states.Add("France1");
                        states.Add("France2");
                        states.Add("France3");
                        states.Add("France4");
                    }
                    break;
                case "pakistan":
                    {
                        states.Add("Pakistan1");
                        states.Add("Pakistan2");
                        states.Add("Pakistan3");
                        states.Add("Pakistan4");
                    }
                    break;
                case "germany":
                    {
                        states.Add("Germany1");
                        states.Add("Germany2");
                        states.Add("Germany3");
                        states.Add("Germany4");
                    }
                    break;
            }
            return new JsonResult(JsonSerializer.Serialize(states));
        }
    }
}

No comments:

Post a Comment

Hot Topics