19-8 Afficher la liste de questions
Imaginons qu'il est possible pour un utilisateur de voir la liste de questions qu'il a déjà posée pour un événement afin de modifier ou supprimer une question.
Nous allons afficher la liste de questions dans la vue New. Alors, quand un utilisateur cliquera sur poser une question, il verra par la même occasion ses questions posées précédemment pour l'événement en question.
Pour cela, il nous faut des fonctions de Repository et de Service!
Ajouter FindByEvenementIdAndUserId dans QuestionRepository
- Ajoutez à l'interface
IQuestioneRepositoryune signature de fonction pourFindByEvenementIdAndUserIdSnowfall.Data/Repositories/IQuestionRepository.cspublic interface IQuestionRepository
{
Task<List<Question>> FindByEvenementIdAndUserId(int evenementId, string userId);
Task<Question> Create(Question question);
} - Dans
QuestionRepository, vous pourrez utiliser l'aide contextuelle (à la ligne du nom de la classe qui sera surligné en rouge) pour faireImplement missing members. Cela ajoutera la définition de la fonction:Snowfall.Data/Repositories/QuestionRepository.cspublic async Task<List<Question>> FindByEvenementIdAndUserId(int evenementId, string userId)
{
throw new NotImplementedException();
} - On fait une requête pour filtrer les questions et les classer par date de création descendante.
Snowfall.Data/Repositories/QuestionRepository.cs
public async Task<List<Question>> FindByEvenementIdAndUserId(int evenementId, string userId)
{
string sql = @"
SELECT * FROM questions q
WHERE q.evenement_id = @EvenementId
AND q.utilisateur_id = @UserId
ORDER BY created_at DESC
";
using (IDbConnection connection = _dbContext.CreateConnection())
{
var param = new
{
EvenementId = evenementId,
UserId = userId
};
IEnumerable<Question> questions = await connection.QueryAsync<Question>(sql, param);
return questions.ToList();
}
}
Ajouter FindByEvenementIdAndUserId dans QuestionService
- Ajoutez à l'interface
IQuestionServiceune signature de fonction pourFindByEvenementIdAndUserIdSnowfall.Application/Services/IQuestionService.cspublic interface IQuestionService
{
Task<List<Question>> FindByEvenementIdAndUserId(int evenementId, string userId);
Task<Question> Create(Question question);
} - Dans
QuestionService, vous pourrez utiliser l'aide contextuelle (à la ligne du nom de la classe qui sera surligné en rouge) pour faireImplement missing members. Cela ajoutera la définition de la fonction:Snowfall.Application/Services/QuestionService.cspublic async Task<List<Question>> FindByEvenementIdAndUserId(int evenementId, string userId)
{
throw new NotImplementedException();
} - Finalement, on appelle le repository à partir du service.
Snowfall.Application/Services/QuestionService.cs
public async Task<List<Question>> FindByEvenementIdAndUserId(int evenementId, string userId)
{
return await _questionRepository.FindByEvenementIdAndUserId(evenementId, userId);
}
Créer une action Index pour afficher les questions existantes
Pour afficher les questions existantes, nous créerons une vue et une action Index. De plus, créons un ViewModel QuestionsIndexViewModel qui contiendra l'événement et la liste de questions.
- Créez le
ViewModelQuestionsIndexViewModelSnowfall.Web.Mvc/Models/Questions/QuestionsIndexViewModel.cspublic class QuestionsIndexViewModel
{
public required Evenement Evenement { get; set; }
public required List<Question> Questions { get; set; }
} - Créez la signature de l'action
IndexSnowfall.Web.Mvc/Controllers/QuestionsController.cs[HttpGet] //GET /evenements/{evenementId}/questions
[Authorize]
public async Task<IActionResult> Index(int evenementId)
{
} - Créez une vue
Indexsous le dossierViews/Questionsqui accepte un leViewModelcréé précédemment.Snowfall.Web.Mvc/Views/Questions/Index.cshtml@model Snowfall.Web.Mvc.Models.Questions.QuestionsIndexViewModel
@{
ViewBag.Title = "Vos questions";
}
<h2>Vos questions pour l'évémement @Model.Evenement.Nom</h2> - Obtenir l'événement dans l'action
Indexdu contrôleurSnowfall.Web.Mvc/Controllers/QuestionsController.cspublic async Task<IActionResult> Index(int evenementId)
{
var evenement = await _evenementService.FindById(evenementId);
if (evenement == null) return NotFound();
} - Obtenir la liste de questions de l'utilisateur
public async Task<IActionResult> Index(int evenementId)
{
var evenement = await _evenementService.FindById(evenementId);
if (evenement == null) return NotFound();
var questions = await _questionService.FindByEvenementIdAndUserId(
evenementId,
User.Identity!.Id());
} - Retourner le ViewModel à la vue.
Snowfall.Web.Mvc/Controllers/QuestionsController.cs
public async Task<IActionResult> Index(int evenementId)
{
var evenement = await _evenementService.FindById(evenementId);
if (evenement == null) return NotFound();
var questions = await _questionService.FindByEvenementIdAndUserId(
evenementId,
User.Identity!.Id());
var viewModel = new QuestionsIndexViewModel()
{
Evenement = evenement,
Questions = questions
};
return View(viewModel);
}
Faire un lien vers la liste des questions de l'utilisateur
OK, on a une ébauche de vue et une action de contrôleur pour afficher une liste de questions pour un événement en particulier!
Sur la vue New on affichera un lien permettant à l'utilisateur d'afficher sa liste de questions.
- Dans la vue
Newafficher un lien vers la vueIndexSnowfall.Web.Mvc/Views/Questions/New.cshtml<div class="row">
<div class="col-md-6 offset-md-3">
<h1>@ViewBag.Title</h1>
<div class="mb-3">
Déjà posé une question?
<a asp-controller="Questions"
asp-action="Index"
asp-route-evenementId="@Model.EvenementId">Voir vos questions pour cet événement</a>.
</div>
<!-- ... -->
Maintenant, testez votre application pour valider que la séquence fonctionne. Aucune question ne sera affichée dans la vue, mais la séquence de navigation devrait fonctionner.

Afficher la liste de questions
Finalement, affichez la liste de questions dans la vue!
<!-- ... -->
<h2>Vos questions pour l'évémement @Model.Evenement.Nom</h2>
<div class="row">
<div class="col-12 col-lg-6">
@foreach (Question question in Model.Questions)
{
<div class="card mb-3">
<div class="card-body">
<p class="card-text" style="white-space: pre-line">@question.Contenu</p>
</div>
</div>
}
</div>
</div>
Ce qui devrait vous donner quelque chose comme ceci pour un événement pour lequel vous avez des questions.


À noter qu'il serait préférable de créer une vue partielle pour chaque élément de la liste, mais par souci de limiter les étapes dans ce niveau, les éléments sont directement dans la vue index.