Совместное использование данных дочерними и родительскими компонентами в Blazor

Как осуществляется передача данных от родительских компонентов в дочерние с использованием каскадных параметров в Blazor мы уже знаем. При этом, вполне возможна необходимость и в обратном — передача данных от дочернего компонента в родительский. Сегодня мы рассмотрим вопрос про совместное использование данных дочерними и родительскими компонентами в Blazor и научимся передавать данные из дочернего компонента к предку. 

Рассмотрим следующую, достаточно распространенную, ситуацию: в приложении есть список сущностей (например, книг, телефонов и т.д.), каждая сущность имеет свой набор параметров, которые необходимо отобразить пользователю на экране. Соответственно, в приложении у нас есть два компонента:

  • дочерний — представляет собой конкретную сущность
  • родительский — список сущностей (это может быть как обычный список, так и таблица — сути это не меняет)

у нас есть задача — сортировать список сущностей по различным признакам, которые пользователь выбирает, например, кликая мышкой по соответствующему параметру сущности в списке.

Создадим такое приложение Blazor Hybrid, используя в качестве сущности, например, телефон. Для начала, создадим необходимую модель (класс) телефона. Для этого, создадим в папке Data файл Phone.cs со следующим содержимым:

namespace PhoneManager.Data
{
    public class Phone
    {
        /// <summary>
        /// Название телефона
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// Операционная система
        /// </summary>
        public string OS { get; set; }
        /// <summary>
        /// Цена телефона
        /// </summary>
        public int Price { get; set; }	
    }
}

Теперь создадим компонент Razor, который будет представлять информацию по одному телефону. Назовем его PhoneItem.razor:

@using PhoneManager.Data;

@if (PhoneData != null)
{
<div class="container">
    <div class="row-sm-12" @onclick="@(()=>PhoneElementClick(SortData.Name))">
        <b>@PhoneData.Name</b>
    </div>
        <div class="col-sm-6">
        Операционная система: <button class="btn btn-link" @onclick="@(()=>PhoneElementClick(SortData.OS))">@PhoneData.OS</button>
    </div>
        <div class="col-sm-6" @onclick="@(()=>PhoneElementClick(SortData.Price))">
            Цена: @PhoneData.Price
        </div>
</div>
}

@code {
    [Parameter]
    public Phone PhoneData { get; set; }
    
    [Parameter]
    public EventCallback<SortData> PhoneClick { get; set; }

    public async Task PhoneElementClick(SortData data)
    {
        await PhoneClick.InvokeAsync(data);	
    }
}

Рассмотрим более подробно этот компонент. Во-первых, у компонента определены два параметра:

public Phone PhoneData { get; set; }

Содержит информацию по телефону, которую необходимо показать пользователю.

[Parameter] 
public EventCallback<SortData> PhoneClick { get; set; }

С помощью этого параметра компонента Blazor мы будем вызывать метод родительского компонент для сортировки списка элементов. При этом, тип SortData будет содержать сведения о том, по какому критерию сортируется список и выглядит следующим образом:

public enum SortData
{
    Name, 
    Price,
    OS
}

У некоторых элементов <div> в разметке компонента определены обработчики события click:

@onclick="@(()=>PhoneElementClick(SortData.Name))

Таким образом, клик по элементу будет вызывать метод родительского компонента, который мы передадим дочернему в параметре PhoneClick.

Напишем родительский компонент PhoneList:

@using PhoneManager.Data


<h3>Список телефонов</h3>

@if (Phones != null)
{
    @sort
    <br>
    <div class="container">
    	@foreach (Phone phone in Phones)
        {
            <div class="row-sm">
              <PhoneItem PhoneData="@phone" PhoneClick="@ClickPhone"></PhoneItem>
            <hr>
            </div>
        }
    </div>
}


@code {
    [Parameter]
    public List<Phone> Phones { get; set; }

    string sort = "";

    private void ClickPhone(SortData data)
    {
        switch (data)
        {
            case SortData.Name: 
                {
                    Phones = Phones.OrderBy(o => o.Name).ToList();
                    sort = "Список отсортирован по названию";
                    break; 
                }	
            case SortData.OS: 
                { 
                    Phones = Phones.OrderBy(o => o.OS).ToList();
                    sort = "Список отсортирован по операционной системе";
                    break; 
                }
            case SortData.Price: 
                { 
                    Phones = Phones.OrderBy(o => o.Price).ToList();
                    sort = "Список отсортирован по цене";
                    break; 
                }
        }
    }
}

Этот компонент принимает один параметр — список телефонов, а также, содержит метод обратного вызова (ClickPhone), который будет срабатывать при кликах на определенные элементы в компоненте PhoneItem. Метод обратного вызова назначается в этой строке:

<PhoneItem PhoneData="@phone" PhoneClick="@ClickPhone"></PhoneItem>

Теперь откроем главную страницу приложения (Index.razor) и добавим на неё наш компонент PhoneList:

@page "/"

@using PhoneManager.Data

<PhoneList Phones="@phones"></PhoneList>

@code
{
    List<Phone> phones = new() 
    { 
        new() { Name = "Xiaomi", OS = "Android 13", Price = 40000 },
        new() { Name = "Samsung", OS = "Android 14", Price = 50000 },
        new() { Name = "LG", OS = "Android 9", Price = 60000 },
        new() { Name = "Honor", OS = "Android 10", Price = 12000 },
        new() { Name = "IPhone", OS = "iOS", Price = 120000 },
    };
}

Здесь мы в коде компонента создаем список телефонов, а в разметке — передаем его компоненту PhoneList. Запустим приложение и убедимся, что всё работает:

Приложение Blazor Hybrid список телефонов
Приложение Blazor Hybrid список телефонов. Несортированный список

 

Теперь нажмем на название телефона, операционную систему или цену и увидим, что список отсортируется по заданному критерию:

Отсортированный список телефонов
Отсортированный список телефонов

 

Итого

Таким образом, совместное использование данных дочерними и родительскими компонентами в Blazor осуществляется путем использования методов обратного вызова, которые назначаются дочерним компонентам через структуру EventCallback<T>. Используя EventCallback<T>, мы можем передавать в родительский компонент любую необходимую информацию — строки, числа, объекты и так далее. Родительский компонент будет обрабатывать полученную информацию и автоматически перерисовывать себя без дополнительных вызовом метода StateHasChanged.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии