Search code examples
c#asp.net-corerazorrazor-pages

How to pass multi List values using <a> tag?


Basic example link - following link is what I am trying to build. But this is only for single value.

Issue Detail After I select multi colors in <select>, Then i click <a> tag, I want to pass the value of what i select in <select>. Currently after clicking on <a> tag, it wont keep values selcted inside <select>

Step#1 Here I am creating Form with 2 filters. 1 search text box and 2 selectlist

<form asp-page="./index" method="get">
     <input type="text" asp-for="SearchString"  />
     <select asp-for="Colors" asp-items="@Model.Colors_SELECT" class="MultiSelect" multiple>...</select>
   ...
</form>

Step#2 Display data in table grid. <a> is passing filters to url

<table>
....
     <a asp-page="./My_Training"   
                    asp-route-SearchString="@Model.SearchString"
                    asp-route-Colors="@Model.Colors"
                    asp-route-SortOrder="@Model.Colors_Sort">
                        @Html.DisplayNameFor(model => model.MyListData[0].Colors)
     </a>
     .. // more `<a>` tags. 1 for each column 
  </table>

Step#3 Back-end code: - mainly bind filter values

[BindProperty(SupportsGet = true)]
public string? SearchString { get; set; }
[BindProperty(SupportsGet = true)]
public List<string>? Colors { get; set; }
public SelectList? Colors_SELECT { get; set; }

public async Task OnGetAsync()
{
    // everything is auto bind to properties  
}

What I tried: according to google, they recommended using asp-all-route-data with Dictionary. I have tried this code and it doesnt work for multi values. Dictionary doesnt allow same key. for example: if I use asp-all-route-data and pass URL like Colors[0]=Red&Colors[1]=Green than it wont keep values selected inside <select>

I also Tried to do this. This works but the code is a mess and hard to maintain if you have too many filters & columns in data grid

<input type="hidden" asp-for="URL_String" />
...
<a href="/Index? @Model.URL_String&[email protected]_Sort">
                        @Html.DisplayNameFor(model => model.CourseTakenList[0].Colors)
</a>

public string? URL_String { get; set; } = "";

  public async Task<IActionResult> OnPostAsync()
    {
        string? createURL = "?";
        createURL += $"SearchString={SearchString}&";
        foreach (var p in Colors)
        {
            createURL += $"Colors={p}&";
        }

        if (createURL.EndsWith("?") || createURL.EndsWith("&"))
        {
            createURL = createURL.TrimEnd(createURL[createURL.Length - 1]); //remove last '&' 
        }

        string url = $"{HttpContext.Request.Path}{createURL}";
        return Redirect(url);
    } 

  public async Task OnGetAsync()
  {
        URL_String = Request.QueryString.ToString().Replace("??", "?");
        CurrentSort = Request.Query["SortOrder"];        
 }

Solution

  • Because asp-all-route-data can't pass value with the same key, So you need to add index by yourself, Please refer to this simple demo:

    @{
        var colors = new Dictionary<string, string>();
        var i = 0;
        foreach (var item in Model.colors)
        {
            colors.Add($"colors[{i}]", item);
            i++;
        }
    }
    
    <a asp-page="index" asp-all-route-data="colors">Test</a>
    

    It will pass data like:

    ?colors[0]=red&colors[1]=green&colors[2]=black

    Demo:

    enter image description here

    =========================Update================

    <select multiple id="selectone">
        <option value="red">red</option>  
        <option value="black">black</option>
        <option value="white">white</option>  
        <option value="yellow">yellow</option>  
         
    </select>
    
    <button onclick="MySelect()">Select color</button>
    
    
    
    <a asp-page="index" asp-route-SearchString="Test" id="color">Test</a>
    
    
    
    <script>
       
        
    
        function MySelect(){
            var result = document.getElementById("selectone").selectedOptions;
            var arr=[];
            for(let i=0,len = result.length;i<len;i++){
                if(result[i].selected){
                    arr.push("colors["+i+"]=" + result[i].value)
                }
                
            }
    
    
            var str=arr.join("&");
           var a = document.getElementById("color").getAttribute('href');
    
           var url = a+ "&" + str;
    
           document.getElementById("color").href = url;
           
            
        }
    
    
       
    </script>
    

    Demo:

    enter image description here