2
Oct/09
0

Gestion générique des appels Ajax

Le fonctionnement au niveau du navigateur est revu, et on pose les briques de base pour une gestion générique des événements Ajax au niveau de l’interface.

Pour cela, jQuery offre de nombreux points de rattachement lorsqu’une requête Ajax est déclenchée.

Notre but sera de programmer des comportements génériques de la façon la plus personnalisable et en essayant de rester au plus près du style de programmation jQuery.

Création de la vue

Des bibliothèques jQuery de messagerie informative et non intrusive existent, comme par exemple jGrowl. Nous prévoyons plutôt un système simple d’affichage, dans lequel un unique message est affiché à la fois. La référence ici est celle de google reader, à savoir un simple bandeau en position fixe en haut de l’écran.

Code HAML priv/templates/views/index.html.haml :

  %body
    #header
      #logo MyApp
    #global_msg
    #main
      ...

La feuille de style priv/templates/styles/application.css.sass :

#global_msg
  :background-color #DDD
  :border-bottom 1px solid #555
  :top 41px
  :display none
  :position fixed
  :left 0
  :width 100%
  :padding 2px

Rien de particulier ici. On lance une action rake front pour transformer les modèles en fichiers cibles.

Création des comportements

Les fonctions javascript génériques seront écrites dans leur espace de nom. Pour cela, on « étend » jQuery afin de proposer les fonctions en tant que valeur de clés Json (la clé = le nom de la fonction / la valeur = la fonction anonymisée).

Pour cela, toutes les fonctions seront stockées dans le bloc suivant :

$.extend({
});

On commence par définir les éléments génériques suivants :

$.extend({
 
  // Global messages, depending on locale
  messages: {
    forbidden: "You don't have access to this resource",
    server_error: "A problem occurred on the server",
    loading: "Loading...",
    loaded: "Data loaded"
  },
 
  // Effect when a global message expire
  globalMessageTimeout: function() {
    $("#global_msg").slideUp("fast");
  }
});

Ensuite, on ajoute les méthodes de rappel qui seront associées à chaque événement Ajax :

$.extend({
  ...
 
  globalAjaxStartEvent: function(event) {
    clearTimeout(this.timeout);
    this.timeoutDelay = 3000;
    $("#global_msg").text($.messages.loading).show();
  },

Cette fonction sera appelée avant toute action Ajax. On en profite pour afficher la zone de message. De plus, on réinitialise la fonction utilisée lorsque le délai d’affichage est dépassé. On défini aussi la durée d’affichage par défaut du message. Les éléments de timeout seront associés directement à l’objet sur lequel l’événement Ajax sera joué ; d’où le mot clé this.

...
 
  globalAjaxEndEvent: function(event, request, ajaxOptions) {
    if (request.status == 200) {
      $("#global_msg").text($.messages.loaded);
      this.timeoutDelay = 500;
    }
    this.timeout = setTimeout($.globalMessageTimeout, this.timeoutDelay);
  },

Cette méthode est appelée à la fin d’un événement Ajax, quel que soit le résultat. Si l’action Ajax est correcte, on diminue le délai d’affichage, puis on déclenche la méthode qui permet d’enlever la zone de message de l’interface (à la fin du délai bien sûr).

  ...
 
  globalAjaxErrorEvent: function (event, request, ajaxOptions, thrownError) {
    msg = request.statusText;
    if (request.status == 403) {
      msg = $.messages.forbidden;
    }
    else if (request.status == 502) {
      msg = $.messages.server_error;
    }
    $("#global_msg").text(msg);
  }
});

Cette fonction est appelée si une action Ajax s’est mal passée : ici on traduit un code d’erreur en message lisible par l’utilisateur. Et on l’affiche dans la zone de message.

Au final, on a cette structure priv/www/assets/scripts/app-core.js :

$.extend({
  messages: { ... },
  globalMessageTimeout: function() { ... },
  globalAjaxStartEvent: function(event) { ... },
  globalAjaxEndEvent: function(event, request, ajaxOptions) { ... },
  globalAjaxErrorEvent: function (event, request, ajaxOptions, thrownError) { ... }
});

Affectation des évenements

La réaction aux événements doit être réalisée de façon globale à la page. On décide donc d’affecter les événements au tag HTML le plus à la racine : le tag body.

jQuery déclenche des événements au niveau de l’élément sur lequel on clique (en général, un lien). Ces événements sont propagés à travers les ancètres de l’élément dans l’arbre DOM. Et ceci jusqu’à ce qu’ils soient trappés ou arrivent à la racine (ce qui est nommé event delegation). Ce fonctionnement permet par exemple de faire des événéments live qui fonctionnent correctement même lorsque des éléments sont ajoutés au DOM de façon dynamique (voir, par exemple, ce blog)

Pour notre part, on rajoute à notre fichier précédent ce type de code :

$(function() {
  $("body").bind("ajaxStart", $.globalAjaxStartEvent)
           .bind("ajaxComplete", $.globalAjaxEndEvent)
           .bind("ajaxError", $.globalAjaxErrorEvent) 
});

Le fait de coder de cette façon permet d’avoir une lisibilité accrue lors de l’utilisation des fonctions, ce qui est extrêmement important lorsqu’on sera obligé de reprendre ce javascript dans quelques mois (on sait tous que c’est inévitable).

Tous les évenements Ajax passeront alors par nos fonctions génériques. Toute propriété ajoutée (timeout) sera stockée au niveau du body.

Nous sommes alors parés pour continuer les développements en étant assurés d’avoir une base solide pour gérer les événements applicatifs.

Filed under: javascript
Comments (0) Trackbacks (0)

No comments yet.

Leave a comment

No trackbacks yet.