Skip to content

JS Data : gestion des objets

Denis Merigoux edited this page May 6, 2016 · 4 revisions

#Pourquoi JS-Data ?

JS-Data permet de transformer le frontend en une véritable application autonome avec ses données et pas seulement une couche qui "affiche" le backend. JS-Data est ainsi le "backend du frontend", il communique avec le backend de manière à minimiser les requêtes HTTP. Par exemple, quand un User est chargé dans JS-Data, il ne sera pas redemandé au backend. Ainsi quand on navigue sur le site, la première fois les informations des pages mettent longtemps à se charger à cause du delai de la requête au backend, puis les fois suivantes le chargement est instantané car les données se trouvent dans le cache de JS-Data.

#Concepts de JSData

L'information est organisée autour de trois objets : Resource, Record et Mapper.

Une Resource est une abstraction de données, par exemple le type "User", le type "Group" ou le type "Cluster". En principe, on doit pouvoir effectuer des actions CRUD sur une Resource.

Un Record est une instance d'une Resource. Par exemple le groupe "Binet Réseau" est un Record de la Resource "Group".

Un Mapper est un objet qui associe les Records d'une Resource aux objets en mémoire. C'est cet objet qui va nous permettre de définir des services pour gérer nos Resources.

#DataStore

JSData fournit un outil qui permet de stocker les objets en mémoire cache, et donc d'éviter de faire des appels à l'API REST pour des objets déjà vus. Il s'agit du DataStore.

Les Mappers sont attachés à un DataStore de telle sorte que tout appel à une ressource sur le serveur est mise en cache, de même que toute création d'une nouvelle instance d'une ressource.

Le service APIService possède donc un attribut store de type DataStore. Par exemple, pour récupérer un utilisateur grace à son id, on utilisera l'instruction suivante :

APIService.store.find('user', 3)

Cette fonction renvoie un objet de type JSData.utils.Promise. On peut donc utiliser la méthode .then() pour exploiter le résultat.

#Classes, relations

##Définitions

Dans les fichiers du dossier src/shared/resources sont définies les classes des objets de JS-Data. On peut voir que ces objets contiennent plus de champs que ceux fournis par le backend ; en effet, JS-Data permet de relier les objets entre eux. Par exemple, dans user.ts on a :

hasMany: {
    membership: {
        foreignKey: 'user_id',
        localField: 'memberships'
    }
}

Grâce à cette relation, JS-Data va inclure dans user.memberships tous les objets du Datastore de la classe Membership tels que membership.user_di==user.id. Réciproquement, dans membership.ts :

belongsTo: {
    user: {
        localKey: 'user_id',
        localField: 'user'
    }
}

Dans le champ local membership.group va figurer l'objet de la classe User dont l'id est stocké dans le champ membership.user_id.

##Utilisation

Ces liens entre objets s'utilisent d'une manière assez particulière. Cela se comprend mieux sur un exemple. Sur la page du profil d'un utilisateur, le composant ProfileDisplayComponent qui reçoit en @Input un objet de la classe User va immédiatement chercher tous les Memberships de cet user. Lorsque ces Memberships arrivent dans le DataStore, ils sont liés directement et arrivent dans le champ user.memberships. Chaque Membership a un groupe membership.group qui est automatiquement lié (grâce au champ membershipgroup_id) mais pour qu'il soit lié au bon groupe il faut que ce groupe soit dans le DataStore. Ainsi il faut appeler store.find pour chercher tous les groupes de l'utilisateur et les ramener dans le DataStore. Le code suivant dans profile-display.ts se comprend donc :

this.api.store.findAll('membership',{'user':this.user.id}).then(res => {
    for (var membership of this.user.memberships) {
        this.api.store.find('group',membership.group_id);
    };
});

Dans profile-display.html, on peut donc accéder aux groupes d'un utilisateur via user.memberships[...].group.