Nicolas Moyère
Utilisation de jQuery avec ASP.NET MVC
Développer une IHM à page unique avec ASP.NET MVC et jQuery
Par Nicolas Moyère publié le 30/06/2008 à 10:28, lu 1453 fois, 9 pages
 6 | Envoi du message
Après avoir saisi notre message, le clic sur le bouton Send doit bien sûr expédier le message, mais aussi restaurer l'affichage initial de la zone d'action.

Le HTML initial est dans Index.aspx qui contient aussi la liste des contacts et le menu.

Pour que la solution mise en place à l'étape précédente fonctionne, il faut que le contrôleur puisse demander uniquement le rendu HTML de la zone de lecture.Le contrôleur doit pouvoir choisir la sous partie d'une page ASPX qu'il souhaite afficher.

Il n'y a qu'un seul moyen pour une page ASPX de n'afficher qu'une de ses sous parties. C'est en surchargeant la méthode Render de la class Control.
Dans le cycle de vie d'une page ASPX, la méthode Render est exécutée quand tous les contrôles de la page sont initialisés.
En redéfinissant la méthode Render, nous pouvons chercher un contrôle particulier de la page et n'exécuter que le rendu de celui-ci.

Dans le cas d'Index.aspx, nous voulons afficher la page dans sa totalité au démarrage de l'application puis rafraîchir soit la zone de lecture soit la liste des contacts.
Le comportement de la méthode Render doit donc être paramétrable par le contrôleur.

Ceux qui utilisent déjà MVC ont remarqué que toutes les ASPX doivent hériter de la classe ViewPage. Néanmoins, cette classe n'est pas visible depuis les contrôleurs qui n'instancient que des ViewResult.
Par contre, ViewPage et ViewResult ont en commun le ViewData qui est le modèle de données pour l'affichage.
En simplifiant, lors de son exécution, un ViewResult instancie un ViewPage et lui passe le ViewData.
Les contrôleurs peuvent passer des paramètres à la méthode Render des pages en utilisant le ViewData. Dans notre cas, en ajoutant une clé dans ViewData, nous pouvons indiquer à la méthode Render d'afficher toute la page ou juste un contrôle particulier.

Pour clarifier tout çà, mettons-le en pratique.

Commençons par modifier Index.aspx en ajoutant un contrôle PlaceHolder autour de la zone de lecture (d'autres contrôles font tout aussi bien l'affaire mais PlaceHolder a l'avantage de ne pas modifier le HTML généré). Le code obtenu est le suivant :

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="Messenger.Views.Shared.Index"

%><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Messenger</title>

    <script src="../../jquery.js" type="text/javascript"></script>

    <script src="../../jquery.aspmvc.js" type="text/javascript"></script>

    <link href="../../style.css" type="text/css" rel="Stylesheet" />

</head>

<body>

    <div id="contacts">   

            <ul>

            <% foreach (Contact contact in ViewData.Model.Contacts)

               { %>

                <li><%= Html.ActionLink(contact.Name, "Read", "Home", new { id=contact.Email }) %></li>

            <% } %>

            </ul>

    </div>

 

    <div id="actions">

        <script type="text/javascript">

            $(document).ready(function() { $('#actions a').ajaxify(); });

        </script>

        <%= Html.ActionLink("Add Contact", "New", "Contacts") %>

        <%= Html.ActionLink("Send Msg", "New", "Messages", new { id = ViewData.Model.SelectedContact.Email })%>

    </div>

 

    <div id="panel">  

        <asp:PlaceHolder ID="ReadContactPanel" runat="server">

            <span>Name</span>

            <%= Html.AttributeEncode(ViewData.Model.SelectedContact.Name) %><br />

            <span>Email</span>

            <%= Html.AttributeEncode(ViewData.Model.SelectedContact.Email) %><br />

            <span>Photo</span>

            <img src="<%= Url.Action("Photo", "Contacts", new { id = ViewData.Model.SelectedContact.Email }) %>" /><br />

        </asp:PlaceHolder>

    </div>

</body>

</html>

Passons à la méthode Render en modifiant le code behind d'Index.aspx :

using System.Web.Mvc;

using System.Web.UI;

 

namespace Messenger.Views.Shared

{

    public partial class Index : ViewPage<IndexViewData>

    {

        /// <summary>

        /// The control that must be rendered as result of the AJAX request.

        /// </summary>

        public string RenderedControlId

        {

            get

            {

                object controlId = null;

                ViewData.TryGetValue("__RenderedControlId", out controlId);

                return (string)controlId;

            }

        }

 

        protected override void Render(HtmlTextWriter writer)

        {

            if (RenderedControlId == null)

            {

                // The complete view must be rendered.

                // We keep the default mechanism

                base.Render(writer);

            }

            else

            {

                // Only the given control is rendered

                Control control = FindControl(RenderedControlId);

                control.RenderControl(writer);

            }

        }

    }

}

Si ViewData contient la clé __RenderedControlId alors uniquement ce contrôle est affiché. Autrement, l'implémentation par défaut de Render génère toute la page.

Pour finir, nous pouvons coder l'action d'envoi du message dans MessagesController et demander uniquement la mise à jour du contrôle ReadContactPanel d'Index.aspx en modifiant le ViewData :

public ActionResult Send(string id)

{

    // On envoie le message au contact selectionné

    // puis on retourne au formulaire de départ.

 

    Console.WriteLine("Send msg to " + id + ":" + Request.Form["messagetext"]);

 

    DataContext context = new DataContext();

    IndexViewData model = new IndexViewData();

    model.SelectedContact = context.Contacts.Where(c => c.Email == id).Single();

    ViewData.Model = model;

 

    ViewData["__RenderedControlId"] = "ReadContactPanel";

    return View("Index");

}

Le modèle utilisé lors du rendu d'Index.aspx est incomplet. Il ne contient pas la liste de tous les contacts puisqu'il n'y en a pas besoin lors de l'affichage de la zone de lecture.

Reprenons les étapes effectuées lors de l'envoi d'un message :
  • À l'affichage de la zone de saisie, jQuery détourne la soumission du formulaire vers notre extension.
  • Lors du clic sur Send, notre extension jQuery utilise l'URL du formulaire pour appeler l'action Send de MessagesController.
  • Le contrôleur retourne une instance de ViewResult pour la page Index.aspx avec un ViewData contenant ReadContactPanel.
  • Le ViewResult appelle la méthode Render d'Index.aspx.
  • Trouvant ReadContactPanel dans ViewData, la méthode Render retourne uniquement le HTML de ce composant.
  • Enfin, l'extension jQuery remplace le contenu du div panel par le HTML généré.
Maintenant, nous savons mettre à jour une partie de l'interface à la fois, via une page complète ou un de ses contrôles.
 
» Démarrer une discussion