AngularJS est un framework JavaScript MVC développé par Google qui vous permet de créer des applications frontales bien structurées, facilement testables et maintenables.
Si vous n’avez pas encore essayé AngularJS, vous passez à côté. Le cadre se compose d'un ensemble d'outils étroitement intégré qui vous aidera à créer des applications côté client riches et bien structurées de manière modulaire, avec moins de code et plus de flexibilité.
AngularJS étend le HTML en fournissant directives qui ajoutent des fonctionnalités à votre balisage et vous permettent de créer de puissants modèles dynamiques. Vous pouvez également créer vos propres directives, en créant des composants réutilisables qui répondent à vos besoins et en supprimant toute la logique de manipulation DOM.
Il implémente également une liaison de données bidirectionnelle, connectant votre HTML (vues) à vos objets JavaScript (modèles) de manière transparente. En termes simples, cela signifie que toute mise à jour de votre modèle sera immédiatement reflétée dans votre vue sans nécessiter de manipulation DOM ou de gestion d'événements (par exemple, avec jQuery).
Angular fournit des services en plus de XHR qui simplifient considérablement votre code et vous permettent d'abstraire les appels d'API en services réutilisables. Avec cela, vous pouvez déplacer votre modèle et votre logique métier vers le front-end et créer des applications Web indépendantes du back-end.Enfin, j'adore Angular en raison de sa flexibilité en matière de communication serveur. Comme la plupart des frameworks JavaScript MVC, il vous permet de travailler avec n'importe quelle technologie côté serveur tant qu'il peut servir votre application via une API Web RESTful. Mais Angular fournit également des services en haut de XHR qui simplifient considérablement votre code et vous permettent d'abstraire les appels d'API en services réutilisables. Par conséquent, vous pouvez déplacer votre modèle et votre logique métier vers le front-end et créer des applications Web indépendantes du back-end. Dans cet article, nous allons faire exactement cela, une étape à la fois.
Tout d'abord, décidons de la nature de l'application que nous souhaitons créer. Dans ce guide, nous préférons ne pas passer trop de temps sur le back-end, nous allons donc écrire quelque chose basé sur des données facilement accessibles sur Internet, comme une application de flux sportif!
Étant donné que je suis un grand fan de course automobile et de Formule 1, j'utiliserai un service d'API autosport pour servir de back-end. Heureusement, les gars de Ergast ont la gentillesse de fournir une API de sport automobile gratuite qui sera parfaite pour nous.
Pour un aperçu de ce que nous allons construire, jetez un œil à la démo en direct . Pour embellir la démo et montrer quelques modèles angulaires, j'ai appliqué un thème Bootstrap de WrapBootstrap , mais comme cet article ne concerne pas le CSS, je vais simplement l'abstraire des exemples et le laisser de côté.
Lançons notre exemple d'application avec un passe-partout. Je recommande le angulaire-graine projet car il vous fournit non seulement un excellent squelette pour le bootstrapping, mais définit également le terrain pour les tests unitaires avec Karma et Jasmin (nous ne ferons aucun test dans cette démo, nous allons donc laisser ces choses de côté pour le moment; voir Partie 2 de ce didacticiel pour plus d'informations sur la configuration de votre projet pour les tests unitaires et de bout en bout).
EDIT (mai 2014): Depuis que j'ai écrit ce tutoriel, le angulaire-graine projet a subi d'importants changements (y compris l'ajout de Tonnelle en tant que gestionnaire de paquets). Si vous avez des doutes sur la façon de déployer le projet, jetez un coup d'œil à la première section de leur guide de référence . Dans Partie 2 de ce tutoriel, Tonnelle , entre autres outils, est traité plus en détail.
OK, maintenant que nous avons cloné le dépôt et installé les dépendances, le squelette de notre application ressemblera à ceci:
Maintenant, nous pouvons commencer à coder. Alors que nous essayons de créer un flux sportif pour un championnat de course, commençons par la vue la plus pertinente: la table de championnat .
Étant donné que nous avons déjà une liste de pilotes définie dans notre champ d'application (accrochez-vous - nous y arriverons), et ignorant tout CSS (pour la lisibilité), notre HTML pourrait ressembler à:
Drivers Championship Standings {{$index + 1}}
{{driver.Driver.givenName}} {{driver.Driver.familyName}} {{driver.Constructors[0].name}} {{driver.points}}
La première chose que vous remarquerez dans ce modèle est l'utilisation d'expressions ('{{' et '}}') pour renvoyer des valeurs de variable. Dans le développement AngularJS , les expressions vous permettent d'exécuter certains calculs afin de renvoyer une valeur souhaitée. Certaines expressions valides seraient:
{{ 1 + 1 }}
{ 946757880 }
{{ user.name }}
En fait, les expressions sont des extraits de code de type JavaScript. Mais en dépit d'être très puissant, vous ne devez pas utiliser d'expressions pour implémenter une logique de niveau supérieur. Pour cela, nous utilisons des directives.
La deuxième chose que vous remarquerez est la présence de ng-attributes
, que vous ne verriez pas dans le balisage classique. Ce sont des directives.
À un niveau élevé, les directives sont des marqueurs (tels que des attributs, des balises et des noms de classe) qui indiquent à AngularJS d'attacher un comportement donné à un élément DOM (ou de le transformer, de le remplacer, etc.). Jetons un coup d'œil à ceux que nous avons déjà vus:
Le ng-app
directive est responsable de l'amorçage de votre application en définissant sa portée. Dans AngularJS, vous pouvez avoir plusieurs applications dans la même page, donc cette directive définit où chaque application distincte commence et se termine.
Le ng-controller
directive définit quel contrôleur sera en charge de votre vue. Dans ce cas, nous désignons le driversController
, qui fournira notre liste de pilotes (driversList
).
Le ng-repeat
La directive est l'une des plus couramment utilisées et sert à définir la portée de votre modèle lorsque vous parcourez des collections. Dans l'exemple ci-dessus, il réplique une ligne du tableau pour chaque pilote de driversList
.
Bien entendu, notre vue ne sert à rien sans contrôleur. Ajoutons driversController
à nos controllers.js:
angular.module('F1FeederApp.controllers', []). controller('driversController', function($scope) { $scope.driversList = [ { Driver: { givenName: 'Sebastian', familyName: 'Vettel' }, points: 322, nationality: 'German', Constructors: [ {name: 'Red Bull'} ] }, { Driver: { givenName: 'Fernando', familyName: 'Alonso' }, points: 207, nationality: 'Spanish', Constructors: [ {name: 'Ferrari'} ] } ]; });
Vous avez peut-être remarqué le $scope
variable que nous transmettons en tant que paramètre au contrôleur. Le $scope
variable est censée lier votre contrôleur et vos vues. En particulier, il contient toutes les données qui seront utilisées dans votre modèle. Tout ce que vous y ajoutez (comme le driversList
dans l'exemple ci-dessus) sera directement accessible dans vos vues. Pour l'instant, travaillons simplement avec un tableau de données factice (statique), que nous remplacerons plus tard par notre service API.
Maintenant, ajoutez ceci à app.js:
angular.module('F1FeederApp', [ 'F1FeederApp.controllers' ]);
Avec cette ligne de code, nous initialisons réellement notre application et enregistrons les modules dont elle dépend. Nous reviendrons sur ce fichier (app.js
) plus tard.
Maintenant, rassemblons tout dans index.html
:
F-1 Feeder Drivers Championship Standings {{$index + 1}}
{{driver.Driver.givenName}} {{driver.Driver.familyName}} {{driver.Constructors[0].name}} {{driver.points}}
Modulo erreurs mineures, vous pouvez maintenant démarrer votre application et vérifier votre liste (statique) de pilotes.
Remarque: si vous avez besoin d'aide pour déboguer votre application et visualiser vos modèles et votre portée dans le navigateur, je vous recommande de jeter un coup d'œil à l'impressionnant Batarang plugin pour Chrome.
Étant donné que nous savons déjà comment afficher les données de notre contrôleur dans notre vue, il est temps de récupérer les données en direct à partir d'un serveur RESTful.
Pour faciliter la communication avec les serveurs HTTP, AngularJS fournit le $http
et $resource
prestations de service. Le premier n'est qu'une couche au-dessus de XMLHttpRequest ou JSONP , tandis que ce dernier offre un niveau d'abstraction plus élevé. Nous utiliserons $http
.
Pour extraire nos appels d'API serveur du contrôleur, créons notre propre service personnalisé qui récupérera nos données et agira comme un wrapper autour de $http
en ajoutant ceci à notre services.js
:
angular.module('F1FeederApp.services', []). factory('ergastAPIservice', function($http) { var ergastAPI = {}; ergastAPI.getDrivers = function() { return $http({ method: 'JSONP', url: 'http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK' }); } return ergastAPI; });
Avec les deux premières lignes, nous créons un nouveau module (F1FeederApp.services
) et enregistrons un service dans ce module (ergastAPIservice
). Notez que nous passons $http
en tant que paramètre de ce service. Cela indique à Angular injection de dépendance moteur requis par notre nouveau service (ou dépend de ) le $http
un service.
De la même manière, nous devons dire à Angular d'inclure notre nouveau module dans notre application. Enregistrons-le avec app.js
, en remplaçant notre code existant par:
angular.module('F1FeederApp', [ 'F1FeederApp.controllers', 'F1FeederApp.services' ]);
Maintenant, tout ce que nous avons à faire est d'ajuster notre controller.js
un peu, incluez ergastAPIservice
en tant que dépendance, et nous serons prêts à partir:
angular.module('F1FeederApp.controllers', []). controller('driversController', function($scope, ergastAPIservice) { $scope.nameFilter = null; $scope.driversList = []; ergastAPIservice.getDrivers().success(function (response) { //Dig into the responde to get the relevant data $scope.driversList = response.MRData.StandingsTable.StandingsLists[0].DriverStandings; }); });
Maintenant, rechargez l'application et vérifiez le résultat. Notez que nous n'avons apporté aucune modification à notre modèle, mais nous avons ajouté un nameFilter
variable à notre portée. Utilisons cette variable.
Génial! Nous avons un contrôleur fonctionnel. Mais il ne montre qu'une liste de pilotes. Ajoutons quelques fonctionnalités en mettant en œuvre une entrée de recherche de texte simple qui filtrera notre liste. Ajoutons la ligne suivante à notre index.html
, juste en dessous de l'étiquette:
ng-model
Nous utilisons maintenant le Cette ligne indique À ce stade, la liaison de données bidirectionnelle entre en jeu: chaque fois qu'une valeur est entrée dans le champ de recherche, Angular s'assure immédiatement que le Rechargez l'application et consultez la barre de recherche. Notez que ce filtre recherchera le mot-clé sur tous les attributs du modèle, y compris ceux que nous n'utilisons pas. Disons que nous voulons uniquement filtrer par Maintenant, de retour à Rechargez l'application une fois de plus et nous avons maintenant une recherche par nom. Notre prochain objectif est de créer une page de détails du pilote qui nous permettra de cliquer sur chaque pilote et de voir les détails de sa carrière. Tout d'abord, incluons le Avec ce changement, accédez à AngularJS vous permettra de lier vos routes à des contrôleurs et des vues spécifiques. Mais d'abord, nous devons indiquer à Angular où rendre ces vues partielles. Pour cela, nous utiliserons le Désormais, chaque fois que nous naviguons dans les itinéraires de notre application, Angular chargera la vue associée et la restituera à la place de l'étiquette. Tout ce que nous devons faire est de créer un fichier nommé Enfin, décidons ce que nous voulons afficher dans la page de détails. Que diriez-vous d'un résumé de tous les faits pertinents sur le conducteur (par exemple, naissance, nationalité) avec un tableau contenant ses résultats récents? Pour ce faire, nous ajoutons à Cette fois, nous fournissons l'ID du conducteur au service afin de récupérer les informations pertinentes uniquement pour un conducteur spécifique. Maintenant, nous modifions La chose importante à noter ici est que nous venons d'injecter le Maintenant que nous avons nos données dans la portée, nous n'avons besoin que de la vue partielle restante. Créons un fichier nommé Notez que nous mettons maintenant le Ajoutez un tas de CSS et rendez votre page. Vous devriez vous retrouver avec quelque chose comme ceci: Vous êtes maintenant prêt à lancer votre application et à vous assurer que les deux itinéraires fonctionnent comme vous le souhaitez. Vous pouvez également ajouter un menu statique à EDIT (mai 2014): J'ai reçu de nombreuses demandes pour une version téléchargeable du code que nous développons dans ce didacticiel. J'ai donc décidé de le sortir Ici (dépouillé de tout CSS). Cependant, je fais vraiment ne pas recommande de le télécharger, car ce guide contient toutes les étapes nécessaires pour créer la même application de vos propres mains, ce qui sera un exercice d'apprentissage beaucoup plus utile et efficace. À ce stade du didacticiel, nous avons couvert tout ce dont vous avez besoin pour créer une application simple (comme un feeder de Formule 1). Chacune des pages restantes de la démo en direct (par exemple, tableau du championnat des constructeurs, détails de l'équipe, calendrier) partage la même structure de base et les mêmes concepts que nous avons examinés ici. Enfin, gardez à l'esprit qu'Angular est un framework très puissant et que nous avons à peine effleuré la surface en termes de tout ce qu'il a à offrir. Dans Partie 2 de ce didacticiel, nous allons donner des exemples des raisons pour lesquelles Angular se distingue parmi ses frameworks MVC front-end pairs: testabilité. Nous passerons en revue le processus d'écriture et d'exécution des tests unitaires avec Karma , réalisant une intégration continue avec Yeomen , Sol , et Tonnelle , et d'autres atouts de ce fantastique framework front-end. AngularJS est un framework JavaScript MVC développé par Google qui vous permet de créer des applications frontales bien structurées, facilement testables et maintenables. AngularJS étend HTML en fournissant des directives qui ajoutent des fonctionnalités à votre balisage et vous permettent de créer de puissants modèles dynamiques. Vous pouvez également créer vos propres directives, créer des composants réutilisables qui répondent à vos besoins et faire abstraction de toute la logique de manipulation DOM.$scope.nameFilter
directif. Cette directive lie notre champ de texte au ng-repeat
variable et s'assure que sa valeur est toujours à jour avec la valeur d'entrée. Maintenant, visitons une fois de plus index.html et apportons un petit ajustement à la ligne qui contient le directif: ng-repeat
driversList
que, avant de sortir les données, le nameFilter
tableau doit être filtré par la valeur stockée dans $scope.nameFilter
.nameFilter
que nous lui avons associé est mis à jour avec la nouvelle valeur. Puisque la liaison fonctionne dans les deux sens, le moment où ng-repeat
La valeur est mise à jour, la deuxième directive qui lui est associée (c'est-à-dire le Driver.givenName
) obtient également la nouvelle valeur et la vue est mise à jour immédiatement.Driver.familyName
et driversController
: Tout d'abord, nous ajoutons à $scope.driversList = [];
, juste en dessous de $scope.searchFilter = function (driver) ;
ligne:index.html
ng-repeat
, nous mettons à jour la ligne qui contient le directif: $routeProvider
Itinéraires
app.js
service (en app.js
) qui nous aidera à faire face à ces divers itinéraires d'application . Ensuite, nous ajouterons deux de ces itinéraires: un pour la table de championnat et un autre pour les détails des pilotes. Voici notre nouveau angular.module('F1FeederApp', [ 'F1FeederApp.services', 'F1FeederApp.controllers', 'ngRoute' ]). config(['$routeProvider', function($routeProvider) { $routeProvider. when('/drivers', {templateUrl: 'partials/drivers.html', controller: 'driversController'}). when('/drivers/:id', {templateUrl: 'partials/driver.html', controller: 'driverController'}). otherwise({redirectTo: '/drivers'}); }]);
:http://domain/#/drivers
driversController
chargera le partials/drivers.html
et recherchez la vue partielle à rendre dans ng-view
. Mais attendez! Nous n'avons pas encore de vues partielles, n'est-ce pas? Nous devrons également les créer.Vues partielles
index.html
directive, en modifiant notre F-1 Feeder
pour refléter ce qui suit:partials/drivers.html
et y mettre notre table de championnat HTML. Nous utiliserons également cette opportunité pour associer le nom du pilote à notre itinéraire de détails du pilote:
Drivers Championship Standings {{$index + 1}} {{driver.Driver.givenName}} {{driver.Driver.familyName}}
{{driver.Constructors[0].name}} {{driver.points}} services.js
angular.module('F1FeederApp.services', []) .factory('ergastAPIservice', function($http) { var ergastAPI = {}; ergastAPI.getDrivers = function() { return $http({ method: 'JSONP', url: 'http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK' }); } ergastAPI.getDriverDetails = function(id) { return $http({ method: 'JSONP', url: 'http://ergast.com/api/f1/2013/drivers/'+ id +'/driverStandings.json?callback=JSON_CALLBACK' }); } ergastAPI.getDriverRaces = function(id) { return $http({ method: 'JSONP', url: 'http://ergast.com/api/f1/2013/drivers/'+ id +'/results.json?callback=JSON_CALLBACK' }); } return ergastAPI; });
:controllers.js
angular.module('F1FeederApp.controllers', []). /* Drivers controller */ controller('driversController', function($scope, ergastAPIservice) { $scope.nameFilter = null; $scope.driversList = []; $scope.searchFilter = function (driver) re.test(driver.Driver.familyName); ; ergastAPIservice.getDrivers().success(function (response) { //Digging into the response to get the relevant data $scope.driversList = response.MRData.StandingsTable.StandingsLists[0].DriverStandings; }); }). /* Driver controller */ controller('driverController', function($scope, $routeParams, ergastAPIservice) { $scope.id = $routeParams.id; $scope.races = []; $scope.driver = null; ergastAPIservice.getDriverDetails($scope.id).success(function (response) { $scope.driver = response.MRData.StandingsTable.StandingsLists[0].DriverStandings[0]; }); ergastAPIservice.getDriverRaces($scope.id).success(function (response) { $scope.races = response.MRData.RaceTable.Races; }); });
:$routeParams
:id
service dans le contrôleur de pilote. Ce service nous permettra d'accéder à nos paramètres URL (pour le $routeParams.id
, dans ce cas) en utilisant partials/driver.html
. <- Back to drivers list
et ajouter:
{{driver.Driver.givenName}} {{driver.Driver.familyName}} Country: {{driver.Driver.nationality}}
Team: {{driver.Constructors[0].name}}
Birth: {{driver.Driver.dateOfBirth}}
Biography
Formula 1 2013 Results Round Grand Prix Team Grid Race {{race.round}} {{race.raceName}}
{{race.Results[0].Constructor.name}} {{race.Results[0].grid}} {{race.Results[0].position}} ng-show
true
directive à bon usage. Cette directive n'affichera l'élément HTML que si l'expression fournie est false
(c'est-à-dire ni null
, ni index.html
). Dans ce cas, l'avatar n'apparaîtra qu'une fois que l'objet pilote aura été chargé dans la portée par le contrôleur.La touche finale
|_+_|
pour améliorer les capacités de navigation de l’utilisateur. Les possibilités sont infinies. Conclusion
Comprendre les bases
Qu'est-ce que AngularJS?
Pourquoi AngularJS?