Exercício - Partilhar dados em aplicações Blazor

Concluído

Agora que seu aplicativo está conectado a um banco de dados, é hora de adicionar a capacidade de os clientes configurarem e pedirem uma pizza.

Blazing Pizza quer que você construa a capacidade de os clientes mudarem o tamanho de suas pizzas especiais. Você precisa armazenar o pedido e deseja armazenar o estado do aplicativo em um serviço de contêiner.

Neste exercício, vais passar dados para um novo componente de configuração de pedido e aprender como armazenar o estado da aplicação num serviço com o escopo de OrderState.

Adicionar uma nova caixa de diálogo de configuração de ordem

  1. Pare o aplicativo se ele ainda estiver em execução.

  2. No Visual Studio Code, clique com o botão direito do mouse na pasta compartilhada e selecione Novo arquivo.

  3. Digite ConfigurePizzaDialog.razor como o nome do arquivo.

  4. Insira este código para a interface do usuário do novo componente de pedido:

    @inject HttpClient HttpClient
    
    <div class="dialog-container">
        <div class="dialog">
            <div class="dialog-title">
                <h2>@Pizza.Special.Name</h2>
                @Pizza.Special.Description
            </div>
            <form class="dialog-body">
                <div>
                    <label>Size:</label>
                    <input type="range" min="@Pizza.MinimumSize" max="@Pizza.MaximumSize" step="1" />
                    <span class="size-label">
                        @(Pizza.Size)" (£@(Pizza.GetFormattedTotalPrice()))
                    </span>
                </div>
            </form>
    
            <div class="dialog-buttons">
                <button class="btn btn-secondary mr-auto" >Cancel</button>
                <span class="mr-center">
                    Price: <span class="price">@(Pizza.GetFormattedTotalPrice())</span>
                </span>
                <button class="btn btn-success ml-auto" >Order ></button>
            </div>
        </div>
    </div>
    

    Este componente é uma caixa de diálogo que mostra a pizza especial selecionada e permite que o cliente selecione o tamanho da pizza.

    O componente precisa de uma pizza especial do componente da página de índice para acessar os valores de membro de uma pizza.

  5. Adicione o bloco Blazor @code para permitir que os parâmetros sejam passados para o componente:

    @code {
        [Parameter] public Pizza Pizza { get; set; }
    }
    

Peça uma pizza

Quando um cliente seleciona uma pizza, a caixa de diálogo deve permitir que ele altere o tamanho de sua pizza. Vamos aprimorar o controle index.razor para adicionar essa interatividade.

  1. No explorador de ficheiros, expanda Páginas e, em seguida, selecione Index.razor.

  2. Adicione este código no bloco @code sob a variável List<PizzaSpecial>:

    Pizza configuringPizza;
    bool showingConfigureDialog;
    
  3. Adicione este código para criar uma pizza sob o método OnInitializedAsync():

    void ShowConfigurePizzaDialog(PizzaSpecial special)
    {
        configuringPizza = new Pizza()
        {
            Special = special,
            SpecialId = special.Id,
            Size = Pizza.DefaultSize
        };
    
        showingConfigureDialog = true;
    }
    
  4. Permita que a página da Web chame o método ShowConfigurePizzaDialog do lado do servidor, ao permitir que os clientes selecionem a tag <li> de uma pizza. Substitua a linha <li> por este código:

    <li @onclick="@(() => ShowConfigurePizzaDialog(special))" style="background-image: url('@special.ImageUrl')">
    

    Quando um cliente seleciona uma pizza, o servidor executa o método ShowConfigurePizzaDialog que cria uma pizza com os dados especiais da pizza e define a variável showingConfigureDialog como true.

  5. A página precisa de uma maneira de exibir o novo componente ConfigurePizzaDialog. Adicione este código acima do bloco @code:

    @if (showingConfigureDialog)
    {
        <ConfigurePizzaDialog Pizza="configuringPizza" />
    }
    

    Todo o ficheiro index.razor deverá ficar semelhante a este exemplo:

    @page "/"
    @inject HttpClient HttpClient
    @inject NavigationManager NavigationManager
    
    <div class="main">
        <h1>Blazing Pizzas</h1>
        <ul class="pizza-cards">
        @if (specials != null)
        {
            @foreach (var special in specials)
            {
              <li @onclick="@(() => ShowConfigurePizzaDialog(special))" style="background-image: url('@special.ImageUrl')">
                <div class="pizza-info">
                <span class="title">@special.Name</span>
                @special.Description
                <span class="price">@special.GetFormattedBasePrice()</span>
                </div>
              </li>
            }
        }
        </ul>
    </div>
    
    @if (showingConfigureDialog)
    {
        <ConfigurePizzaDialog Pizza="configuringPizza" />
    }
    
    @code {
        List<PizzaSpecial> specials = new();
        Pizza configuringPizza;
        bool showingConfigureDialog;
    
        protected override async Task OnInitializedAsync()
        {
            specials = await HttpClient.GetFromJsonAsync<List<PizzaSpecial>>(NavigationManager.BaseUri + "specials");
        }
    
        void ShowConfigurePizzaDialog(PizzaSpecial special)
        {
            configuringPizza = new Pizza()
            {
                Special = special,
                SpecialId = special.Id,
                Size = Pizza.DefaultSize
            };
    
            showingConfigureDialog = true;
        }
    }
    
  6. Selecione F5 ou selecione Executar. Em seguida, selecione Iniciar depuração.

  7. Selecione uma pizza e veja a nova caixa de diálogo aparecer.

    Captura de tela mostrando a caixa de diálogo de pedido de pizza.

Lidar com o estado de um pedido

No momento, o aplicativo mostra a caixa de diálogo de configuração, mas não permite que você cancele ou passe a pedir a pizza. Para gerenciar o estado do pedido, adicione um novo serviço de contêiner de estado do pedido.

  1. Pare o aplicativo se ele ainda estiver em execução.

  2. Crie uma nova pasta na pasta BlazingPizza . Nomeie-o Serviços.

  3. Crie um novo arquivo na pasta Services. Nomeie-o OrderState.cs.

  4. Insira este código para a classe:

    namespace BlazingPizza.Services;
    
    public class OrderState
    {
        public bool ShowingConfigureDialog { get; private set; }
        public Pizza ConfiguringPizza { get; private set; }
        public Order Order { get; private set; } = new Order();
    
        public void ShowConfigurePizzaDialog(PizzaSpecial special)
        {
            ConfiguringPizza = new Pizza()
            {
                Special = special,
                SpecialId = special.Id,
                Size = Pizza.DefaultSize,
                Toppings = new List<PizzaTopping>(),
            };
    
            ShowingConfigureDialog = true;
        }
    
        public void CancelConfigurePizzaDialog()
        {
            ConfiguringPizza = null;
    
            ShowingConfigureDialog = false;
        }
    
        public void ConfirmConfigurePizzaDialog()
        {
            Order.Pizzas.Add(ConfiguringPizza);
            ConfiguringPizza = null;
    
            ShowingConfigureDialog = false;
        }
    }
    

    Você percebe que há um código atualmente no componente index.razor que podemos mover para a nova classe. O próximo passo é disponibilizar esse serviço no aplicativo.

  5. No explorador de ficheiros, selecione Program.cs.

  6. Na parte do arquivo com as linhas que começam com builder.Services., adicione esta linha:

    builder.Services.AddScoped<OrderState>();
    

    A partir do exercício anterior, adicionamos nosso contexto de banco de dados aqui. Este código adiciona o novo serviço OrderState. Com esse código em vigor, agora podemos usá-lo no componente index.razor.

  7. Adicione a seguinte using diretiva à parte superior do arquivo. Esta diretiva resolve quaisquer referências à OrderState classe:

    using BlazingPizza.Services;
    
  8. No explorador de ficheiros, expanda Páginas e, em seguida, selecione Index.razor.

  9. Na parte superior do ficheiro, em @inject NavigationManager NavigationManager, adicione este código:

    @using BlazingPizza.Services
    @inject OrderState OrderState
    
  10. Remova configuringPizza, showingConfigureDialoge ShowConfigurePizzaDialog() do bloco @code. Agora deve ser assim:

    @code {
        List<PizzaSpecial> specials = new List<PizzaSpecial>();
    
        protected override async Task OnInitializedAsync()
        {
            specials = await HttpClient.GetFromJsonAsync<List<PizzaSpecial>>(NavigationManager.BaseUri + "specials");
        }
    }
    

    Agora há erros sempre que o código faz referência aos elementos excluídos.

  11. Altere a chamada de ShowConfigurePizzaDialog(special)) para utilizar a versão OrderState:

    <li @onclick="@(() => OrderState.ShowConfigurePizzaDialog(special))" style="background-image: url('@special.ImageUrl')">
    
  12. Altere a referência ao booleano showingConfigureDialog:

    @if (OrderState.ShowingConfigureDialog)
    
  13. Altere o parâmetro usando configuringPizza:

    <ConfigurePizzaDialog Pizza="OrderState.ConfiguringPizza" />
    
  14. Selecione F5 ou selecione Executar. Em seguida, selecione Iniciar depuração.

    Se tudo estiver correto, você não deve ver nenhuma diferença. A caixa de diálogo é exibida como antes.

Cancelar e fazer pedidos de pizza

Você pode notar que há dois métodos na classe OrderState que ainda não são usados. Os CancelConfigurePizzaDialog métodos e ConfirmConfigurePizzaDialog fecham a caixa de diálogo e adicionam a pizza a um Order objeto assim que o cliente confirma o pedido. Vamos conectar esses métodos aos botões de diálogo de configuração.

  1. Pare o aplicativo se ele ainda estiver em execução.

  2. No explorador de ficheiros, expanda Partilhado. Em seguida, selecione ConfigurePizzaDialog.razor.

  3. No bloco @code, adicione dois novos parâmetros:

    @code {
       [Parameter] public Pizza Pizza { get; set; }
       [Parameter] public EventCallback OnCancel { get; set; }
       [Parameter] public EventCallback OnConfirm { get; set; }
    }
    `` `
    
    
  4. Agora, as diretivas @onclick podem ser adicionadas aos botões. Altere o código atual dos botões de diálogo para esta marcação:

    <div class="dialog-buttons">
        <button class="btn btn-secondary mr-auto" @onclick="OnCancel">Cancel</button>
        <span class="mr-center">
            Price: <span class="price">@(Pizza.GetFormattedTotalPrice())</span>
        </span>
        <button class="btn btn-success ml-auto" @onclick="OnConfirm">Order ></button>
    </div>
    
  5. O último passo é passar os métodos OrderState para cancelar e confirmar pedidos. No explorador de ficheiros, expanda Páginas. Em seguida, selecione Index.razor.

  6. Altere o código da chamada para o componente ConfigurePizzaDialog:

    <ConfigurePizzaDialog
        Pizza="OrderState.ConfiguringPizza"
        OnCancel="OrderState.CancelConfigurePizzaDialog"
        OnConfirm="OrderState.ConfirmConfigurePizzaDialog" />
    
  7. Selecione F5 ou selecione Executar. Em seguida, selecione Iniciar depuração.

O aplicativo agora deve permitir que os clientes cancelem ou adicionem uma pizza configurada a um pedido. Não temos como mostrar o pedido atual ou atualizar os preços quando o tamanho da pizza é alterado. Adicionaremos estes recursos no próximo exercício.