value display null for items selected select2 control although it filled by values ?

Ahmed Salah Abed Elaziz 390 Reputation points
2023-04-19T03:09:01.27+00:00

I working on blazor server side . I face issue I can't get values selected on razor page I can select data and fill on control select 2 but can't get values selected separated by comma outside on <p> tag. I put break point on event OnSelectedValuesChanged it not catch or hit when debug . Issue selected value for items selected display null custom control I made it (Select2MultiSelect.razor)

<select id="@ElementId" @onchange="OnSelectionChanged">
    @foreach (var option in Options)
    {
        <option value="@option.serverID">@option.server_Name</option>
    }
</select>

@code {
    [Parameter] public string ElementId { get; set; } = "select2_" + Guid.NewGuid().ToString("N");
    [Parameter] public List<SelectedServers> Options { get; set; } = new();
    [Parameter] public List<string> SelectedValues { get; set; } = new();
    [Parameter] public EventCallback<List<string>> SelectedValuesChanged { get; set; }

    private async Task OnSelectionChanged(ChangeEventArgs args)
    {
        SelectedValues = await JSRuntime.InvokeAsync<List<string>>("select2Interop.getSelectedValues", ElementId);
        await SelectedValuesChanged.InvokeAsync(SelectedValues);
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JSRuntime.InvokeVoidAsync("select2Interop.initializeSelect2", ElementId);
            await JSRuntime.InvokeVoidAsync("select2Interop.setSelectedValues", ElementId, SelectedValues);
        }
    }

JS file I use it Select2JsInterop.js

window.select2Interop = {
    initializeSelect2: function (elementId) {
        $('#' + elementId).select2({
            width: '100%',
            multiple: true
        });
    },

    getSelectedValues: function (elementId) {
        return $('#' + elementId).val();
    },

    setSelectedValues: function (elementId, values) {
        $('#' + elementId).val(values).trigger('change');
    }
};

on _host file i use

<script src="~/assets/js/select2jsinterop.js"></script>
    <script src="_framework/blazor.server.js"></script>

on UI I use control as below

 <Select2MultiSelect Options="@SimilarServers" SelectedValues="@selectedValues" SelectedValuesChanged="OnSelectedValuesChanged" />
                                        <p>Selected values: @string.Join(", ", @selectedValues)</p>
private void OnSelectedValuesChanged(List<string> newSelectedValues)
    {
        selectedValues = newSelectedValues;
        
    }
private List<SelectedServers> SimilarServers = new()
    {
        new SelectedServers { serverID = 1, server_Name = "atapa222" },
        new SelectedServers { serverID = 2, server_Name = "linuxdata2" }
        
    };
public class SelectedServers
    {
        public int serverID { get; set; }
        public string server_Name { get; set; }
    }

third party scripts i use it as below

<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

<!-- Select2 CSS -->
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />

<!-- Select2 JS -->
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>

selected value display null why and how to solve it ? see expected result below selectedvaluenullissue

Blazor
Blazor
A free and open-source web framework that enables developers to create web apps using C# and HTML being developed by Microsoft.
1,385 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Zhi Lv - MSFT 32,011 Reputation points Microsoft Vendor
    2023-04-25T06:48:33.8333333+00:00

    Hi @Ahmed Salah Abed Elaziz
    According to your code, I could reproduce the problem, after debugging it seems that the issue relates the select element's onchange event, it never triggers.
    I modify your code as below and use jquery select2's change event to get the selected text.
    Select2JsInterop.js:

    window.select2Interop = {
        initializeSelect2: function (dotNetHelper, elementId) {
            $('#' + elementId).val(""); //prevent the first selected option.
            $('#' + elementId).select2({ 
                placeholder: {
                    id: '', // the value of the option
                    text: 'None Selected'
                }, 
                width: '100%',
                multiple: true
            }).on('change', (event) => {
    
                var value = $('#' + elementId).select2('data').map((element) => element.text);
                if (value.length > 0) {
                    dotNetHelper.invokeMethodAsync('SetSelectedText', value);
                }
                console.log(value.join(", "));
    
            });
        },
    
        getSelectedValues: function (elementId) {
            console.log("get selected values");
            return $('#' + elementId).val();
        },
    
        setSelectedValues: function (elementId, values) {
    
            console.log("set selected values");
    
            $('#' + elementId).val(values).trigger('change');
        }
    };
    

    _Host.cshtml

        <!-- jQuery -->
        <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    
        <!-- Select2 CSS -->
        <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
    
        <!-- Select2 JS -->
        <script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
        <script src="/js/Select2JsInterop.js"> </script>
        <script src="_framework/blazor.server.js"></script> 
        <script src="/js/checksessiontimeout.js"></script>
    

    Select2MultiSelect.razor (my project name is BlazorServerIdentity, you need to change it to yours)

        @inject IJSRuntime JSRuntime
        @using BlazorServerIdentity.Data
        <select id="@ElementId" @onchange="OnSelectionChanged"> 
            @foreach (var option in Options)
            {
                <option value="@option.serverID">@option.server_Name</option>
            }
        </select>
        @code {
            [Parameter] public string ElementId { get; set; } = "select2_" + Guid.NewGuid().ToString("N");
            [Parameter] public List<SelectedServers> Options { get; set; } = new();
            [Parameter] public List<string> SelectedValues { get; set; } = new();
            [Parameter] public EventCallback<List<string>> SelectedValuesChanged { get; set; }
    
            private DotNetObjectReference<Select2MultiSelect>? objRef;
            protected override void OnInitialized()
            {
                objRef = DotNetObjectReference.Create(this);
            }
    
            private async Task OnSelectionChanged(ChangeEventArgs args)
            {
                SelectedValues = await JSRuntime.InvokeAsync<List<string>>("select2Interop.getSelectedValues", ElementId);
                await SelectedValuesChanged.InvokeAsync(SelectedValues);
            }
    
            protected override async Task OnAfterRenderAsync(bool firstRender)
            {
                if (firstRender)
                {
                    //await JSRuntime.InvokeAsync<IJSObjectReference>("import", "https://code.jquery.com/jquery-3.6.0.min.js");
                    //await JSRuntime.InvokeAsync<IJSObjectReference>("import", "https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js");
                    await JSRuntime.InvokeVoidAsync("select2Interop.initializeSelect2", objRef, ElementId);
                    //await JSRuntime.InvokeVoidAsync("select2Interop.setSelectedValues", ElementId, SelectedValues);
                }
            }
            [JSInvokable]
            public async void SetSelectedText(List<string> selected)
            {
    
                SelectedValues = selected;
                await SelectedValuesChanged.InvokeAsync(SelectedValues);
            }
        }
    

    Index.razor

        @page "/" 
    
        @using BlazorServerIdentity.Data
        @inject IJSRuntime JS
        <PageTitle>Index</PageTitle>
    
        <h1>Hello, world!</h1>
    
        Welcome to your new app.
     
        <Select2MultiSelect Options="@SimilarServers" SelectedValues="@selectedValues" SelectedValuesChanged="OnSelectedValuesChanged" />
        <p>Selected values: @string.Join(", ", @selectedValues)</p>
    
        @code { 
            private List<string> selectedValues = new List<string>();
    
            protected override async Task OnAfterRenderAsync(bool firstRender)
            {
                if (firstRender)
                {
                   // await JS.InvokeAsync<IJSObjectReference>("import", "https://code.jquery.com/ui/1.13.2/jquery-ui.js"); //"https://code.jquery.com/jquery-3.6.0.min.js"
    
                    //await JS.InvokeAsync<IJSObjectReference>("import", "https://code.jquery.com/jquery-3.6.0.min.js");
                    //await JS.InvokeAsync<IJSObjectReference>("import", "https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js");
                    //await JS.InvokeAsync<IJSObjectReference>("import", "./js/TestJS.js");
                }
            }
    
            private void OnSelectedValuesChanged(List<string> newSelectedValues)
            {
                selectedValues = newSelectedValues;
    
            }
            private List<SelectedServers> SimilarServers = new()
            {
                new SelectedServers { serverID = 1, server_Name = "atapa222" },
                new SelectedServers { serverID = 2, server_Name = "linuxdata2" }
    
            }; 
        }
    
    

    Then, the result as below: image2


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.
    Best regards,
    Dillion

    1 person found this answer helpful.
    0 comments No comments