I have joined Anti-IF Campaign

2ème partie l'architecture en détail d'une Single page web app HTML5 webstorage, offline et Angularjs


Dans la 1ere partie nous avions généré une Single page web app HTML5 webstorage, offline et Angularjs :
génération d'une Single page web app HTML5 webstorage, offline et Angularjs
Maintenant que nous avons une belle application, regardons comment cela fonctionne.





MVC Angular
La page principale est "index.html" et nous resterons toujours sur celle-ci (Single page application).
C'est elle qui définit les ressources à utiliser (js, css etc.) et initialise Angular : "data-ng-app" + "data-ng-view".
La valeur de "data-ng-app" fait référence au module principal "bookStore" contenu dans le fichier "mainctrl.js".
Ce module :
  • déclare le module de gestion de la persistance : "bookStore.storage.services" que nous verrons par la suite
  • déclare tous les autres modules, un module par entité :
  • déclare les routes principales :
  • s'appuie sur Modernizr pour déterminer les capacités du navigateur :
  • et enfin force l'initialisation des tous les morceaux de pages (toutes les pages edit, create et list de chaque entité)
    cela permet de nous assurer qu'au premier chargement, l'application est entièrement disponible, même si le serveur est par la suite inaccessible:

Chaque entité possède donc son propre module (ex : "authorctrl.js") qui :
  • déclare les routes liées à la gestion de l'entité :
  • déclare les contrôleurs et leurs méthodes pour former le crud complet : list, create, edit et remove dans l'exemple ci-dessous, il s'agit du contrôleur pour la liste des authors :
  • déclare ses dépendances par ex. "authorctrl.js" est lié à "bookStore.author.services" qui représente les services propres aux authors (authorsrv.js)

Chaque entité possède donc aussi son module de service (ex. "authorsrv.js") qui :
  • déclare tous les services propres à l'entité :
  • déclare la dépendance à "bookStore.storage.services" (services génériques de persistance : "datastore.js")

Arrêtons nous quelques instants sur l'architecture des différents modules.
Celle-ci est découpée en couches bien isolées permettant de faire évoluer facilement un comportement sans remettre en cause les autres.
Si nous récapitulons l'enchainement des modules, on obtient ceci pour l'entité author :
mainctrl.js (contrôleur principal) -> authorctrl.js (contrôleur pour author) -> authorsrv.js (services pour author) -> datastore.js (services génériques de persistance)

Remettons tout cela à plat pour comprendre comment ca fonctionne.
Voici les protagonistes en remontant :
  • le fichier "datastore.js" :
    • correspond au module "bookStore.storage.services"
    • déclare "ApiStorage" comme identifiant de l'api générique de persistance
  • le fichier "authorsrv.js" :
    • correspond au module "bookStore.author.services"
    • utilise le module "bookStore.storage.services" (protagoniste précédent)
    • demande à recevoir en paramètre la classe "ApiStorage" (api générique de persistance déclarée par le protagoniste précédent)
    • déclare "ApiAuthor" comme identifiant de l'api de gestion des authors
  • le fichier "authorctrl.js" :
    • correspond au module "bookStore.author"
    • utilise le module "bookStore.author.services" (protagoniste précédent)
    • contient un contrôleur "AuthorListCtrl"
      • "AuthorListCtrl" demande à recevoir "ApiAuthor" (api définie par le protagoniste précédent)
      • "AuthorListCtrl" demande à recevoir "ApiStorage" (dépendance au protagoniste précédent)

Cette description permet de mieux comprendre comment fonctionne l'injection de dépendance dans Angular.
Pour plus d'information, je vous invite à consulter le site d'Angular.


Binding Angular
Le binding bidirectionnel permet à Angular de synchroniser la vue et le modèle de façon dynamique.
Sa mise en place est ultra simple, il vous suffit de :
  • déclarer le contrôleur (data-ng-controller)
  • rattacher chaque input à une donnée du modèle (data-ng-model)
  • plugger les actions sur les boutons (data-ng-click)
  • et le tour est joué
Pour les reste, Angular s'en occupe.

Web storage
Les services génériques de persistance "datastore.js" s'appuient sur le localstorage html5.
Le but est d'offrir à l'application la possibilité de fonctionner sans serveur pour le stockage des données.
Le localstorage gère, sans date d'expiration, des données de type clé/valeur.
Pour simplifier notre tutoriel, toutes les données, quelques soit l'entité, sont stockées au format json dans une unique clé.
Le json est toujours en mémoire pour accélérer les lectures.
Chaque modification du json implique une mise à jour en localstorage.
Voici un exemple de cette structure :
Cette méthode n'est surement pas optimisée, mais il s'agit d'une première version, nous irons plus loin avec indexedDB.


Offline Monitoring
Un des petits plus de cette application est le Offline Monitoring qui permet de détecter quand le serveur n'est plus accessible.
Vous trouverez dans les liens utiles la référence expliquant comment mettre en place un vrai monitoring.
J'ai adapté ces principes dans le fichier "offline.js" en utilisant un fichier texte "onlineCheck.txt" pour la détection.


Offline app cache
Depuis Html5, la mise en cache de ressources (html, js, css ...) permet d'utiliser une application web même si le serveur ne répond plus.
Le navigateur ira alors chercher en local les ressources nécessaires.
Pour cela, nous devons identifier toutes les ressources concernées dans un CACHE MANIFEST.
C'est ce qui est réalisé dans le fichier "offline.appcache" déclaré en entête de la page "index.html".
Notons que deux fichiers ne sont pas déclarés dans ce manifest :
  • offline.appcache
  • onlineCheck.txt (pour permettre de vraiment détecter si le serveur est accessible ou non)


Responsive Design
L'utilisation du Bootstrap Twitter permet de proposer une application respectant le concept de Responsive Design.
Quelque soit la taille de l'écran, les composants s'adaptent pour vous offrir la meilleure lisibilité :
  • adaptation de la largeur des blocs
  • affichage d'un menu complet ou d'un bouton d'accès à ce menu suivant la place disponible
  • ...
Je vous propose de tester sur Smartphone ou tablette, vous verrez.


Conclusion
Je pense avoir fait le tour de cette nouvelle application.
Elle évoluera dans les semaines à venir pour s'enrichir et s'améliorer.
Si vous avez des suggestions, n'hésitez pas à nous en faire part.


Nous ferons prochainement une vidéo sur Youtube de cette procédure.


Liens utiles :
Lien 1ere partie : génération d'une Single page web app HTML5 webstorage, offline et Angularjs

Le site de Telosys : http://www.telosys.org/
La doc : https://sites.google.com/site/telosystools/
Les sources : https://code.google.com/p/telosys-tools
L'update site : http://marketplace.eclipse.org/content/telosys-tools
Le site google code : https://code.google.com/p/telosys-tools/
L'archétype maven angularHtml5offline-starterkit dans le central repository :
Le starterkit SANS maven : starterkit sans maven
Le code source de l'archétype maven : https://github.com/asicfr/angularHtml5offline-starterkit
Angular : http://angularjs.org/

Jquery : http://jquery.com/
Bootstrap : http://twitter.github.com/bootstrap/
Modernizr : http://modernizr.com
Toastr : https://github.com/CodeSeven/toastr
Html5 app cache : https://developer.mozilla.org/fr/docs/Utiliser_Application_Cache
Local storage : http://www.w3schools.com/html/html5_webstorage.asp
Monitoring offline : http://ednortonengineeringsociety.blogspot.fr/2010/10/detecting-offline-status-in-html-5.html
App cache sous firefox : about:cache (browser.cache.memory.enable doit être à true)
App cache sous chrome : chrome://appcache-internals/
CRUD : http://fr.wikipedia.org/wiki/CRUD

Aucun commentaire:

Enregistrer un commentaire