jeudi 16 février 2017

Créer des afficheurs ou des filtres dans les tempaltes d'Aurelia JS

Aurelia est un framework web comme l'est Angular JS.
Il est un peu moins connu, mais il est pourtant très agréable à utiliser.

Venant du monde d'Angular 1, j'ai été quelque peu perturbé par la gestion des filtres sur les données (comme les tableaux), à tort, car le fonctionnement est logique et unifié, comme chaque partie du framework Aurelia.

Aurelia utilise le même principe qu'Angular, dans le HTML il faut utiliser le pipe "|".
Là où Aurelia se distingue c'est par sa logique. Que ce soit un filtre ou un convertisseur, c'est la même chose.

En effet, convertir l'affichage d'un nombre (par exemple une monnaie) s'écrit simplement ${maVar | convertisseur}.

Créer un afficheur de prix en euro


Pour faire un afficheur en euro, rien de plus simple, créez une classe quelque part dans vos sources :
/**
 * Converti le prix en centime, en euro.
 */
export class PriceValueConverter {
  toView (price) {
    return (price / 100) + ' €'
  }
}

Dans votre template incluez le convertisseur et utilisez le :
<template>
  <require from="../../../converters/price/price"></require>
  ...
  <span>${o.prix | price}</span>
  ...
</template>

Vous pouvez aussi inclure votre convertisseur de façon globale :
export function configure (aurelia) {
  aurelia.use
    .basicConfiguration()
    .developmentLogging()
    .globalResources(
      './price-value-converter'
    )

  aurelia.start().then(() => aurelia.setRoot())
}

Notez que le nom du convertisseur est conventionné, c'est en minuscule la partie avant ValueConverter.

Ce n'est pas plus compliqué que ça.

Créer un filtre de tableau 1ère solution


Créer un filtre de tableau est identique.

Créons le filtre suivant :
export class FilterValueConverter {
  toView (array) {
    return array.filter(item =>
      filterFunc('recherche', item)
    )
  }
  
  filterFunc (searchExpression, value) {
    const itemValue = value.name

    return (!searchExpression || !itemValue)
      ? false
      : itemValue.toUpperCase().indexOf(searchExpression.toUpperCase()) !== -1
  }
}

Dans le template :
<template>
  ...
  <div repeat.for="s of array | filter" />
  ...
</template>

On filtre donc un tableau qui contient des structures de données avec un champ name.
L'inconvénient c'est qu'on ne peut pas préciser le terme à rechercher via un input type text.

Créer un filtre de tableau 2ème solution


Modifions le code comme ceci :
export class FilterValueConverter {
  toView (array, searchTerm) {
    return array.filter(item =>
      filterFunc(searchTerm, item)
    )
  }
  
  filterFunc (searchExpression, value) {
    const itemValue = value.name

    return (!searchExpression || !itemValue)
      ? false
      : itemValue.toUpperCase().indexOf(searchExpression.toUpperCase()) !== -1
  }
}

Côté template on spécifie la valeur via un input text :
<template>
  ...
  <input type="text" value.bind="searchTerm" />
  ...
  <div repeat.for="s of array | filter:searchTerm" />
  ...
</template>

On passe donc le texte à rechercher via un input html.
C'est mieux mais ça impose un ValueConverter par type de recherche.

Créer un filtre de tableau 3ème solution


D'une recherche à l'autre, ce qui change finalement c'est la partie filterFunc.
Nous créons donc un FilterValueConverter générique :
export class FilterValueConverter {
  toView (array, searchTerm, filterFunc) {
    return array.filter(item =>
      searchTerm && searchTerm.length > 0
        ? filterFunc(searchTerm, item)
        : true
    )
  }
}

Côté template, on ajout la fonction a appeler :
<template>
  ...
  <input type="text" value.bind="searchTerm" />
  ...
  <div repeat.for="s of array | filter:searchTerm:myFilter" />
  ...
</template>

Dans le controlleur du template, il faut ajouter la fonction de filtrage :
export class MyController {
  ...
    myFilter (searchExpression, value) {
    const itemValue = value.name

    return (!searchExpression || !itemValue)
      ? false
      : itemValue.toUpperCase().indexOf(searchExpression.toUpperCase()) !== -1
  }
  ...
}

Et voilà, le tour est joué.

Aucun commentaire:

Publier un commentaire