Search code examples
c#autocompletemudblazor

MudAutocomplete with a complex object to set text and value of edit form properties


I'm implementing an autocomplete function using MudAutocomplete. It works perfectly well if I simply want to bind the single search value into a model value in my editform. I cant figure out how to populate two values though. The autocomplete searches a list of agencies and puts the agency name into agency name property of the form but I also need to populate a hidden AgencyIdentifier field. Here's a simplified sample of my edit form just showing the autocomplete (in reality there are many more input fields on the form, this is just for demo purposes)

<EditForm Model="@ApplicationUser" OnValidSubmit="OnValidSubmit">
    <DataAnnotationsValidator />
    <MudDialog Style="width:550px;height:650px;">
        <DialogContent>
            <MudGrid>
                <MudItem xs="12">
                    <MudCard>
                        <MudCardContent>
                            <MudStack Row="true">
                                <MudStack Row="true">
                                    <MudAutocomplete Label="Agency" @bind-Value="@ApplicationUser.AgencyName" Required="true"
                                                        SearchFunc="@AgenciesAsync" Immediate="true"  ResetValueOnEmptyText="true"
                                                        AdornmentIcon="@MudBlazor.Icons.Material.Filled.Search" AdornmentColor="MudBlazor.Color.Primary"
                                                        For="@(() => ApplicationUser.AgencyName)" />

                                    
                                         
                                </MudStack>
                            </MudStack>
                        </MudCardContent>
                        <MudCardActions>
                            <div Class="pr-2">
                                <MudButton Variant="Variant.Filled" StartIcon="@MudBlazor.Icons.Material.Filled.Cancel" Color="MudBlazor.Color.Error" Size="MudBlazor.Size.Small" OnClick="Cancel" ButtonType="MudBlazor.ButtonType.Button">Cancel</MudButton>
                            </div>
                            <div Class="pr-2">
                                <MudButton Variant="Variant.Filled" StartIcon="@MudBlazor.Icons.Material.Filled.Save" Color="MudBlazor.Color.Success" Size="MudBlazor.Size.Small" ButtonType="MudBlazor.ButtonType.Submit">Save</MudButton>
                            </div>
                        </MudCardActions>
                    </MudCard>
                </MudItem>
            </MudGrid>
        </DialogContent>
    </MudDialog>
</EditForm>

here's the code activated when a valid form submission is made

private async Task OnValidSubmit(EditContext context)
{
    if (context.Validate())
    {
        var agencyDTO = Mapper.Map<UserEditViewModel, ApplicationUser>(ApplicationUser);
        //update & save code goes here
        await InvokeAsync(() => MudDialog.Close(DialogResult.Ok(context)));
    }

}

and this is the search function for the agency lookup

private async Task<IEnumerable<string?>> AgenciesAsync(string value)
{
    var empty = Enumerable.Empty<string>();
    if (!String.IsNullOrEmpty(value) && value.Length > 0)
    {
        var agencies = await AgencyService.AgencyAutocompleteLookupAsync(value.Trim());
        var result = agencies.Select(x => x.AgencyName);
        return result;
    }
    else
    {
        return empty;
    }
    
}

I'm struggling to implement a search function that returns an object containing the AgencyName & AgencyIdentifier

I tried creating a simple view model and returning that from the search function like this

public class AgencyLookupViewModel
{
    public Guid AgencyIdentifier { get; set; }
    public string AgencyName { get; set; } = string.Empty;
}

Then I modified the search lookup

private async Task<IEnumerable<AgencyLookupViewModel?>> AgenciesAsync(string value)
{
    var empty = Enumerable.Empty<AgencyLookupViewModel>();
    if (!String.IsNullOrEmpty(value) && value.Length > 0)
    {
        var agencies = await AgencyService.AgencyAutocompleteLookupAsync(value.Trim());
        var result = Mapper.Map <IEnumerable<AgencyDto>,IEnumerable<AgencyLookupViewModel>>(agencies);
        return result;
    }
    else
    {
        return empty;
    }

}

I just cant figure out how to get this to work with the MudAutocomplete so that I can populate both the forms AgencyName & the forms hidden AgencyIdentifier. Can anyone help ?


Solution

  • If your SearchFunc is utilizing an object, the MudAutoComplete component needs to be made aware of what that object is. You do this by specifying the T property of the MudAutoComplete. Here is an example.

    <MudAutocomplete T="Element" 
                     @bind-Value="value" 
                     SearchFunc="@Search" 
                     ToStringFunc="@(e=> e==null?null : $"{e.Name} ({e.Sign})")"/>
    
    

    What this shows is the MudAutoComplete is bound to an Element object. The ToStringFunc is used to display what you want. In your case it would be the Name (the example uses name and sign). The bind-value is an Element variable that gets set to the users selection. This means that once the user makes a selection, you have access to the full selected Element via the bound value. This means you can now get the AgencyIdentifier or any other public property available on the object (in the example, the element Number is retrieved).