Дочерние компоненты: как включить ввод на основе состояния другого компонента

Я разрабатываю приложение Blazor WebAssembly, в котором у меня есть родительский компонент Father, содержащий два дочерних компонента (Child1 и Child2). Child2 следует включать только при выполнении определенного условия в Child1, но я сталкиваюсь с проблемами с поддержанием правильного состояния между этими компонентами.

В Child1 у меня есть компонент автозаполнения MudAutocomplete, который при выборе должен включать определенные функции в Child2, устанавливая состояние Model.SuperUser в родительском компоненте Father. Я позаботился о том, чтобы StateHasChanged() вызывался после обновления состояния в Child1, но ввод в Child2 оставался отключенным, даже если условие Model.SuperUser != null выполнено.

@page "/father"

<Child1 Model = "model" />
<Child2 Model = "model" />

@code {

    private MyModel model;
    protected override void OnInitialized()
    {
        model = new MyModel();
        base.OnInitialized();
    }


    public class MyModel
    {
        public int? AdminUserId { get; set; }
        public UserDTO? AdminUser { get; set; }

        public int? CustomerUserId { get; set; }
        public UserDTO? CustomerUser { get; set; }

        public int? SuperUserId { get; set; }
        public UserDTO? SuperUser { get; set; }
    }
}

// Child1.razor
<!-- SuperUser -->
<div class = "form-group col-6">
    <label class = "required" for = "SuperUser">@Localizer["SuperUser"]</label>
    <MudAutocomplete T = "UserDTO"
                     ResetValueOnEmptyText = "true"
                     SearchFunc = "@SearchSuperUser"
                     ToStringFunc = "@(e => e == null ? null : $"{e.Email}")"
                     ShowProgressIndicator = "true"
                     Variant = "Variant.Outlined"
                     Clearable = "true"
                     Placeholder = "@Localizer["PleaseSelectSuperUser"]"
                     OnClearButtonClick = "OnSuperUserCleared"
                     ProgressIndicatorColor = "Color.Primary"
                     ValueChanged = "OnSuperUserValueChanged">
        <NoItemsTemplate>
            <MudList Clickable = "false">
                <MudListItem>
                    @Localizer["NoItemsWasFound"]
                </MudListItem>
            </MudList>
        </NoItemsTemplate>
        <BeforeItemsTemplate>
            <MudText Color = "Color.Primary" Class = "mud-list-item mud-list-item-gutters mud-list-item-clickable mud-ripple">@Localizer["PleaseSelectSuperUser"]</MudText>
        </BeforeItemsTemplate>
        <ProgressIndicatorInPopoverTemplate>
            <MudList Clickable = "false">
                <MudListItem>
                    @Localizer["Loading"]
                </MudListItem>
            </MudList>
        </ProgressIndicatorInPopoverTemplate>
    </MudAutocomplete>
    <ValidationMessage For = "@(() => Model.SuperUserId)" />
</div>

@code {
    [Parameter][EditorRequired] public MyModel Model { get; set; } = null!;

    private async Task<IEnumerable<UserDTO>> SearchSuperUser(string value)
    {
        var result = await _myService.GetSuperUserFiltered(value);
        if (result != null)
        {
            return result;
        }
        return new List<UserDTO>();

    }

    private void OnSuperUserCleared(MouseEventArgs args)
    {
        Model.SuperUser = null;
        Model.SuperUserId = null;
        StateHasChanged();
    }

    private void OnSuperUserValueChanged(UserDTO value)
    {
        Model.SuperUser = value;
        Model.SuperUserId = value.Id;
        StateHasChanged();
    }
}

// Child2.razor
<!-- AdminUser -->
<div class = "form-group col-6">
    <label class = "required" for = "AdminUser">@Localizer["AdminUser"]</label>
    <MudAutocomplete T = "UserDTO"
                     ResetValueOnEmptyText = "true"
                     SearchFunc = "@SearchAdminUser"
                     ToStringFunc = "@(e => e == null ? null : $"{e.Email}")"
                     ShowProgressIndicator = "true"
                     Variant = "Variant.Outlined"
                     Clearable = "true"
                     Placeholder = "@Localizer["PleaseSelectAdminUser"]"
                     OnClearButtonClick = "OnAdminUserCleared"
                     ProgressIndicatorColor = "Color.Primary"
                     ValueChanged = "OnAdminUserValueChanged"
                     Disabled = "Model.SuperUser == null"> <!-- It should be enabled only id SuperUser is selected -->
        <NoItemsTemplate>
            <MudList Clickable = "false">
                <MudListItem>
                    @Localizer["NoItemsWasFound"]
                </MudListItem>
            </MudList>
        </NoItemsTemplate>
        <BeforeItemsTemplate>
            <MudText Color = "Color.Primary" Class = "mud-list-item mud-list-item-gutters mud-list-item-clickable mud-ripple">@Localizer["PleaseSelectAdminUser"]</MudText>
        </BeforeItemsTemplate>
        <ProgressIndicatorInPopoverTemplate>
            <MudList Clickable = "false">
                <MudListItem>
                    @Localizer["Loading"]
                </MudListItem>
            </MudList>
        </ProgressIndicatorInPopoverTemplate>
    </MudAutocomplete>
    <ValidationMessage For = "@(() => Model.AdminUserId)" />
</div>

@code {
    [Parameter][EditorRequired] public MyModel Model { get; set; } = null!;

    private async Task<IEnumerable<UserDTO>> SearchAdminUser(string value)
    {
        if (Model.SuperUserId.HasValue && Model.SuperUserId.Value > 0)
        {
            var filter = new { Model.SuperUserId, value };
            var result = await _myService.GetAdminUserBySuperUserFiltered(filter);
            if (result != null)
            {
                return result;
            }
        }
        return new List<UserDTO>();

    }

    private void OnAdminUserCleared(MouseEventArgs args)
    {
        Model.AdminUser = null;
        Model.AdminUserId = null;
        StateHasChanged();
    }

    private void OnAdminUserValueChanged(UserDTO value)
    {
        Model.AdminUser = value;
        Model.AdminUserId = value.Id;
        StateHasChanged();
    }
}

Несмотря на правильное обновление Model.SuperUser в Child1 и вызов StateHasChanged(), условие Disabled = "Model.SuperUser == null" в Child2 не включает ввод, как ожидалось.

Есть какие-нибудь предложения о том, как правильно включить/отключить ввод в Child2 в зависимости от состояния Model.SuperUser из Child1?

Вам необходимо использовать объект службы с ограниченной областью или объект каскадного состояния, который использует события для уведомления об изменениях. См. — stackoverflow.com/questions/77687611/…

MrC aka Shaun Curtis 18.04.2024 14:08
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
1
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете использовать каскадные значения для передачи Model из Parent в Childred элементы. Затем используйте обратный вызов события в Children, чтобы передать изменения обратно в Parent.

Вот модифицированная версия предоставленного вами кода.

Другие вопросы по теме