Search code examples
c#razorblazor

How can I use HTML attributes in Blazor?


I am using an input list because I need to contain more than 1,000 data and consider mobile users. So I am using it as another attribute to hide the real value.

ex)

<datalist id="list1">
<option realvalue="1">Option1</option>
</datalist>
<input type="text" list="list1" />
@code{
  private string list1value;
  private void inputchanged()
  {
    listvalue = ???//datalist realvalue
    //etc
  }
}

I need to use the real value in code

I want to communicate with DB using real value, but I don't know how to use it even after searching


Solution

  • I'm guessing you want something like a select control, but using a data list. If so:

    Here's my BlazrInputSelectList control that does that.

    @using System.Linq.Expressions;
    @typeparam TValue
    @typeparam TListItem
    
    <InputText @attributes=this.AdditionalAttributes
               list="@listId"
               Value=@this.selectedValue
               ValueChanged=OnChange
               ValueExpression="() => this.selectedValue"
               placeholder="@this.PlaceholderText" />
    
    <datalist id="@listId">
    
        @foreach (var option in this.DisplayOptionsItems)
        {
            <option>@(this.OptionDelegateText(option))</option>
        }
    
    </datalist>
    
    @code {
        [Parameter] public TValue? Value { get; set; }
        [Parameter] public EventCallback<TValue> ValueChanged { get; set; }
        [Parameter] public Expression<Func<TValue>>? ValueExpression { get; set; }
    
        [Parameter, EditorRequired] public IEnumerable<TListItem> DisplayOptionsItems { get; set; } = default!;
        [Parameter, EditorRequired] public Func<TListItem, string> OptionDelegateText { get; set; } = default!;
        [Parameter, EditorRequired] public Func<TListItem, string, bool> OptionDelegateFinder { get; set; } = default!;
        [Parameter, EditorRequired] public Func<TListItem, TValue> OptionDelegateValue { get; set; } = default!;
    
        [Parameter] public string PlaceholderText { get; set; } = "Select a Value";
        [Parameter(CaptureUnmatchedValues = true)] public IReadOnlyDictionary<string, object>? AdditionalAttributes { get; set; }
    
        private string? selectedValue;
        private readonly string listId = Guid.NewGuid().ToString();
    
        protected override void OnInitialized()
        {
            // Check we have all the delegates. If not throw an exception before we try and render a null list
            ArgumentNullException.ThrowIfNull(this.DisplayOptionsItems);
            ArgumentNullException.ThrowIfNull(this.OptionDelegateText);
            ArgumentNullException.ThrowIfNull(this.OptionDelegateFinder);
            ArgumentNullException.ThrowIfNull(this.OptionDelegateValue);
        }
    
        private async Task OnChange(string value)
        {
            selectedValue = value;
            var item = this.DisplayOptionsItems.FirstOrDefault(item => this.IsItem(item));
            if (item is not null)
                await this.ValueChanged.InvokeAsync(this.OptionDelegateValue(item));
        }
    
        private bool IsItem(TListItem item)
        {
            if (selectedValue is not null)
                return this.OptionDelegateFinder.Invoke(item, selectedValue);
    
            return false;
        }
    }
    

    You implement it in a form like this. I've shown cached and uncached delegate versions. The second cached version is more efficient [the anonymous methods are rebuilt every time the component renders], but has a little more code.

    @page "/"
    
    <PageTitle>Index</PageTitle>
    
    <h1>Hello, world!</h1>
    
    <div class="bg-dark text-white m-2 p-2">
    <pre>Selected Guid : @_selectedUid </pre>
    <pre>Selected Guid1 : @_selectedUid1 </pre>
    </div>
    
    <BlazrInputSelectList class="form-control mb-3"
                          @bind-Value=_selectedUid
                          DisplayOptionsItems=this._countries
                          OptionDelegateText="(item) => item.Name"
                          OptionDelegateFinder="(item, value) => item.Name.Equals(value, StringComparison.CurrentCultureIgnoreCase)"
                          OptionDelegateValue="(item) => item.Uid" />
    
    <BlazrInputSelectList class="form-control mb-3"
                          @bind-Value=_selectedUid1
                          DisplayOptionsItems=this._countries
                          OptionDelegateText=this.GetOptionText
                          OptionDelegateFinder=this.GetOptionFinder
                          OptionDelegateValue=this.GetOptionValue />
    
    @code {
        private List<Country> _countries = new()
            {
                new(Guid.NewGuid(), "Portugal"),
                new(Guid.NewGuid(), "France"),
                new(Guid.NewGuid(), "Spain"),
            };
    
        private Guid? _selectedUid;
        private Guid? _selectedUid1;
    
        public record Country(Guid Uid, string Name);
    
        private string GetOptionText(Country item)
            => item.Name;
    
        private Guid? GetOptionValue(Country item)
            => item.Uid;
    
        private bool GetOptionFinder(Country item, string value)
            => item.Name.Equals(value, StringComparison.CurrentCultureIgnoreCase);
    }