Search code examples
c#asp.netrazor-pages

asp.net Razor Pages - Update select list based on the selection of another select list


I want to update a select list when the user selects a value in another select list. I've managed to get the first select list to call a get (or post) method on the model with a parameter, and can update the underlying data. But the second select list never shows the new values.

I'm not very experienced with asp.net, so what am I doing wrong?

Code below

.cshtml

<div>
    <form method="post">
        <select id="departureStation" asp-items="Model.DepartureStations" onchange="getDestinationStations()"></select>
        <select id="destinationStation" asp-items="Model.DestinationStations"></select>
    </form>
</div>


@section Scripts {
<script type="text/javascript">
    function getDestinationStations() {
        var selectedDepartureStationID = $("#departureStation").find(":selected").val();
        console.log("selectedDepartureStationID = " + selectedDepartureStationID);

        $.ajax({
            type: "GET",
            url: "/Index?handler=Departure",
            beforeSend: function (xhr) {
                xhr.setRequestHeader("XSRF-TOKEN",
                    $('input:hidden[name="__RequestVerificationToken"]').val());
            },
            data: {
                selectedDepartureStationID: selectedDepartureStationID
            },
            success: function(result) {
                console.log("success - " + result);
            },
            error: function() {
                console.log("failure");
            }
        })
    }
</script>
}

.cs

public List<SelectListItem> DestinationStations
        {
            get
            {
                if (this._selectedDepartureStationID == -1)
                    return new List<SelectListItem>();

                List<Models.Station> stations = new List<Models.Station>();

                List<Models.RouteSegment> routeSegments = this._context.RouteSegments.Where(x => x.StationID == this._selectedDepartureStationID).ToList();
                foreach (Models.RouteSegment routeSegment in routeSegments.DistinctBy(x => x.RouteID))
                {
                    List<Models.RouteSegment> routeSegments2 = this._context.RouteSegments.Where(x => x.RouteID == routeSegment.RouteID).Include(x => x.Station).ToList();
                    stations.AddRange(routeSegments2.Select(x => x.Station));
                }

                return new List<SelectListItem>(stations.Distinct().ToList().Select(x => new SelectListItem { Value = x.StationID.ToString(), Text = x.StationName }).ToList());
            }
        }

        public IndexModel(MyViewContext context)
        {
            this._context = context;
        }

        public void OnGet()
        {
            this.DepartureStations = this._context.Stations.Select(x => new SelectListItem { Value = x.StationID.ToString(), Text = x.StationName }).ToList();
        }

        public IActionResult OnGetDeparture(int selectedDepartureStationID)
        {
            this._selectedDepartureStationID = selectedDepartureStationID;

            return Page();
        }

Solution

  • Whenever your #departureStation select changes, your code will call getDestinationStations javascript code. Inside that function you are sending a request to your backend server to receive possible destination stations if I understood correctly. What you need to do here is when ajax request successes, add options dynamically based on your returned array or data.

    I am assuming your "/Index?handler=Departure" returns a JSON like:

    [
    {
        id: 1,
        name: "station1"
    },
    {
        id: 2,
        name: "station2"
    }
    ]
    

    Check if code below works.

    $.ajax({
                type: "GET",
                url: "/Index?handler=Departure",
                beforeSend: function (xhr) {
                    xhr.setRequestHeader("XSRF-TOKEN",
                        $('input:hidden[name="__RequestVerificationToken"]').val());
                },
                data: {
                    selectedDepartureStationID: selectedDepartureStationID
                },
                success: function(result) {
                    let destinationStationSelect = $('#destinationStationSelect');
                    let optionTemplate = $('<option></option>');
                    $.each(result, (index, element) => {
                      let option = optionTemplate.clone();
                      option.append(element.name);
                      option.attr('value', element.id);
                      destinationStationSelect.append(option);
                    });
                },
                error: function() {
                    console.log("failure");
                }
            })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>