– AngularJS – Formation au framework



– AngularJS – Formation au framework

0 0


formation_angular


On Github romainseb / formation_angular

AngularJS

Formation au framework

Tamaris

Plan

Première partie

  • Introduction
  • Initialisation
  • Rooting
  • Expressions
  • Templates
  • Contrôleurs
  • Filtres
  • Formulaires

Plan

Seconde partie

  • Services
  • Promesses
  • Directives
  • Spécifique Tamaris
  • Limitations
  • Tests
  • Le futur !

Introduction

AngularJS n'est pas :

  • Une librairie ( jQuery / Mootools .. ) - Une librairie est une boite à outils utilisables quand le besoin se fait sentir.
  • Un framework frond-end ( Bootstrap / Foundation .. ) -Bibliothèque de composants graphiques.

AngularJS apporte :

  • Un framework javascript
  • Approche MVC
  • Étend HTML à un format plus lisible et expressif
  • Sépare les interactions du DOM avec le code métier
  • Two-way Databinding
  • La construction organisée d'une "Single Page Application"

En comparaison avec certains homologues ?

Communauté ( 16/08/2014 )

Métrique AngularJS Backbone.js Ember.js Etoiles sur Github 27,2k 18,8k 11k Modules 800 236 21 Questions StackO. 49.5k 15.9k 11.2k Resultats YouTube 75k 16k 6k Contrib GitHub 928 230 393

Intérêt de la communauté

Tendances

Marché de l'emploi ( relatif )

Tendances

Marché de l'emploi ( absolu )

Apprentissage

Initialisation

Récupérer AngularJS

  • via NPM
  • via Bower
  • via le site internet

Prenons un fichier Html basique ...

<html>
    <head></head>
    <body>
        <div>hello</div>
    </body>
</html>

... ajoutons y Angular

<html ng-app="formation">
    <head></head>
    <body>
        <div>hello</div>
        <script src="angular.js"></script>
        <script src="app.js"></script>
    </body>
</html>

Fichier app.js

angular.module("formation",[]);

Que se passe-t-il ?

  • Attente de document.ready
  • Chargement du module associé à ng-app
  • Création du système d'injection de dépendance
  • Compilation du DOM en prennant comme racine la balise portant la propriété ng-app.

Rooting

Besoin

  • Avoir différentes vues correspondant à plusieures urls
  • Associer un comportement
  • Conserver le contexte
  • Conserver certains éléments graphiques

Modules

Il existe 2 modules principaux pour faire du routing AngularJS

  • UI Router ( https://github.com/angular-ui/ui-router )
  • ngRoute ( https://docs.angularjs.org/api/ngRoute )

Initialisation

Javascript

angular.module('formation').config(function($routeProvider) {

    $routeProvider.when('/', {
        templateUrl: 'app/views/home/home.html',
        controller: 'HomeController'
    });

    $routeProvider.when('/settings/', {
        templateUrl: 'app/views/settings/settings.html',
        controller: 'SettingsController'
    });

    $routeProvider.otherwise({redirectTo: '/'});
});

Templates

<div ng-view></div>

Expression

Les expressions sont sous la forme {{Expression}}

<html ng-app="formation">
    <head></head>
    <body>
        <div>
            {{1+2}}
            {{a+b}}
            {{user.name}}
            {{items[index]}}
        </div>
        <script src="angular.js"></script>
        <script src="app.js"></script>
    </body>
</html>

Data-Binding - One Way Data-Binding

  • Méthode traditionnelle dans la construction de vues.
  • Le template et le modèle sont fusionnés pour constituer la vue.
  • Les changements du modèle ne sont pas mis à jour dans la vue et inversement de manière automatique
  • Le développeur doit écrire le code permettant de faire les synchronisations vue / modèle

Data-Binding - Two Way Data-Binding

  • Compilation du template dans le navigateur
  • Toute modification du modèle est directement propagée à la vue et inversement
  • Le modèle est la source de confiance pour l'application.
  • La vue n'est que la projection instantanée du modèle

Expressions Angular

  • Ne peuvent pas contenir de structure de contrôle ( boucle / if / exception )
  • Ne peuvent pas contenir de fonction
  • Peuvent utiliser les filtres pour formater les données

Expressions Angular VS Javascript

Indulgence à l'évaluation de propriétés non définies

  • Epression Javascript : ReferenceError or TypeError
  • Expression Angular : valeur évaluée à undefined ou null

Expressions Angular VS Javascript

Contexte

  • Epression Javascript : utilisation du contexte Global
  • Expression Angular : utilisation du "scope", un contexte local relatif à un contrôleur

Templates

Les templates AngularJS sont basé sur du HTML :)

<html ng-app="formation">
    <head></head>
    <body>
        <div ng-controller="FormationController">
            <input ng-model="maVal">
        </div>
        <button ng-click="maFonction()"> {{buttonText}} </button>
        <script src="angular.js"></script>
        <script src="app.js"></script>
    </body>
</html>

Elements à disposition

  • Des directives
  • Des expressions
  • Des filtres
  • Des formulaires

Directives spécifiques AngularJS à disposition

  • ng-if : Présence conditionnelle d'un élément
<div ng-if="maCondition == true">
ng-show : Affichage conditionnel d'un élément
<div ng-show="maCondition == true">
ng-repeat : Permet de répéter un élément avec un contexte donné
<div ng-repeat="monOjbet in monTableau">
<div>{{monObjet.maPropriete}}</div>
</div>

Directives spécifiques AngularJS à disposition

  • ng-disabled : Désactive conditionnellement un input
<input type="text" ng-disabled="maCondition == true">
ng-class : Ajoute une classe conditionnellement
<div ng-class="{'ma-classe':maCondition}">
ng-click : Ajoute un écouteur sur le click
<div ng-click="maFonctionAuClic()">
... et pleins d'autres

Contrôleur

Initialisation d'un contrôleur possible :

  • Déclaration d'une route
  • Déclaration d'une directive
  • Dans le template via l'attribut ng-controller
<html ng-app="formation">
    <head></head>
    <body>
        <div ng-controller="FormationController"></div>
        <script src="angular.js"></script>
        <script src="app.js"></script>
    </body>
</html>

Rôles du contrôleur

  • Initialise le scope, son contexte local
  • Contient du code simple
  • Permet de définir les fonctions et les attributs utilisés dans le template

Ce que le contrôleur ne fait pas

  • Ne manipule pas le DOM
  • Ne formate pas les données à afficher

Déclaration du contrôleur

angular.module('formation').controller('FormationController',
                            function( $scope ){
                            $scope.variableAffiche = "hello";
                            }
                            ));

Utilisation de l'attribut défini

<html ng-app="formation">
    <head></head>
    <body>
        <div ng-controller="FormationController">
            {{variableAffiche}}
        </div>
        <script src="angular.js"></script>
        <script src="app.js"></script>
    </body>
</html>

Déclaration du contrôleur

angular.module('formation').controller('FormationController',
    function( $scope ){
        $scope.maFonction = function(){ alert("hello"); };
    }
));

Utilisation de la fonction définie

<html ng-app="formation">
    <head></head>
    <body>
        <div ng-controller="FormationController">
            <input type="button" ng-click="maFonction()"/>
        </div>
        <script src="angular.js"></script>
        <script src="app.js"></script>
    </body>
</html>

Filtres

Rôle des filtres

  • Permettent de sélectionner un sous ensemble d'un tableau
  • Equivalents aux opérateurs de templates dans les langages de templates courants
  • Permettent de reformater des données afin de les afficher

Liste des filtres natifs AngularJS

  • filter : Récupération d'un sous ensemble d'un tableau
  • currency : Affichage sous format monétaire
  • date : Formatatge de dates
  • json : Formatte un objet javascript en string
  • lowercase : Formate le texte en minuscule
  • upercase : Formate le texte en majuscule
  • limitTo : Permet d'afficher un certain nombre d'éléments d'un tableau
  • orderBy : Permet d'ordonner les objets d'un tableau par un de leurs attributs communs

Déclaration côté javascript

angular.module('formation', []).filter('yOrN', function() {
    return function(input) {
        return input ? 'y' : 'n';
    };
});

Déclaration dans un template

{{true|yOrN}} -> 'y'

Formulaires

Description

AngularJS apporte un lot de fonctionnalités concernant les formulaires.

Ces formulaires permettent de contrôler les balises input, textarea et select.

Ces formulaires vont permettre de construire dynamiquement des objets.

Fonctionnement

<div ng-controller="FormationController">
    <form novalidate class="simple-form">
        Name : <input type="text" ng-model="user.name"/>
        Email : <input type="email" ng-model="user.email"/>
    </form>
    <span>form = {{user.name}}</span>
    <span>form = {{user.email}}</span>
</div>

Les éléments des champs de saisie sont rattachés via l'attribut ng-model.

L'attribut "novalidate" sert à désactiver la validation native du navigateur.

Côté CSS

Des classes sont ajoutés automatiquement

  • ng-valid : La valeur est correcte
  • ng-invalid : La valeur est incorrecte
  • ng-pristine : La valeur n'a pas été modifiée
  • ng-dirty : La valeur a été modifiée
  • ng-touched : La contrôleur a été solicité pour un changement
  • ng-unteouched : Le contrôleur n'a pas été notifié

Exemple

  • Affichage en rouge des valeur incorrectes modifiées
  • Affichage en vert des valeur correctes modifiées
<div ng-controller="FormationController">
    <form novalidate class="simple-form">
        Name : <input type="text" ng-model="user.name"/>
        Email : <input type="email" ng-model="user.email"/>
    </form>
    <span>form = {{user.name}}</span>
    <span>form = {{user.email}}</span>
</div>
.simple-form input.ng-invalid.ng-touched {
    background-color: red;
}

.simple-form input.ng-valid.ng-touched {
    background-color: green;
}

Afficher des messages

Il est possible d'ajouter des conditions pour la validité

Les états de ces conditions peuvent être contrôlés indépendament

Exemple

E-mail:
<input type="email" ng-model="user.email" name="uEmail" required/>
<div ng-show="form.$submitted || form.uEmail.$touched">
    <span ng-show="form.uEmail.$error.required">
        L'adresse mail est obligatoire
    </span>
    <span ng-show="form.uEmail.$error.email">
        L'adresse mail saisie n'est pas valide
    </span>
</div>
Age:
<input type="number" ng-model="user.age" name="uAge" required min="18" max="100"/>
<div ng-show="form.$submitted || form.uAge.$touched">
    <span ng-show="form.uAge.$error.required">
        Le champ âge est obligatoire
    </span>
    <span ng-show="form.uAge.$error.min">
        La valeur saisie est inférieure au minimum ( 18 )
    </span>
    <span ng-show="form.uAge.$error.max">
        La valeur saisie est supérieure au minimum ( 100 )
    </span>
</div>

Configuration du déclenchement

La mise à jour du modèle peut être retardée, voir uniquement déclenchée lors d'un évènement

Déclenchement évènementiel

Utilisation de l'attribut "on-blur" pour déclencher la mise à jour du modèle quand on perd le focus sur le champ

<input type="text" ng-model="user.name"
ng-model-options="{ updateOn: 'blur' }" />

Déclenchement évènementiel

Utilisation de l'attribut "debounced" pour déclencher la mise à jour du modèle après un certain temps sans modification

<input type="text" ng-model="user.name" ng-model-options="{ debounce: 500 }" />

Pour les plus acharnés

Il est tout à fait possible de cumuler ces différnts déclencheurs

<input type="text" ng-model="user.name"
    ng-model-options="{
        updateOn: 'default blur',
        debounce: { default: 500, blur: 0 }
    }" />

Services

Déclaration d'un service

angular.module('formation').service('FormationService',
    function(){
        this.afficheAlerte = function(){
           alert("hello");
        }
    }
));

Injection de ces services

angular.module('formation').controller('FormationController',
    function( $scope, FormationService ){
        $scope.maFonction = function(){
            FormationService.afficheAlerte();
        };
    };
));

Particularités des services AngularJS

  • Lazily instantiated : Instanciation du service uniquement quand un composant en a besoin
  • Singleton : Chaque composant ayant une référence vers un service récupère la même instance

Directives

Rôle

  • Rendre plus expressif les templates
  • Créer des composants réutilisables
  • Améliorer la maintenablité

Types

  • Element
<nom-directive></nom-directive>
  • Attribut
<div nom-directive></div>
<div data-nom-directive></div>
<div x-nom-directive></div>
  • Classe css
<div class="nom-directive"></div>

Déclaration

HTML

<nom-directive></nom-directive>

javascript

angular.module("formation").directive("nomDirective", function() {
    return {
        restrict: 'E', //E pour élément, A pour attribut
        template: '<div>test</div>'
    };
});

Passer des paramètres

HTML

<nom-directive
                            param1="text"
                            param2="value"
                            param3="function">
                            </nom-directive>

Javascript

angular.module("formation").directive("nomDirective", function() {
    return {
        restrict: 'E', //E pour élément, A pour attribut
        scope:{
            param1 : '@', // Reception d'une chaine de caractère
            param2 : '=', // Réception d'une variable
            param3 : '&' // Réception d'une fonction
        }
        template: '<div>test</div>'
    };
});

Comportement d'une directive

Utilisation des contrôleurs
angular.module('formation').controller('FormationController',
    function( $scope ){
        $scope.maFonction = function(){ alert("hello"); };
    }
));
angular.module("formation").directive("nomDirective", function() {
    return {
        restrict: 'E', //E pour élément, A pour attribut
        controller : 'FormationController',
        scope:{
            param1 : '@', // Reception d'une chaine de caractère
        }
        template: '<div ng-click="maFonction()">test</div>'
    };
});

Templates

Utilisation de l'attribut TemplateURL

angular.module("formation").directive("nomDirective", function() {
    return {
        restrict: 'E', //E pour élément, A pour attribut
        controller : 'FormationController',
        scope:{
            param1 : '@', // Reception d'une chaine de caractère
        }
        templateUrl: '/formation/templates/madirective.html'
    };
});

Templates

Le template passé en paramètre ne doit avoir qu'un seul élément parent.

  • Cas non fonctionnel :
<div>
...
</div>
<div>
...
</div>
  • Cas fonctionnel :
<div>
...
</div>

Priorité

Quand plusieurs directives sont sur le même élément, une priorité d'exécution peut être définie

angular.module("formation").directive("nomDirective", function() {
    return {
        restrict: 'E', //E pour élément, A pour attribut
        controller : 'FormationController',
        priority: 1,
        scope:{
            param1 : '@', // Reception d'une chaine de caractère
        }
        templateUrl: '/formation/templates/madirective.html'
    };
});

La directive ayant la priorité la plus grande sera exécutée en premier

La priorité est par défaut à 0

Comment sont elles compilées ?

$compile parcourt le DOM et récupère les directives. Quand une directive est trouvée, elle est ajouté à la liste des directives utilisées. Un élément peut correspondre à plusieurs directives. Quand toutes les directives sont identifiées, le compilateur trie les directives retenues par "priority". $compile fait le lien entre le scope et le template pour chaque directive.

Spécifique Tamaris

Composants spécifiques

  • TamarisPanel
  • TamarisAlert
  • TamarisComboBox
  • TamarisContextMenu
  • TamarisDatePicker

Directives

  • focusMe
  • getWidth
  • ngScopeElement
  • ngModelOnblur
  • draggableHeader
  • sglclick
  • tamClickParent
  • tamMove
  • tamLeave
  • ngRightClick

Services

  • FlexService
  • WindowService
  • KeyBoardService

Organisation des fichiers historique

Organisation des fichiers historique

Limitations

Comment les éléments se mettent à jour dans l'IHM

AngularJS utilise un système de Dirty-Checking. Exemple, je click sur un bouton avec un ng-click

  • Le ngClick applique un "$apply" sur le scope
  • L'apply effectue une vérification des valeurs de tous les champs reliés au databinding
  • Si une différence est présente entre la nouvelle et l'ancienne, la modif est appliquée à la vue

Problématique du nombre de watch

Que se passe-t-il quand un nombre d'éléments important est synchronisé en two-way data-binding ?

De forts ralentissements

Comment l'éviter ?

Le nombre maximum à avoir pour obtenir une expérience utilisateur correcte est "décrite" à 2000 watchs

Pour les diminuer, il est possible d'associer des éléments statiques en one-way :

  • Bind once ( pour angular < 1.3 )
  • Binding One Way natif en AngularJS >= 1.3 ( {{:maValeur}}

Attention à certaines directives

Des directives telles que "ngClick" provoquent une réévaluation de toute la page à chaque click. Un ngMouseOver le fait à chaque mouvement de souris sur l'élément suivi

Tentez d'utiliser :

  • tamClickParent
  • tamMove
  • tamLeave ...

Tests

Karma

Jasmine

Le futur !

AngularJS 1.4

AngularJS 2.0

THE END

0
AngularJS Formation au framework Tamaris