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
IQuestioneRepository
une signature de fonction pourFindByEvenementIdAndUserId
Snowfall.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
IQuestionService
une signature de fonction pourFindByEvenementIdAndUserId
Snowfall.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
ViewModel
QuestionsIndexViewModel
Snowfall.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
Index
Snowfall.Web.Mvc/Controllers/QuestionsController.cs[HttpGet] //GET /evenements/{evenementId}/questions
[Authorize]
public async Task<IActionResult> Index(int evenementId)
{
} - Créez une vue
Index
sous le dossierViews/Questions
qui accepte un leViewModel
créé 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
Index
du 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
New
afficher un lien vers la vueIndex
Snowfall.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.