Exercícios: compartilhar dados em aplicativos Blazor

Concluído

Agora que seu aplicativo está conectado a um banco de dados, é hora de adicionar a capacidade de pedir e configurar a pizza de um cliente.

A Blazing Pizza quer que você permita aos clientes a capacidade de alterar o tamanho das pizzas especiais. Você precisa armazenar o pedido, e optou por armazenar o estado do aplicativo em um serviço de contêiner.

Neste exercício, você transmitirá dados para um novo componente de configuração de pedido e verá como armazenar o estado do aplicativo em um serviço com escopo OrderState.

Adicionar uma caixa de diálogo de configuração de novo pedido

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

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

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

  4. Insira este código para a interface do usuário do componente de novo 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>
    

    Esse 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 de página de índice para acessar os valores de membro de uma pizza.

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

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

Pedir uma pizza

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

  1. No explorador de arquivos, expanda Páginas e selecione Index.razor.

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

        Pizza configuringPizza;
        bool showingConfigureDialog;
    
  3. Adicione o 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, permitindo que os clientes selecionem uma tag <li> de 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 da pizza especial 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" />
    }
    

    Agora, o arquivo index.razor deve ser parecido com 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 Executar. Selecione Iniciar Depuração.

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

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

Manipular 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 já faça o pedido da pizza. Para gerenciar o estado do pedido, você adicionará um serviço de contêiner de estado de novo pedido.

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

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

  3. Crie um novo arquivo na pasta Serviços. Nomeie-o como 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ê verá que há código atualmente no componente index.razor que podemos mover para a nova classe. A próxima etapa é disponibilizar esse serviço no aplicativo.

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

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

    builder.Services.AddScoped<OrderState>();
    

    No exercício anterior, adicionamos nosso contexto de banco de dados aqui. Esse código adiciona o novo serviço OrderState. Com o código aplicado, agora podemos usá-lo no componente index.razor.

  7. Adicione a seguinte diretiva using ao topo do arquivo para resolver a classe OrderState:

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

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

    @using BlazingPizza.Services
    @inject OrderState OrderState
    
  10. Remova configuringPizza, showingConfigureDialog e ShowConfigurePizzaDialog() do @code bloco. Agora, ele 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 onde todo o código faz referência ao que foi excluído.

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

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

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

    <ConfigurePizzaDialog Pizza="OrderState.ConfiguringPizza" />
    
  14. Selecione F5 ou Executar. Selecione Iniciar Depuração.

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

Cancelar e fazer pedidos de pizza

Talvez você tenha observado na classe OrderState dois métodos que ainda não foram usados. Os métodos CancelConfigurePizzaDialog e ConfirmConfigurePizzaDialog fecharão a caixa de diálogo e adicionarão a pizza a um objeto Order se o cliente tiver confirmado o pedido. Vamos conectar esses métodos aos botões da caixa de diálogo de configuração.

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

  2. No explorador de arquivos, expanda Compartilhado. 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, os botões podem ter diretivas @onclick adicionadas. Altere o código atual dos botões da caixa 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. A última etapa é transmitir os métodos OrderState para cancelar e confirmar pedidos. No explorador de arquivos, expanda Páginas. Depois, 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 Executar. Selecione Iniciar Depuração.

Agora, o aplicativo 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 cliente muda o tamanho da pizza. Adicionaremos esses recursos no próximo exercício.