Modèles de vues

Maintenant que notre projet est créé et qu'il affiche fièrement un "Hello World!", il serait bon de découvrir ce qu'on est capable de faire afficher à notre template. Éditons donc le fichier src/app.html où tout commence.

Convention

Avant de regarder comment fonctionne un template, il faut d'abord s'intéresser à la source de données. Notre application contient pour le moment uniquement un customElement sous la forme de la balise <app></app>. Chaque customElement, par convention, est, sauf exception, constitué de deux fichiers : un fichier javascript et un fichier html. Tous les deux portent le nom du customElement avec une extension .js et .html. Le fichier javascript doit exporter une classe portant le même nom que le customElement en CamelCase. Le fichier html doit contenir une balise <template>.

La classe exportée par le fichier javascript est ce qu'on appelle le viewModel. C'est l'objet qui va fournir à la vue toutes les données dont elle disposera. C'est donc ici que nous pourrons initialiser les valeurs à afficher et les fonctions à appeler soit pour l'affichages de données complexes, soit lors de l'interaction avec la vue. Notre customElement <app> dispose ainsi d'une propriété message dont une valeur est initialisée dans le contrôleur. Pour information, vous pouvez aussi rédiger votre classe en utilisant des propriétés de classe comme je vais vous le montrer avec un exemple d'un customElement nommé <mon-super-element>. Je devrais donc créer un fichier mon-super-element.js contenant ceci avec quelques exemples de choses qu'il peut contenir :

export class MonSuperElement {  
  message = 'Hello World';
  error = false;

  get type() {
    if (this.error === 42) {
      return 'danger';
    }
    return 'normal';
  }

  isError() {
    return true;
  }

  doSomething(e) {
    e.preventDefault();
    console.log('someone clicked on view');
  }
}

Tout ce qui est accessible depuis ce viewModel devient accessible via l'interpolation de la vue qui lui est associée.

Interpolation

Regardons maintenant le template app.html. Nous pouvons y voir deux choses étranges : une balise <template> et un texte encadré de ${ et }. Cette balise <template> est une balise HTML5 permettant d'intégrer du html dans une page qui sera validé par le moteur du navigateur mais qui ne sera pas attaché au DOM. C'est une façon standardisée pour générer des modèles de vues. Cette balise sera obligatoire dans tout vos fichiers de template et la console de debug vous le rappellera bien gentiment si d'aventure vous oubliiez de l'y mettre. Nous verrons par la suite, qu'elle nous sera aussi bien utile pour gérer d'autres cas particuliers. Regardons plutôt la suite.

${message} est une convention pour insérer une valeur interpolée. Cela veut dire que le texte entre les ${ et } sera du code exécuté dans le contexte du viewModel et son résultat en tant que chaine sera inséré dans la vue. Sur la plupart des framework, comme Angular par exemple, on utilise plutôt la notation {{et }}. Ici, le choix a été fait d'utiliser encore une fois un standard : les string literal. Ça ne change pas grand chose, sauf pour le développeur qui a à cœur de respecter les standards et qui en a marre de switcher entre deux types de notation selon qu'il rédige un template ou du javascript.

Dans cette balise, on peut y mettre à peu près tout ce qui peut être exécuté en javascript. Par exemple, je peux appeler une méthode de l'objet : ${message.toUpperCase()} même si nous verrons par la suite qu'il est préférable d'utiliser un valueConverter. Nous pouvons aussi utiliser de la logique : ${message ? 'un message est disponible' : 'aucun message :('}. Et surtout, nous pouvons utiliser cette balise à peu près n'importe où : en tant que nœud texte ou en tant que valeur d'attribut :

<template>  
<p  
  title="${message}"
  class="${error ? 'has-error' : ''}">${message}</p>
</template>  

Attributs

Dans un template, on peut attacher des déclarations à un élément grâce à ses attributs. La syntaxe est très intuitive et suit la forme suivante :

attribute.command="expression"

où :

  • attribute est le nom de l'attribut cible. Cela peut être absolument tous les attributs imaginables, qu'ils fassent partie du DOM, que ce soit des attributs javascript de l'élément (innerHTML par exemple) ou des customAttributes.
  • command représente le comportement qu'on veut attacher à l'attribut. Le plus souvent, nous utiliserons bind qui permet d'attacher une variable à un attribut et d'activer ainsi le two-way ou le one-way binding automatiquement selon le cas (two-way pour les contrôles de formulaire, one-way pour tout le reste). Mais on peut aussi forcer le type de binding en utilisant les commandes two-way, one-way et one-time.
  • expression est donc l'expression à exécuter. Elle s'exécutera dans le contexte du viewModel, c'est à dire que les variables spécifiées seront des propriétés de la classe associée.

On retrouvera la même syntaxe pour attacher des écouteurs d'événements sauf que l'attribut sera le nom d'un évenement. Concernant les commandes, nous en aurons deux : trigger et delegate. Le second est à privilégier car il utilise le principe de la délégation d'évènements et est donc moins couteux en ressources. L'expression pourra prendre en paramètre un objet $event qui correspondra au DOM Event associé.

Nous verrons par la suite, quand nous apprendrons à faire des customElements qu'il existe une troisième commande : call, qui permet de passer une fonction à un customElement afin qu'il l'exécute quand c'est nécéssaire.

Plusieurs attributs particuliers sont à votre dispositions pour accéder plus précisément à votre DOM :

  • ref : permet de lier un élément de votre template à une propriété de votre viewModel. Ainsi, si je déclare l'élément suivant <div ref="myDiv"></div> dans mon template, j'aurais accès à cet élément depuis mon viewModel via this.myDiv.
  • textcontent : permet de modifier le contenu textuel de l'élément. Cela sera surtout utile quand on travaillera avec un élément dont le contenu est éditable (contenteditable).

Visualisons tout ça par quelques exemples :

<template>  
<form  
  submit.delegate="send($event)">
  <div
    class="form-control">
    <label
      for="initial">Initial Value</label>
    <input
      id="initial"
      value.one-time="something"
      disabled="disabled">
    <label
      for="new">New Value</label>
  </div>
  <div
    class="form-control ${hasError ? 'has-error' : ''}">
    <input
      id="new"
      value.bind="something"
      ref="somethingInput">
  </div>
  <button
    type="submit"
    disabled.bind="!valid">Ok</button>
</form>  
</template>  

La prochaine étape sera de créer un premier customElement que nous intégrerons dans notre template app.html.

Hadrien Lanneau

Développeur de guichet, expert ESNext pile complète

Toulouse, France https://hadrien.eu

Subscribe to Aurelia Framework pour les frenchies

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!