asp.net-coreblazor

Dropdown list is not working in the Asp.net Blazor Component


I am trying to learn the new feature in ASP.NET Blazor. I am using Visual Studio 2019. I am trying to create an Ideas Registration form. So the code for dropdownlist i had took from Bootstrap 4. It was not working as expected. Can you please tell me where i am working wrong?

Just a little overwhelmed here, any advice would be much appreciated.

Given Code:

<!-- Card Body -->
<div class="card-body">
    <!-- <form   -->
    <form>
        <div class="form-group">
            <label for="exampleFormControlInput1">Title</label>
            <input type="email" class="form-control" id="exampleFormControlInput1">
        </div>
        <div class="form-group">
            <label for="exampleFormControlSelect1">Description</label>
            <textarea class="form-control" id="exampleFormControlTextarea1" rows="4"></textarea>
        </div>
        <!-- Basic dropdown -->
        <div class="form-group">
        <button class="btn btn-primary dropdown-toggle mr-4" type="button" data-toggle="dropdown"
                aria-haspopup="true" aria-expanded="false">
            Basic dropdown
        </button>

        <div class="dropdown-menu">
            <a class="dropdown-item" href="#">.Net</a>
            <a class="dropdown-item" href="#">Python</a>
            <a class="dropdown-item" href="#">Data Science</a>
            <div class="dropdown-divider"></div>
        </div>
        </div>
        <!-- Basic dropdown -->


Solution

  • where i am working wrong

    1. According to the official docs](https://getbootstrap.com/docs/4.0/components/dropdowns/#data-toggledropdown-still-required):

      Regardless of whether you call your dropdown via JavaScript or instead use the data-api, data-toggle="dropdown" is always required to be present on the dropdown’s trigger element.

      I would suggest you should wrap your Basic dropdown in the following structure

       <div class="dropdown">  
            <button data-toggle="dropdown" class="..." > ...</button>
            <div class="dropdown-menu ...>
                ...
            </div>
       </div>
       
    2. You didn't add an event handler for selection. At least you should add a @onclick for the toggle button. When clicking this button, show or hide the dropdown-menu.

    3. Finally, if you want to implement the dropdown component with Blazor(without javascript), you should also replace the text content within the toggle button when someone selects a dropdown list item.

    A Demo : How to Create A General Dropdown Component

    Rather than simply fixing the issue, I think it's much better to create a general dropdown Component so that we can always invoke them in following way:

    @{ var list = new List<string>{ ".NET", "Python","Java" }; }
    <Dropdown TItem="string" OnSelected="@OnSelected" >
        <InitialTip>This is a dropdown list</InitialTip>
        <ChildContent>
            <DropdownListItem Item="@list[0]">.NET</DropdownListItem>
            <DropdownListItem Item="@list[1]">Python</DropdownListItem>
            <div class="dropdown-divider"></div>
            <DropdownListItem Item="@list[2]">Java</DropdownListItem>
        </ChildContent>
    </Dropdown>
    
    @code {
        private void OnSelected(string selection)
        {
            Console.WriteLine(selection);
        }
    }
    

    Here the TItem is a generic type parameter that is the type of each dropdown list item and can be any .NET type.

    Demo

    enter image description here

    How-To

    1. Add a Shared/Dropdown.razor component:

      @using Microsoft.AspNetCore.Components.Web
      @typeparam TItem
      <div class="dropdown">
          <button class="btn btn-primary dropdown-toggle mr-4" data-toggle="dropdown" type="button" @onclick="e => this.show=!this.show " 
                  aria-haspopup="true" aria-expanded="false">
                  @Tip
          </button>
          <CascadingValue name="Dropdown" Value="@this">
          <div class="dropdown-menu @(show? "show":"")" >
              @ChildContent
          </div>
          </CascadingValue>
      </div>
      
      @code {
          [Parameter]
          public RenderFragment InitialTip{get;set;}
          [Parameter]
          public RenderFragment ChildContent{get;set;}
          [Parameter]
          public EventCallback<TItem> OnSelected {get;set;}
      
          private bool show = false;
          private RenderFragment Tip ;
      
          protected override void OnInitialized(){ this.Tip = InitialTip; }
          public async Task HandleSelect(TItem item, RenderFragment<TItem> contentFragment)
          {
              this.Tip= contentFragment.Invoke(item);
              this.show=false;
              StateHasChanged();
              await this.OnSelected.InvokeAsync(item);
          }
      }
      
    2. Add a Shared/DropdownListItem.razor component:

      @using Microsoft.AspNetCore.Components.Web
      @typeparam TItem
      <a class="dropdown-item" Item="@Item" @onclick="e=> Dropdown.HandleSelect(Item, ChildContent)" >@ChildContent(Item)</a>
      
      @code {
          [CascadingParameter(Name="Dropdown")]
          public Dropdown<TItem> Dropdown {get;set;}
      
          [Parameter]
          public TItem Item{get;set;}
          [Parameter]
          public RenderFragment<TItem> ChildContent {get;set;}
      }