29-8 Modification
La modification est très proche de la création, les principales différences étant:
- L'événement doit être chargé initialement
- Le formulaire doit être rempli avec les données de l'événement récupéré
Créer la page Edit
Créons la page Edit
permettant de modifier un événement.
- Sous le dossier
Web.Admin/Pages/Evenements
->Clic droit
->Add
->Blazor Component
- Choisir
Page
- Nommer la composante
Edit
Associer une route à la page
La route associée à la page sera: /evenements/{id:int}/edit
. On peut définir cette dernière à l'aide de @page
, tout en ajoutant le paramètre associé à bloc @code
.
@page "/evenements/{id:int}/edit"
<h1>Modifier l'événement</h1>
@code {
[Parameter]
public int Id { get; set; }
}
Ajouter un lien à partir de la page Show
vers la page Edit
Dans la page Show
, assurez-vous d'avoir un bouton "Modifier".
Dans Show
, faites ensuite en sorte que le bouton Modifier
pointe vers la page de modification:
<!-- ... -->
<div class="card-body">
<NavLink class="btn btn-primary" href="@($"/evenements/{Id}/edit")">Modifier</NavLink>
</div>
<!-- ... -->
Récupérer l'événement à modifier
Au chargement du composant, on doit récupérer le détail de l'événement à modifier via l'API (l'événement en tant que tel et la liste de villes).
Ajouter une variable pour contenir l'événement, le DTO de modification et la liste de villes
@code {
[Parameter]
public int Id { get; set; }
private EvenementDto? _evenementDto;
private ModifierEvenementDto _modifierEvenementDto = new();
private List<VilleDto>? _villes;
}
Injecter EvenementHttpClient
et VilleHttpClient
dans le composant
Pour obtenir l'événement et la liste de villes, il sera nécessaire de faire appel aux deux clients pour Evenement
et Ville
.
@page "/evenements/{id:int}/edit"
@using Snowfall.Application.Dtos.Evenements
@using Snowfall.Application.Dtos.Villes
@using Snowfall.Web.Admin.HttpClients
@inject EvenementHttpClient EvenementHttpClient
@inject VilleHttpClient VilleHttpClient
Récupérer l'événement et la liste de villes
Nous avons déjà les fonctions au niveaux des clients pour récupérer ces informations, il suffit d'appeler les fonctions respectives lors de l'initialisation du composant (OnInitializedAsync
).
Oops!, le code de cette portion a disparu, vous devrez la compléter vous-même!
@code {
[Parameter]
public int Id { get; set; }
private EvenementDto? evenementDto;
private List<VilleDto>? villes;
protected override async Task OnInitializedAsync()
{
// Oups...! Le code a disparu :(
// Récupérez l'événement et la liste de villes, puis assignez-les aux variables
}
}
Mapper le DTO d'événement vers le DTO de modification
Une fois que vous aurez récupéré le DTO de l'événement, il faut le "mapper" au DTO de modification.
Les étapes qui suivent sont importantes! Un moment d'égarement de ma part a mené à vous faire créer le fichier de configuration AutoMapper dans le projet Api
. Or, nous avons besoin de faire du mapping dans le projet Admin
. Nous allons donc déplacer le fichier de configuration AutoMapper, en plus d'installer AutoMapper dans le projet Application
afin qu'il soit accessible à toute l'application.
- Installer AutoMapper dans
Application
. Dans le projetApplication
,click droit
->Manage Nuget Packages
->RecherchezAutoMapper
->Procédez à l'ajout dans le projet - Dans Rider, déplacez le fichier
Snowfall.Web.Api/Configurations/AutoMapperConfig.cs
vers le dossierSnowfall.Application/Mappings
. Rider devrait faire le refactoring nécessaire. - Ajoutez un mappage de
EvenementDto
versModifierEvenementDto
Snowfall.Application/Mappings/AutoMapperConfig.cspublic AutoMapperConfig()
{
CreateMap<Evenement, EvenementDto>().ReverseMap();
CreateMap<CreerEvenementDto, Evenement>();
CreateMap<EvenementDto, ModifierEvenementDto>();
CreateMap<Ville, VilleDto>().ReverseMap();
} - Ajoutez AutoMapper aux services accessibles à l'injection de dépendance du projet Admin.
Snowfall.Web.Admin/Program.cs
// Injection de dépendances
builder.Services.EnregistrerServices();
builder.Services.AddAutoMapper(typeof(AutoMapperConfig)); - Injecter AutoMapper dans la page
Snowfall.Web.Admin/Pages/Evenements/Edit.razor
@page "/evenements/{id:int}/edit"
@using AutoMapper
@using Snowfall.Application.Dtos.Evenements
@using Snowfall.Application.Dtos.Villes
@using Snowfall.Web.Admin.HttpClients
@inject EvenementHttpClient EvenementHttpClient
@inject VilleHttpClient VilleHttpClient
@inject IMapper Mapper - Mapper
EvenementDto
versModifierEvenementDto
lors de l'initialisationSnowfall.Web.Admin/Pages/Evenements/Edit.razorprotected override async Task OnInitializedAsync()
{
(var status, _evenementDto) = await EvenementHttpClient.ObtenirEvenement(Id);
_villes = await VilleHttpClient.OtenirVilles();
Mapper.Map(_evenementDto, _modifierEvenementDto);
}
Afficher un message de chargement
Pendant le bref moment où _evenementDto
est null et donc qu'on attend une réponse de l'API, on peut afficher un message de chargement.
@page "/evenements/{id:int}/edit"
@using AutoMapper
@using Snowfall.Application.Dtos.Evenements
@using Snowfall.Application.Dtos.Villes
@using Snowfall.Web.Admin.HttpClients
@inject EvenementHttpClient EvenementHttpClient
@inject VilleHttpClient VilleHttpClient
@inject IMapper Mapper
<h1>Modifier l'événement</h1>
@if (_evenementDto == null)
{
<p>Chargement...</p>
}
else
{
}
Créer les fonctions GererSubmit
et Retour
Tout comme dans la création, on devra gérer l'action submit
du formulaire en plus d'avoir une option annuler pour revenir en arrière.
//...
async Task GererSubmit()
{
}
void Retour()
{
}
Afficher le formulaire
Pour cette portion, on peut, à quelques exceptions près, reprendre le formulaire de la page New
et le mettre dans la portion else
du bloc de chargement.
Quelques modifications doivent être faites au formulaire:
- La fonction
GererSubmit
n'existe pas, on devra la créer - La fonction
Retour
pour annuler n'existe pas non plus, elle sera à créer.
- Reprenez votre formulaire de la vue
New
et intégrez-le dans la vueEdit
Snowfall.Web.Admin/Pages/Evenements/Edit.razor@page "/evenements/{id:int}/edit"
@using AutoMapper
@using Snowfall.Application.Dtos.Evenements
@using Snowfall.Application.Dtos.Villes
@using Snowfall.Web.Admin.HttpClients
@inject EvenementHttpClient EvenementHttpClient
@inject VilleHttpClient VilleHttpClient
@inject IMapper Mapper
<h1>Modifier l'événement</h1>
@if (_evenementDto == null)
{
<p>Chargement...</p>
}
else
{
<div class="col-lg-6">
<EditForm Model="_creerEvenementDto" OnValidSubmit="GererSubmit">
<DataAnnotationsValidator />
<div class="form-floating mb-3">
<InputText id="nom" class="form-control" placeholder="Nom" @bind-Value="_creerEvenementDto.Nom"/>
<label asp-for="nom">Nom</label>
<ValidationMessage class="invalid-feedback" For="@(() => _creerEvenementDto.Nom)" />
</div>
<div class="form-floating mb-3">
<InputTextArea id="description" rows="5" class="form-control" placeholder="Description" @bind-Value="_creerEvenementDto.Description"/>
<label asp-for="description">Description</label>
<ValidationMessage class="invalid-feedback" For="@(() => _creerEvenementDto.Description)" />
</div>
<div class="form-floating mb-3">
<InputNumber id="capacite"
class="form-control"
placeholder="Capacité"
ParsingErrorMessage="La capacité doit être un nombre"
@bind-Value="_creerEvenementDto.Capacite"/>
<label asp-for="capacite">Capacité</label>
<ValidationMessage class="invalid-feedback" For="@(() => _creerEvenementDto.Capacite)" />
</div>
<div class="form-floating mb-3">
<InputDate id="date" class="form-control" placeholder="Date" @bind-Value="_creerEvenementDto.Date"/>
<label asp-for="date">Date</label>
<ValidationMessage class="invalid-feedback" For="@(() => _creerEvenementDto.Date)" />
</div>
<div class="form-floating mb-3">
<InputNumber id="prix" class="form-control" placeholder="Prix" @bind-Value="_creerEvenementDto.Prix"/>
<label asp-for="prix">Prix</label>
<ValidationMessage class="invalid-feedback" For="@(() => _creerEvenementDto.Prix)" />
</div>
<div class="form-floating mb-3">
<InputSelect id="ville" class="form-select" @bind-Value="_creerEvenementDto.VilleId">
<option value="">Veuillez faire une sélection</option>
@if (villes != null)
{
@foreach (var ville in villes)
{
<option value="@ville.Id">@ville.Nom, @ville.PaysIso</option>
}
}
</InputSelect>
<label for="ville">Ville</label>
<ValidationMessage class="invalid-feedback" For="@(() => _creerEvenementDto.VilleId)" />
</div>
<button type="submit" class="btn btn-primary">Sauvegarder</button>
<button class="btn btn-secondary" @onclick="Retour">Annuler</button>
</EditForm>
</div>
} - Important: Assurez-vous de remplacer les références à
_creerEvenementDto
par_modifierEvenementDto
!
Vous devriez maintenant être en mesure de naviguer vers la page de modification et voir les détails de l'événement dans le formulaire.
Bouton Annuler (fonction Retour
)
On peut compléter la fonction retour afin qu'elle redirige vers la page de détails (show).
@inject NavigationManager NavigationManager
//...
void Retour()
{
NavigationManager.NavigateTo($"/evenements/{Id}");
}
Sauvegarde de modifications
La dernière étape consiste à sauvegarder les modifications.
Créer la fonction ModifierEvenement
de EvenementClient
Pour communiquer avec l'API, notre façade est EvenementHttpClient
. On peut donc créer une fonction de modification qui fera une requête PATCH
à l'API et retourne true
ou false
selon le résultat.
Malheureusement, le code complet n'est pas disponible. Vous avez cependant la signature. Inspirez-vous de la fonction pour la création création, il y a des ressemblances!
/// <summary>
/// Permets de modifier un événement
/// </summary>
/// <param name="id">L'identifiant de l'événement à modifier</param>
/// <param name="modifierEvenementDto">L'événement à modifier</param>
/// <returns>Bool représentant le succès ou l'échec de la requête</returns>
public async Task<bool> ModifierEvenement(int id, ModifierEvenementDto modifierEvenementDto)
{
// Oups... à compléter!
}
Appeler le client lors de la sauvegarde
Finalement, lorsqu'on soumet le formulaire, on appelle le client Http
et selon le résultat, on affiche un message.
//...
async Task GererSubmit()
{
bool success = await EvenementHttpClient.ModifierEvenement(Id, _modifierEvenementDto);
// Gérez le cas ou success est true et success est false!
// Si true, vous voudrez faire afficher un Toast par exemple, et rediriger l'utilisateur
// Si false, vous voudrez faire afficher un message d'erreur, via un Toast ou autre mécanisme
}
//...
N'oubliez pas de gérer les cas d'erreur, comme mentionné dans le commentaire!
Test
Vous devriez maintenant être en mesure de modifier un événement!