Search code examples
c#asp.net-coredropdownrazor-pagescascadingdropdown

How can I create a cascading dropdown in razor pages using predefined select lists?


I know this question has been asked quite a lot on here, but most of those questions are based on MVC and use interfaces and controllers in which im not very familiar with. And the other ones deal with JSON which im not sure is what im needing.

My end goal is to have a dropdown list show a certain select list based on what was chosen in the first list. I quickly found there was no easy way to just change the "asp-items" tag in the select.

After more than a day of trying multiple posts, I've ended up extremely confused.

Also database has been seeded successfully and the select lists do populate when tested in a single dropdown. so I know its not that part.

What I've tried: I've tried to implement multiple different answers from other posts using jQuery, regular JavaScript, and ajax. I also even tried to make 3 different dropdowns pre-populated with the list and just show and hide them based the the first selections. I was unable to get that to work and also found in another post that doing that would cause values to still be selected even though its not visible. This problem is quickly draining my sanity and it seems so trivial but i cant seem to get it. I don't fully understand jQuery or ajax either so that doesn't help me very much either.

I've tried versions almost everything I've found but my most recent attempt looks like this:

Index.cshtml.cs

public class IndexModel : PageModel
{
    private readonly ILogger<IndexModel> _logger;
    private readonly Food2UContext _context;

    //First dropdowns options
    public static IEnumerable<SelectListItem> userTypeOptions() {
        return new[]
        {
            new SelectListItem {Text = "Customer", Value = "Shoppers"},
            new SelectListItem {Text = "Delivery Driver", Value = "DeliverPerson"},
            new SelectListItem {Text = "Restaurant", Value = "LocalRestaurants"},
        };
    } 

    //list to stores db object queries
    public List<Shoppers> shopper {get; set;} = default!;
    public List<DeliveryPerson> deliveryPeople {get; set;} = default!;
    public List<LocalRestaurants> restaurants {get; set;} = default!;

    //select lists to store each object type
    public SelectList shopperList {get; set;} = default!;
    public SelectList deliveryDriverList {get; set;} = default!;
    public SelectList restaurantList {get; set;} = default!;

    //select list to store the select list type chosen
    public SelectList displayedDropDown {get; set;} = default!;


    //called to grab select list depending on the first value selected
    public IActionResult OnGetFetchUserNames(string userType)
    {
        switch (userType)
        {
            case "Shoppers":
                displayedDropDown = shopperList;
                break;
            case "DeliverPerson":
                displayedDropDown = deliveryDriverList;
                break;
            case "LocalRestaurants":
                displayedDropDown = restaurantList;
                break;
        }
        
        //Tried json here because i saw another post successfully use it. 
        return new JsonResult(displayedDropDown);
    }

    public IndexModel(ILogger<IndexModel> logger, Food2UContext context)
    {
        _logger = logger;
        _context = context; //grab db context
    }

    //attempt to populate dropdowns and objects when page loads
    public void OnGet()
    {
        shopper = _context.Shoppers.ToList();
        deliveryPeople = _context.DeliverPerson.ToList();
        restaurants = _context.LocalRestaurants.ToList();

        shopperList = new SelectList(shopper, "shopperID", "Name");
        deliveryDriverList = new SelectList(deliveryPeople, "driverID", "Name");
        restaurantList = new SelectList(restaurants, "restaurantID", "Name");
    }
}

Index.cshtml

<form method="post">
        <div class="form-group w-25 mx-auto">
            <select id="userTypeDropDown" asp-items="IndexModel.userTypeOptions()" class="form-control">
                <option value="">-- Select User Type --</option>
            </select>
        </div>

        <div class="form-group w-25 mx-auto">
            <select id="userNameDropdown" name="users" asp-items="null" class="form-control">
                <option value="">-- Select Name --</option>
            </select>
        </div>
        
        <div class="form-group mt-3 text-center">
            <input type="submit" value="Continue" class="btn btn-secondary">
        </div>
    </form>

</div>

@*attempt to use ajax with the ongetfetch method from index.cshtml.cs*@
@section scripts{ 
<script>
    $("#userTypeDropDown").on("change", function () {
        var userType = $(this).val();
        $.ajax({
            method: 'get',
            url: '/Index?handler=FetchUserNames',
            data: {userType: userType },
            success: function (res) {
                $("#userNameDropdown").empty();
                var htmlString = "";
                $.each(res, function (k, v) {
                    htmlString += "<option value='" + v.val + "'>" + v.val + "</option>";
                });
                $("#userNameDropdown").append(htmlString);
            }

        })
    })
</script>
}

Solution

  • First, we should add shopper andshopperList in public IndexModel(ILogger<IndexModel> logger, Food2UContext context), so that we can get the value agian when we call OnGetFetchUserNames.

    try to change the code like:

    public class IndexModel : PageModel
        {
            private readonly ILogger<IndexModel> _logger;
            private readonly Food2UContext _context;
            //list to stores db object queries
            public List<Shoppers> shopper {get; set;} = default!;
            public List<DeliveryPerson> deliveryPeople {get; set;} = default!;
            public List<LocalRestaurants> restaurants {get; set;} = default!;
        
            //select lists to store each object type
            public SelectList shopperList {get; set;} = default!;
            public SelectList deliveryDriverList {get; set;} = default!;
            public SelectList restaurantList {get; set;} = default!;
        
            //select list to store the select list type chosen
            public SelectList displayedDropDown {get; set;} = default!;
            //First dropdowns options
            public static IEnumerable<SelectListItem> userTypeOptions() {
                return new[]
                {
                    new SelectListItem {Text = "Customer", Value = "Shoppers"},
                    new SelectListItem {Text = "Delivery Driver", Value = "DeliverPerson"},
                    new SelectListItem {Text = "Restaurant", Value = "LocalRestaurants"},
                };
            } 
     
            //called to grab select list depending on the first value selected
            public IActionResult OnGetFetchUserNames(string userType)
            {
                switch (userType)
                {
                    case "Shoppers":
                        displayedDropDown = shopperList;
                        break;
                    case "DeliverPerson":
                        displayedDropDown = deliveryDriverList;
                        break;
                    case "LocalRestaurants":
                        displayedDropDown = restaurantList;
                        break;
                }
                
                //Tried json here because i saw another post successfully use it. 
                return new JsonResult(displayedDropDown);
            }
        
            public IndexModel(ILogger<IndexModel> logger, Food2UContext context)
            {
                _logger = logger;
                _context = context; //grab db context
                shopper = _context.Shoppers.ToList();
                deliveryPeople = _context.DeliverPerson.ToList();
                restaurants = _context.LocalRestaurants.ToList();
        
                shopperList = new SelectList(shopper, "shopperID", "Name");
                deliveryDriverList = new SelectList(deliveryPeople, "driverID", "Name");
                restaurantList = new SelectList(restaurants, "restaurantID", "Name");
            }
            }
        
            //attempt to populate dropdowns and objects when page loads
            public void OnGet()
            {
                
            }
    

    Second: Define the htmlString like

    htmlString += "<option value='" + v.value + "'>" + v.text + "</option>"; 
    

    result: enter image description here