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
 7 | Ajout d'un contact
La première phase de l'ajout d'un contact est identique à celle de l'envoi d'un message. La zone d'action est rafraîchie avec une nouvelle page contenant les zones de saisie pour le nouveau contact.

Nous allons sauter cette étape et passer directement à la validation de l'ajout. Nous avons un nouveau problème. Deux zones sont modifiées : la liste des contacts et la zone de lecture doivent afficher le nouveau contact.

Actuellement, l'extension jQuery insère la totalité de la réponse du contrôleur dans un seul noeud du document HTML.
Pour le nouveau besoin, l'extension doit considérer que la réponse contient plusieurs blocs de HTML distincts et qu'elle doit les placer à des endroits différents.

Jusqu'à présent, les réponses ne contenaient que du HTML. Dorénavant, les réponses utilisent le format suivant :
  • Un sélecteur jQuery pour indiquer quelle partie de la page doit être actualisée.
  • Suivi d'un &&&&.
  • Un bloc de HTML à placer sur les éléments sélectionnés par jQuery.
  • Suivi d'un autre &&&&.
  • Ainsi de suite tant qu'il y a des zones à mettre à jour.
Ce format est simple tout en restant sûr aussi longtemps que &&&& n'apparaît pas dans le HTML. C'est normalement le cas si Html.Encode et Html.AttributeEncode qui transforment & en & sont utilisées correctement.

Côté Javascript, la fonction successFunction tronçonne la réponse puis applique chaque bloc un à un :

var successFunction = function (data, textStatus) {

    // The data is "selector1&&&&HTML1&&&&selector2&&&&HTML2...."

    var views = data.toString().split('&&&&');

 

    for (var i=0; i<views.length; i+=2)

    {

        jQuery(views[i]).html(views[i+1]);

    }

};

Maintenant, il faut que la réponse générée par le serveur ait le format voulu. Comme nous l'avons vu avec les photos, c'est la responsabilité de la classe ActionResult.

Nous en créons une nouvelle implémentation appelée AjaxViewResult :

using System.Collections.Generic;

using System.Web;

using System.Web.Mvc;

 

namespace Messenger

{

    public class AjaxViewResult : ActionResult

    {

        public IList<KeyValuePair<string, ActionResult>> NestedActionResults { get; set; }

 

        public override void ExecuteResult(ControllerContext context)

        {

            HttpResponseBase response = context.HttpContext.Response;

            foreach (KeyValuePair<string, ActionResult> nestedActionResult in NestedActionResults)

            {

                string selector = nestedActionResult.Key;

                ActionResult actionResult = nestedActionResult.Value;

 

                response.Write(selector);

                response.Write("&&&&");

                actionResult.ExecuteResult(context);

                response.Write("&&&&");

            }

        }

    }

}

AjaxViewResult contient la liste de toutes les zones à actualiser avec pour chaque zone, son identifiant et son HTML via un ActionResult.
La méthode ExecuteResult ne fait que concaténer toutes les zones dans la réponse en utilisant &&&& comme séparateur.

AjaxViewResult peut être améliorée en ajoutant les deux méthodes suivantes pour joindre des zones à partir d'une page complète ou d'un sous contrôle :

public AjaxViewResult Add(string selector, ViewResult viewResult, string controlId)

{

    object model = viewResult.ViewData.Model;

    if ((model != null) || (controlId != null))

    {

        ViewDataDictionary viewData = new ViewDataDictionary(viewResult.ViewData);

        if (model != null)

        {

            viewData.Model = model;

        }

        if (controlId != null)

        {

            viewData["__RenderedControlId"] = controlId;

        }

        viewResult.ViewData = viewData;

    }

    return Add(selector, viewResult);

}

 

public AjaxViewResult Add(string selector, ActionResult actionResult)

{

    if (NestedActionResults == null)

    {

        NestedActionResults = new List<KeyValuePair<string, ActionResult>>();

    }

    NestedActionResults.Add(new KeyValuePair<string, ActionResult>(selector, actionResult));

 

    return this;

}

À partir de là, le code de ContactsController devient le suivant :

public ActionResult Add()

{

    // On valide la création en reconstituant

    // le contact via les infos du formulaire.

    // On met à jour la datasource puis la

    // liste des contacts et le contact sélectionné.

    DataContext context = new DataContext();

 

    Contact contact = new Contact();

    contact.Name = Request.Form["name"];

    contact.Email = Request.Form["email"];

    contact.Photo = context.Contacts.First().Photo;

 

    context.AddContact(contact);

 

    IndexViewData model = new IndexViewData();

    model.Contacts = context.Contacts.ToList();

    model.SelectedContact = contact;

    ViewData.Model = model;

 

    return new AjaxViewResult().Add("#panel", View("Index"), "ReadContactPanel")

        .Add("#contacts", View("Index"), "ContactsPanel");

}

Les deux dernières lignes permettent la mise à jour de la zone de lecture et de la liste des contacts simultanément.

Nous venons de compléter notre dernier cas d'utilisation.
 
» Démarrer une discussion