---
sidebar_position: 5
title: Création d'une popup de confirmation
---

## Création d'une popup de confirmation

Afin de créer notre popup, créer le dossier `Modals` à la racine du site.

Créer le composant razor `DeleteConfirmation.razor` et sa classe `DeleteConfirmation.razor.cs`.

```cshtml title="Modals/DeleteConfirmation.razor"
<div class="simple-form">
    
    <p>
        Are you sure you want to delete @item.DisplayName ?
    </p>

    <button @onclick="ConfirmDelete" class="btn btn-primary">Delete</button>

    <button @onclick="Cancel" class="btn btn-secondary">Cancel</button>
</div>
```

```csharp title="Modals/DeleteConfirmation.razor.cs"
public partial class DeleteConfirmation
{
	[CascadingParameter]
	public BlazoredModalInstance ModalInstance { get; set; }

	[Inject]
	public IDataService DataService { get; set; }

	[Parameter]
	public int Id { get; set; }

	private Item item = new Item();

	protected override async Task OnInitializedAsync()
	{
		// Get the item
		item = await DataService.GetById(Id);
	}

	void ConfirmDelete()
	{
		ModalInstance.CloseAsync(ModalResult.Ok(true));
	}

	void Cancel()
	{
		ModalInstance.CancelAsync();
	}
}
```

Ouvrer le fichier `Pages/List.razor.cs` et ajouter les modifications :

```csharp title="Pages/List.razor.cs"
...

[Inject]
public NavigationManager NavigationManager { get; set; }

[CascadingParameter] 
public IModalService Modal { get; set; }

...

private async void OnDelete(int id)
{
	var parameters = new ModalParameters();
	parameters.Add(nameof(Item.Id), id);

	var modal = Modal.Show<DeleteConfirmation>("Delete Confirmation", parameters);
	var result = await modal.Result;

	if (result.Cancelled)
	{
		return;
	}

	await DataService.Delete(id);

	// Reload the page
	NavigationManager.NavigateTo("list", true);
}

```

## Notion : Paramètres en cascade

### Composant `CascadingValue`

Un composant ancêtre fournit une valeur en cascade à l’aide du composant Blazor de l’infrastructure `CascadingValue`, qui encapsule un sous-arbre d’une hiérarchie de composants et fournit une valeur unique à tous les composants de sa sous-arborescence.

L’exemple suivant montre le déroulement des informations de thème dans la hiérarchie des composants d’un composant de disposition pour fournir une classe de style CSS aux boutons des composants enfants.

La classe C# `ThemeInfo` suivante est placée dans un dossier nommé `UIThemeClasses` et spécifie les informations de thème.

:::info

Pour les exemples de cette section, l’espace de noms de l’application est BlazorSample . Quand vous expérimentez le code dans votre propre exemple d’application, remplacez l’espace de noms de l’application par l’espace de noms de votre application d’exemple.

:::

```csharp title="UIThemeClasses/ThemeInfo.cs"
namespace BlazorSample.UIThemeClasses
{
    public class ThemeInfo
    {
        public string? ButtonClass { get; set; }
    }
}
```

Le layout suivant spécifie les informations de thème ( `ThemeInfo` ) comme valeur en cascade pour tous les composants qui composent le corps du layout de la propriété `Body`. 
La valeur `ButtonClass` est affectée à `btn-success`, qui est un style de bouton de démarrage. Tout composant descendant dans la hiérarchie des composants peut utiliser la propriété `ButtonClass` à travers la valeur `ThemeInfo` en cascade.

```cshtml title="Shared/MainLayout.razor"
@inherits LayoutComponentBase
@using BlazorSample.UIThemeClasses

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <div class="main">
        <CascadingValue Value="theme">
            <div class="content px-4">
                @Body
            </div>
        </CascadingValue>
    </div>
</div>

@code {
    private ThemeInfo theme = new() { ButtonClass = "btn-success" };
}
```

### Attribut `[CascadingParameter]`

Pour utiliser des valeurs en cascade, les composants descendants déclarent des paramètres en cascade à l’aide de l'attribut `[CascadingParameter]`. 
Les valeurs en cascade sont liées aux paramètres en cascade par type.

Le composant suivant lie la valeur `ThemeInfo` en cascade à un paramètre en cascade, en utilisant éventuellement le même nom `ThemeInfo`. Le paramètre est utilisé pour définir la classe CSS pour le bouton `Increment Counter (Themed)`.

```cshtml title="Pages/ThemedCounter.razor"
@page "/themed-counter"
@using BlazorSample.UIThemeClasses

<h1>Themed Counter</h1>

<p>Current count: @currentCount</p>

<p>
    <button class="btn" @onclick="IncrementCount">
        Increment Counter (Unthemed)
    </button>
</p>

<p>
    <button 
        class="btn @(ThemeInfo is not null ? ThemeInfo.ButtonClass : string.Empty)" 
        @onclick="IncrementCount">
        Increment Counter (Themed)
    </button>
</p>

@code {
    private int currentCount = 0;

    [CascadingParameter]
    protected ThemeInfo? ThemeInfo { get; set; }

    private void IncrementCount()
    {
        currentCount++;
    }
}
```

### Plusieurs valeurs en cascade 

Pour mettre en cascade plusieurs valeurs du même type dans la même sous-arborescence, fournissez une chaîne unique `Name` à chaque composant `CascadingValue` et à ses attributs `[CascadingParameter]` correspondants.

Dans l’exemple suivant, deux composants `CascadingValue` montent en cascade différentes instances de `CascadingType` :

```cshtml
<CascadingValue Value="@parentCascadeParameter1" Name="CascadeParam1">
    <CascadingValue Value="@ParentCascadeParameter2" Name="CascadeParam2">
        ...
    </CascadingValue>
</CascadingValue>

@code {
    private CascadingType parentCascadeParameter1;

    [Parameter]
    public CascadingType ParentCascadeParameter2 { get; set; }

    ...
}
```

Dans un composant descendant, les paramètres en cascade reçoivent leurs valeurs en cascade du composant ancêtre avec l'attribut `Name` :

```cshtml
...

@code {
    [CascadingParameter(Name = "CascadeParam1")]
    protected CascadingType ChildCascadeParameter1 { get; set; }

    [CascadingParameter(Name = "CascadeParam2")]
    protected CascadingType ChildCascadeParameter2 { get; set; }
}
```

### Transmettre des données dans une hiérarchie de composants

Les paramètres en cascade permettent également aux composants de transmettre des données à travers une hiérarchie de composants. 
Prenons l’exemple de jeu d’onglets de l’interface utilisateur suivant, où un composant de jeu d’onglets gère une série d’onglets individuels.

Créez une interface `ITab` que les onglets implémentent dans un dossier nommé `UIInterfaces`.

```csharp title="UIInterfaces/ITab.cs"
using Microsoft.AspNetCore.Components;

namespace BlazorSample.UIInterfaces
{
    public interface ITab
    {
        RenderFragment ChildContent { get; }
    }
}
```

Le composant `TabSet` suivant gère un ensemble d’onglets. Les composants du jeu d’onglets `Tab`, qui sont créés plus loin dans cette section, fournissent les éléments de liste ( `<li>...</li>` ) de la liste ( `<ul>...</ul>` ).

Les composants enfants `Tab` ne sont pas explicitement passés comme paramètres à `TabSet`. 
Au lieu de cela, les composants enfants `Tab` font partie du contenu enfant de `TabSet`. 
Toutefois, le `TabSet` nécessite toujours une référence `Tab` à chaque composant pour pouvoir afficher les en-têtes et l’onglet actif. 
Pour activer cette coordination sans nécessiter de code supplémentaire, le composant `TabSet` peut se présenter comme une valeur en cascade qui est ensuite récupérée par les composants `Tab` descendants.

```cshtml title="Shared/TabSet.razor"
@using BlazorSample.UIInterfaces

<!-- Display the tab headers -->

<CascadingValue Value=this>
    <ul class="nav nav-tabs">
        @ChildContent
    </ul>
</CascadingValue>

<!-- Display body for only the active tab -->

<div class="nav-tabs-body p-4">
    @ActiveTab?.ChildContent
</div>

@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }

    public ITab ActiveTab { get; private set; }

    public void AddTab(ITab tab)
    {
        if (ActiveTab == null)
        {
            SetActiveTab(tab);
        }
    }

    public void SetActiveTab(ITab tab)
    {
        if (ActiveTab != tab)
        {
            ActiveTab = tab;
            StateHasChanged();
        }
    }
}
```

Les composants `Tab` descendants capturent le conteneur `TabSet` sous la forme d’un paramètre en cascade. Les composants `Tab` s’ajoutent à la `TabSet` coordonnée et pour définir l’onglet actif.

```cshtml title="Shared/Tab.razor"
@using BlazorSample.UIInterfaces
@implements ITab

<li>
    <a @onclick="ActivateTab" class="nav-link @TitleCssClass" role="button">
        @Title
    </a>
</li>

@code {
    [CascadingParameter]
    public TabSet ContainerTabSet { get; set; }

    [Parameter]
    public string Title { get; set; }

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    private string TitleCssClass => 
        ContainerTabSet.ActiveTab == this ? "active" : null;

    protected override void OnInitialized()
    {
        ContainerTabSet.AddTab(this);
    }

    private void ActivateTab()
    {
        ContainerTabSet.SetActiveTab(this);
    }
}
```

Le composant `ExampleTabSet` suivant utilise le composant `TabSet`, qui contient trois composants `Tab`.

```cshtml title="Pages/ExampleTabSet.razor"
@page "/example-tab-set"

<TabSet>
    <Tab Title="First tab">
        <h4>Greetings from the first tab!</h4>

        <label>
            <input type="checkbox" @bind="showThirdTab" />
            Toggle third tab
        </label>
    </Tab>

    <Tab Title="Second tab">
        <h4>Hello from the second tab!</h4>
    </Tab>

    @if (showThirdTab)
    {
        <Tab Title="Third tab">
            <h4>Welcome to the disappearing third tab!</h4>
            <p>Toggle this tab from the first tab.</p>
        </Tab>
    }
</TabSet>

@code {
    private bool showThirdTab;
}
```
