Nouvelles Chroniques d'Amethyste

Penser au Sens, pas au Verbe

Faire des appels Ajax

Poster un commentaire

On a très souvent besoin de faire des appels Ajax dans une appli. Voici 5 méthodes pour y parvenir:

  1. XmlHtmlRequest
  2. @Ajax (Razor)
  3. JSon
  4. Angular
  5. Fetch

 

Nous allons traiter un exemple de chaque

Projet de démo

Le projet se trouve sur mon espace Github:

https://github.com/DeLeneMirouze/demoajax

Le projet s’appuie sur AdventureWorks. Vous devrez définir les informations d’accès à la base de données dans le fichier de configuration.

Notez pour finir que j’ai installé deux Nugets:

Install-Package jQuery
Install-Package Microsoft.jQuery.Unobtrusive.Ajax

Ainsi que les scripts correspondants dans le projet.

Un objet xhr

C’est la méthode historique et ce n’est pas la plus facile et je ne pense pas que vous l’utiliserez souvent. Mais toutes autres méthodes d’appels Ajax est rien de plus qu’une façade à un objet XmlHtmlRequest.

Xhr est une idée en provenance de Microsoft, adoptée et améliorée par tout le monde au point d’être maintenant un standard:

https://xhr.spec.whatwg.org/

Le formulaire de démo est Xhr.cshtml. Visuellement il affiche une liste de personnes avec la possibilité d’afficher un détail:

2017-01-16_10-33-47

 

La logique est posée dans le fichier xhrTools.js. Elle consiste pour sa partie publique en une méthode appelée getJSON qui fera les appels Ajax:

<a onclick="getJSON({ id: @personne.BusinessEntityID})">Détails</a>

La méthode attend un objet anonyme portant les paramètres nécessaires. c’est juste l’id de la personne concernée.  Voyons le JavaScript.

 

var getJSON = function (params) {
      sendAjax({
      type: 'get',
      url: window.location.origin + "/api/personne/" + params.id,
      beforeSend: function (xhr) {
      xhr.setRequestHeader('Accept', 'application/json, text/javascript');
   },
   success:OnSuccess,
   error: params.error,
   complete: params.complete,
   cache: true
   });
};
 
function OnSuccess(response) {
   var personne = JSON.parse(response);
 
   var html = "Id: " + personne.BusinessEntityID + "<br/>";
   html += "FirstName: " + personne.FirstName + "<br/>";
   html += "LastName: " + personne.LastName + "<br/>";
 
   var details = document.getElementById("details")
   details.innerHTML = html;
}

SendAjax est la méthode qui fait le boulot, je la détaillerai plus tard. On doit lui passer en paramètres un objet anonyme avec les informations utiles pour procéder à l’appel Ajax.

Il y a donc le verbe (GET) et l’url de la Web Api appelée de façon asynchrone. La méthode importante est success qui pointe vers OnSuccess. c’est la méthode de rappel qui va réagir au retour de la requête Ajax. Dans la vie réelle on mettrait aussi en place une méthode OnError.

Le point intéressant à remarquer est que le code réclame un objet JSON. Il est ensuite nécessaire de le désérialiser en un objet JavaScript ce qui est fait avec la méthode JSON.Parse().

 

La méthode sendAjax est définie ainsi:


var sendAjax = function (params) {
      var xhr = new XMLHttpRequest(),
      url = params.cache ? params.url + '?' + new Date().getTime() : params.url,
      timer = setTimeout(function () {
         xhr.abort();
         params.error && params.error();
         params.complete && params.complete();
      }, MAX_XHR_WAITING_TIME);

      xhr.open(params.type, url);
      xhr.onreadystatechange = function () {
         if (xhr.readyState === 4) {
            clearTimeout(timer);
            if (xhr.status === 200 || xhr.status === 0) {
               params.success && params.success(xhr.responseText);
               params.complete && params.complete();
            } else {
               params.error && params.error(xhr.responseText);
               params.complete && params.complete();
           }
      }
   };
   
   params.beforeSend && params.beforeSend(xhr);
   xhr.send();
};

 

Sans surprises on commence par instancier un objet XMLHttpRequest. On mets également en œuvre un trigger pour se déclencher si l’appel est trop long.

Si une méthode beforeSend() est définie on la lance, dans notre exemple elle paramétrise la requête pour récupérer un JSON. On termine en lançant la requête avec la méthode send().

 

Comme vous le voyez le code n’est pas spécialement simple et nécessite pas mal de travail. D’où l’intérêt de se simplifier la vie avec divers Framework.

Razor @Ajax

Il s’agit d’un helper Razor qui évite de connaître par cœur la syntaxe JQuery.

Le formulaire de démonstration est AHelper.cshtml. Il affiche une liste d’utilisateurs:

2017-01-13_16-33-07

Un clic sur le lien « Détails » ouvre une popup de confirmation:

2017-01-13_16-34-50

Et remplace le lien par ceci:

2017-01-13_16-35-36

Comment une telle chose est possible?

Je vous laisserai lire le contenu de AHelper.cshtml en détail, mais la partie significative est celle-ci:


<div id="@personne.BusinessEntityID">
   @Ajax.ActionLink("Détails", "Details",
      new { id = @personne.BusinessEntityID },
      new AjaxOptions()
      {
         HttpMethod = "GET",
         InsertionMode = InsertionMode.Replace,
         UpdateTargetId = @personne.BusinessEntityID.ToString(),
         Confirm ="Voulez-vous voir les détails?"
      })
</div>

Le helper reprend la sémantique Razor à laquelle on est habitué: @Ajax.

On s’intéresse à la méthode ActionLink qui génère une ancre HTML. L’action est ‘Details’, on peut aussi préciser un contrôleur.

Je passe ensuite des informations pour le routage. Mon action attend notamment comme paramètre l’id de la personne sélectionnée.

Pour finir on construit un AjaxOptions. C’est le paramètre qui est nécessaire pour construire la requête Ajax.

Dans notre cas c’est très simple. Le verbe HTTP est GET. Confirm permet de construire la boîte de dialogue, si on ne met rien elle ne s’affiche pas.

InsertionMode indique de quelle façon on va a insérer le résultat de la requête de détail. Dans l’exemple on va remplacer par l’HTML retourné la DIV dont l’id est donné par UpdateTargetId.

 

Le contrôleur est le suivant:

public ActionResult Details(int id)
{
   Personne personne = _repository.Details(id);
 
   return PartialView("detail", personne);
}

 

@Ajax propose d’autres possibilités, le plus simple est de lire la documentation ou de regarder le tutoriel proposé dans la bibliographie.

JQuery

Je ne suis pas parvenu à faire fonctionner @Ajax dans certains scénarios, en particulier l’appel d’une web api. C’est pas forcément gênant, techniquement il y a peu de différences entre une action d’un contrôleur et une méthode Get d’une Web Api, mais parfois on a besoin de le faire et donc de revenir à la syntaxe standard de JQuery.

Voyons donc cela.

 

Le formulaire est JQuery.cshtml, la ligne intéressante est la suivante:

<script>
   $("#@personne.BusinessEntityID").on("click",
      function (e) {
      $.ajax(
      {
         type:"GET",
         url:window.location.origin + "/api/personne/@personne.BusinessEntityID",
         success:OnSuccess
      }
   );
 
   function OnSuccess(response)
   {
      var personne = response;
      var html = "Id: " + personne.BusinessEntityID + "<br/>";
      html += "FirstName: " + personne.FirstName + "<br/>";
      html += "LastName: " + personne.LastName + "<br/>";
 
      $("#details").html(html);
   }
}
 
);
</script>

 

Nous commençons par récupérer un pointeur vers le bouton dont l’id est BusinessEntityID et on se propose de surcharger le comportement sur un événement click.

Le comportement consiste en l’appel d’une fonction (lignes 3 à 10).

Cette fonction est très simple, elle appelle la méthode JQuery ajax(). Nous passons en paramètre de la méthode un objet JavaScript qui définit les paramètres de la requête.

Le verbe est toujours GET. Remarquez que cette fois l’url est une action d’une web api.

On a besoin de gérer l’affichage car cette fois il n’y a pas de comportement par défaut. Pour cela on fournit un comportement à l’événement success. Ce comportement est définit par la méthode OnSuccess sur laquelle il y a peu de choses à dire.

 

Visuellement:

2017-01-13_19-05-30

 

 

Angular 1

Je ne vais pas énormément m’étendre la dessus dans la mesure où j’ai déjà proposé des démos dans de précédents articles. Par exemple:

https://amethyste16.wordpress.com/2016/04/16/angular-1-les-services/

Fetch

Fetch est une version modernisée de XmlHttpRequest. Il n’est pas encore suporté par tous les navigateurs, mais des polyfills existent.

Les spécifications sont ici:

https://fetch.spec.whatwg.org/

 

Le formulaire Fetch.cshtml abrite la démo qui reprend le même HTML que précédemment.

On se contente juste de définir une méthode JavaScript getDetail().

var getDetail= function(id) {
   fetch(window.location.origin + "/api/personne/" + id)
   .then(response => response.json())
   .then(personne => {
      var html = "Id: " + personne.BusinessEntityID + "<br/>";
      html += "FirstName: " + personne.FirstName + "<br/>";
      html += "LastName: " + personne.LastName + "<br/>";
 
      var details = document.getElementById("details")
      details.innerHTML = html;
   })
   .catch();
}

 

Fetch renvoie des promises. On pourrait d’ailleurs réécrire ce code avec async/await si le navigateur choisit le supporte. Je ne pense pas que la structure de ce code soit bien difficile. Par défaut on fait une requête GET, mais Fetch permet de passer des paramètres.

 

je ne cherche pas à faire un tuto complet, vous trouverez des exemples mieux fournis dans la bibliographie. Il ne vous reste plus qu’à choisir la méthode la plus adaptée à votre code.

Découvrir si on est dans le contexte d’un appel Ajax

Ajax génère des requêtes GET ou POST normales et il n’y a pas de moyen de le savoir à moins que votre Framework fournisse une indication dans le header de la requête.

Si vous travaillez en JQuery par exemple, vous pouvez examiner le header de la requête à la recherche de l’entête X-Requested-With devant contenir la valeur XMLHttpRequest.

Avec ASP.NET MVC on dispose de la méthode Request.IsAjaxRequest() qui examine pour nous l’entête.

Bibliographie

http://tutlane.com/tutorial/aspnet-mvc/ajax-helpers-in-asp-net-mvc-with-examples

https://blog.hospodarets.com/fetch_in_action

https://jakearchibald.com/2015/thats-so-fetch/

 

Publicités

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s