Découvrez AngularJS

Découvrez AngularJS


Si comme moi vous trouvez qu’une vidéo vaut mieux qu’un long discours, je vous conseille cette excellente formation par Rudy Nappee.

cours tutoriel video angularjs gratuit

Et parce que c’est vous, voici un extrait gratuit. 🙂

Vidéo AngularJS gratuite de 30min


Cette article est la traduction d’une réponse trouvée sur le site Stack Overflow et écrite par Josh David Miller.

La question était : « Comment penser en AngularJS quand on a l’habitude d’utiliser jQuery ? » Et comme beaucoup de développeurs sont dans ce cas, j’ai pensé que ça serait une excellente approche pour découvrir AngularJS.

Si l’article vous plait, n’hésitez pas à envoyer un petit tweet à @joshdmiller 😉

1. Ne concevez pas votre page, pour après la modifier avec des manipulations du DOM

Dans jQuery, vous concevez une page, puis vous la rendez dynamique. Cela est dû au fait que jQuery a été créé pour « l’augmentation »,  et est devenu extrêmement populaire en partant de ce principe.

Mais en AngularJS, vous devez commencez en ayant en tête votre architecture. Au lieu de démarrer en vous disant « j’ai ce morceau de DOM et je veux lui faire faire telle chose », vous devez savoir ce que vous voulez accomplir, puis vous concevez l’application, et enfin la view.

2. N’utilisez pas AngularJS pour ajouter des fonctionnalités à jQuery

Ne partez pas avec l’idée que jQuery peut faire X, Y ou Z, et qu’il suffira d’ajouter AngularJS au dessus pour les modèles et les contrôleurs. C’est très tentant lorsque l’on débute, c’est pour cela que je recommande aux nouveaux développeurs AngularJS de ne pas du tout utiliser jQuery, au moins le temps de se familiariser avec « l’Angular Way ».

J’ai vu beaucoup de développeurs créer des solutions très élaborées de 150 ou 200 lignes avec des plugins jQuery, qu’ils collent dans AngularJS avec des callbacks et des $apply, ce qui donne quelque chose de très compliqué et d’illisible, mais qui fonctionne ! Le problème est que dans la majorité des cas, ce plugin jQuery aurait pu être réécrit en AngularJS en quelques lignes, ce qui au passage, rendrait le code bien plus compréhensible.

Ce qu’il faut retenir de tout ça : Pensez d’abord en AngularJS ; si vous ne trouvez pas, demandez à la communauté ; et si après tout cela vous n’avez pas trouvé de solution simple, alors vous pouvez utiliser jQuery. Mais ne comptez pas trop sur jQuery ou vous ne maitriserez jamais AngularJS.

3. Pensez toujours en terme d’architecture

Tout d’abord ayez en tête que les « single-page applications » sont avant tout des applications. Ce ne sont pas des pages web. Donc vous devez penser comme un développeur server-side en plus de penser comme un développeur client-side. Vous devez trouver comment diviser votre application en composants individuels, extensibles, et testables.

Comment fait-on cela ? Comment penser en AngularJS ? Voici les concepts principaux, comparés avec jQuery.

La view est le « record » officiel

En jQuery, on change la view « programmatiquement ». Par exemple, on pourrait avoir un menu comme celui-ci :

<ul class="main-menu">
	<li class="active">
		<a href="#/home">Home</a>
	</li>
	<li>
		<a href="#/menu1">Menu 1</a>
		<ul>
			<li><a href="#/sm1">Submenu 1</a>
			</li>
			<li><a href="#/sm2">Submenu 2</a>
			</li>
			<li><a href="#/sm3">Submenu 3</a>
			</li>
		</ul>
	</li>
	<li>
		<a href="#/home">Menu 2</a>
	</li>
</ul>

En jQuery, dans la logique de notre application, on écrirait quelque chose comme cela :

$('.main-menu').dropdownMenu();

Quand on regarde juste la view, il n’est pas évident de voir que quelque chose ici est dynamique. Pour de petites applications, ça va, mais pour des applications de taille conséquente, c’est un peu plus déroutant et difficile à maintenir.

En AngularJS en revanche, la view est le « record » officiel. Notre ul ressemblerait plus à quelque chose comme ça :

<ul class="main-menu" dropdown-menu>
	...
</ul>

Les deux morceaux de code font la même chose, mais dans la version AngularJS, n’importe qui peut comprendre en un coup d’oeil ce qui se passe dans le template. Quand un nouveau développeur rejoint l’équipe, il peut comprendre instantanément qu’il y a une directive dropdown-menu. Il n’a pas besoin de le deviner, ou de fouiller dans le code. La view nous renseigne sur ce qu’il doit se passer. Bien plus propre.

Les développeurs qui découvrent AngularJS posent souvent la question suivante : Comment faire pour trouver tous les éléments similaires pour leur attribuer une directive ? Le développeur est en général très étonné quand on lui dit qu’on ne peut pas. On ne fait pas ainsi, car cela reviendrait à faire du mi-jQuery, mi-AngularJS. Le problème est que le développeur essaie de faire du jQuery dans un contexte AngularJS. La view est le « record » officiel. En dehors d’une directive (plus d’explications un peu plus loin), vous ne devez jamais changer le DOM. D’ailleurs les directives sont appliquées dans la view, ce qui rend les choses bien claires.

Data binding

C’est de loin la plus géniale des fonctionnalités d’AngularJS, elle permet d’ailleurs de nous épargner pas mal de manipulations de DOM dont je parlais un peu plus haut. AngularJS mettra à jour la view automatiquement, sans que vous ayez à intervenir ! En jQuery, on répond à des événements, et à partir de là on met à jour le contenu. Par exemple :

$.ajax({
	url: '/myEndpoint.json',
	success: function(data, status) {
		$('ul#log').append('&lt;li&gt;Data Received!&lt;/li&gt;');
	}
});

Pour une view comme celle-là :

<ul class="messages" id="log">
</ul>

Déjà on mélange tout, mais plus important, on doit mettre à jour manuellement l’élément du DOM. Comment tester la logique en faisant abstraction du DOM ? Et que ce passe-t’il si on veut changer le HTML ?

Ce n’est pas très élégant, mais en AngularJS, on peut faire ceci :

$http('/myEndpoint.json').then(function(response) {
	$scope.log.push({
		msg: 'Data Received!'
	});
});

Et notre view ressemblera à ça :

<ul class="messages">
	<li ng-repeat="entry in log">{{ entry.msg }}</li>
</ul>

Mais pour l’exemple, notre view pourrait aussi ressembler à ça :

<div class="messages">
	<div class="alert" ng-repeat="entry in log">
		{{ entry.msg }}
	</div>
</div>

Et maintenant, au lieu d’utiliser une ul, on utilise les « alert boxes » de Bootstrap. Et à aucun moment on a dû toucher au contrôleur ! Mais plus important, peu importe d’où et comment les données sont modifiées, la view sera mise à jour automatiquement !

Je ne l’ai pas montré ici, mais le data-binding marche dans les deux sens. Ces messages auraient pu être éditables dans la view juste en faisant :

<input ng-model="entry.msg" />

Le modèle est une couche séparée

En jQuery, le DOM est en quelque sorte le modèle. Mais en AngularJS, le modèle est une couche séparée que l’on peut manipuler comme on le veut, et qui est complètement indépendante de la view. Cela permet de respecter le principe de « separation of concerns », et faciliter la testabilité.

« Separation of concerns »

Un point important, la « separation of concerns », c’est-à-dire le fait de ne pas tout mélanger. La view est le « record » officiel ; le modèle, c’est les données ; utilisez les services pour les tâches réutilisables ; les manipulations du DOM se font dans les directives ; et tout cela est collé ensemble par les contrôleurs.

L’injection de dépendances (dependency injection ou DI)

Pour nous aider dans la « separation of concerns », il y a l’injection de dépendances. Si vous avez de l’expérience dans un language server-side (Java, PHP…), vous êtes sûrement déjà familier avec le concept, mais si vous êtes plutôt habitué à jQuery ce concept peut paraitre superflu. Mais ça ne l’est pas.

Globalement, l’injection de dépendances signifie que vous pouvez déclarer un composant un peu n’importe où, puis depuis n’importe quel composant en demander une instance. Vous n’avez pas à vous occuper de l’ordre des déclarations ou de l’emplacement des fichiers. L’intérêt n’est pas forcement visible au premier abord, mais voici juste un exemple : Les tests.

Disons que dans notre application, on utilise un service qui gère le stockage des données côté serveur via une API REST, ou selon le contexte, utilise le localStorage. Quand on lance nos tests sur notre contrôleur, on ne veut pas communiquer avec le serveur, on teste le contrôleur après tout. On peut juste ajouter un service « mock » du même nom que le composant, et l’injecteur s’assurera que le contrôleur utilise bien le faux ; notre contrôleur n’a pas à connaitre le différence.

A propos de tests…

4. Le développement guidé par les tests (TDD) – Toujours

En terme d’architecture,  ça devrait faire partie de la section 3, mais c’est tellement important que j’en ai fait une section à part entière.

De tous les plugins jQuery que vous avez vu, utilisé, ou même écrit, combien d’entre eux étaient accompagnés de tests ? Très peu, car jQuery ne se prête pas vraiment à cette pratique, mais AngularJS oui.

En jQuery, le seul moyen de faire des tests est de créer un composant à part, avec une page de démo sur laquelle les tests pourront faire de la manipulation du DOM. Puis on devrait créer un composant séparément que l’on intègrerait dans notre application. Vraiment pas très pratique ! Donc la plupart du temps, en jQuery, on développe de manière itérative et non en TDD.

Mais puisqu’en AngularJS on a la « separation of concerns », on peut développer de manière itérative et en TDD ! Par exemple, disons que nous voulions une directive qui nous indiquerait quelle est notre route actuelle. On peut déclarer n’importe quoi dans notre view, par exemple :

<a href="/hello" when-active>Hello</a>

Puis, on peut écrire notre test :

it('should add "active" when the route changes', inject(function() {
	var elm = $compile('<a href="/hello" when-active>Hello</a>')($scope);

	$location.path('/not-matching');
	expect(elm.hasClass('active')).toBeFalsey();

	$location.path('/hello');
	expect(elm.hasClass('active')).toBeTruthy();
}));

On lance le test ; il rate. On peut maintenant écrire notre directive :

.directive('whenActive', function($location) {
	return {
		scope: true,
		link: function(scope, element, attrs) {
			scope.$on('$routeChangeSuccess', function() {
				if ($location.path() == element.attr('href')) {
					element.addClass('active');
				} else {
					element.removeClass('active');
				}
			});
		}
	};
});

Désormais, notre test passe, et notre menu fait bien ce que l’on espérait. On développe maintenant de manière itérative et en TDD.

5. Conceptuellement, les directives ne sont pas du jQuery empaqueté

Vous entendrez souvent dire « Ne faites de la manipulation de DOM que dans des directive ». C’est une nécessité. Suivez toujours ce conseil !

Mais creusons un peu…

Certaines directives modifient juste ce qui est déjà dans la view (ngClass par exemple), et font donc parfois de la manipulation de DOM au chargement de page, et puis leur travail est accompli. Mais si une directive est comme un « widget » et a un template, elle devrait aussi respecter la « separation of concerns ». C’est-à-dire que le template aussi devrait être indépendant de son implémentation dans les fonctions link et controller.

AngularJS est livré avec un ensemble d’outils qui rendent la tâche très simple ; avec ngClass on peut mettre à jour la classe dynamiquement ; ngBind permet le « Two-way data binding » ; ngShow et ngHide affichent ou masquent un élément ; et ainsi de suite, en ajoutant les directives que vous écrivez vous-même. En d’autres termes, on peut faire beaucoup de choses sans forcément manipuler le DOM. Moins il y a de manipulation de DOM, plus les directives sont faciles à tester, à faire évoluer, à réutiliser, et à distribuer.

Il y a beaucoup de débutants sur AngularJS qui utilisent les directives simplement pour y mettre des commandes jQuery. En d’autres termes, ils pensent que comme ils ne peuvent pas faire de manipulation de DOM dans le contrôleur, il suffit de mettre le code dans une directive. Certes c’est bien mieux, mais ce n’est souvent pas fait de la meilleure manière.

Pensez à l’exemple de la section 3. Même si l’on met cela dans une directive, on veut quand même le faire façon Angular. Il y a beaucoup de cas où la manipulation de DOM est nécessaire, mais pas autant que vous pourriez l’imaginer ! Avant de manipuler le DOM n’importe où dans votre application, demandez vous si c’est vraiment nécessaire. Il pourrait y avoir une meilleure manière de faire.

Voici un exemple rapide qui montre ce que l’on voit très souvent. On veut un bouton « toggleable ». (Note: Cet exemple est volontairement exagéré pour représenter les cas plus complexes qui peuvent être résolus de la même manière.)

.directive('myDirective', function() {
	return {
		template: '<a class="btn">Toggle me!</a>',
		link: function(scope, element, attrs) {
			var on = false;

			$(element).click(function() {
				if (on) {
					$(element).removeClass('active');
				} else {
					$(element).addClass('active');
				}

				on = !on;
			});
		}
	};
});

Il y a plusieurs erreurs :

  • Premièrement, jQuery n’était pas nécessaire. Il n’y a rien que l’on fait ici qui le requiert.
  • Deuxièmement, même si jQuery est importé dans notre page, il n’est pas nécessaire de l’utiliser. On peut simplement utiliser angular.element et notre composant marcherait même dans un projet qui n’utilise pas jQuery.
  • Troisièmement, même dans le cas où jQuery serait requis, jqLite (angular.element) utilisera toujours jQuery si celui-ci est chargé.
  • Quatrièmement, les éléments jqLite n’ont pas à être empaquetés dans un $, car le paramètre element de la fonction link est déjà un élément jQuery !
  • Et cinquièmement, ce que l’on disait plus haut, ne pas mélanger logique et template.

Cette directive peut être réécrite bien plus simplement (même pour des cas plus complèxes) :

.directive('myDirective', function() {
	return {
		scope: true,
		template: '<a class="btn" ng-class="{active: on}" ng-click="toggle()">Toggle me!</a>',
		link: function(scope, element, attrs) {
			scope.on = false;

			scope.toggle = function() {
				scope.on = !scope.on;
			};
		}
	};
});

Encore une fois, tout ce qui concerne le template va dans le template, de manière à ce que ça puisse être modifié facilement selon le besoin, et la logique n’aura jamais à être modifiée.

Et il y a d’autres bénéfices, comme les tests. C’est facile ! Quoi qu’il y ait dans le template, l’API interne de la directive n’est jamais touchée, donc la refactorisation est facile. On peut modifier le template autant que l’on veut sans toucher à la directive en elle-même. Et les tests passeront toujours.

w00t !

Donc si les directives ne sont pas juste un tas de commandes façon jQuery, que sont-elles ? Les directives sont en fait des extensions du HTML. Si le HTML n’a pas quelque chose dont vous avez besoin, vous n’avez qu’à écrire une directive, et l’utiliser comme si c’était du HTML.

En d’autres termes si AngularJS ne propose pas une certaine fonctionnalité, imaginez comment l’équipe Angular l’implémenterait.

Conclusion

N’utilisez pas jQuery. Ne l’importez même pas. Ça vous ralentirait. Et quand vous rencontrez un problème que vous pensez pouvoir régler avec jQuery, avant d’utiliser $, essayez plutôt de trouver une solution en Angular. Et si vous ne trouvez pas, demandez ! 19 fois sur 20, la meilleure manière de faire n’a pas besoin de jQuery.

Aprés cette introduction théorique, vous pouvez poursuivre avec un de ces deux articles :

AngularJS, par où je commence?

Démo avancée – Angular Motion

16 thoughts on “Découvrez AngularJS

  1. germander

    sympa!

  2. jeff

    Mouais… Angularjs que je pratique depuis quelques jours à l’air fabuleux. Mais même avec les outils de bootstrap, je ne vois pas comment je pourrais carrément « enlever » jquery, surtout quand on utilise Kendo UI ou JQWidgets.

    La grille, l’agenda, les composants de bouton, de tabstrip etc…. Tout est beaucoup puissant que les malheureux composants de bootstrap.

    Donc : « n’importez même pas JQuery » , et bien si, importez le ! Surtout si vous avez besoin de puissants composants dans votre application !
    Après, voilà, ne faites pas n’importe quoi… Mais cette recommandation est valable pour tout : )

  3. jeff c

    Merci pour liens, je connais déjà un peu… Regarde les démos de Kendo UI (grid et scheduler par exemple) ou encore JQwidgets, on est trèèès loin de ces composants simples. Ils proposent vraiment tous les outils pour un développement d’application de gestion complexe. Je vois AngularJS (ou KnockOutJS) comme la couche « propre » d’organisation du code javascript et bien entendu : du databinding.

    Donc me concernant je préfère m’orienter vers la lib angular-kendou, qui est un wrapper de kendo pour angular.

    J’en profite pour te féliciter sur ton site, bravo pour tes tutos, c’est idéal pour commencer ! belle initiative : )

  4. Vraiment super sympa, de très bons articles, complets et instructifs. Un grand merci pour ce boulot remarquable !

  5. Bon article, merci.
    Ca n’est pas très facile de se passer complètement de JQuery quand on y est habitué.
    Je vais essayer de forcer sur Angular tout de même

  6. Lara

    Très bon tutoriel. Dans le même cadre j’aimerais partager avec vous ce cours pour débutants et développeurs confirmé AngularJS http://goo.gl/dmHZyx
    Bonne lecture

  7. OnArap

    Je souhaiterais démarrer Angular.js et ton approche ici est tres mal choisit.

    n’essaye pas de convainre les gens, mais expique les points fort de Angular.js
    tu nous donne plus d’exemple de JQuery qu’autre chose, tu as une dent contre JQuery ou bien ?
    Ca devient de l’acharnement a un point, que c’est meme plus cool a lire, c’est dommage.

    • Jordi Maylin

      Bonjour OnArap,

      Cet article est en fait une réponse à une question posée sur StackOverflow : “Thinking in AngularJS” if I have a jQuery background?

      J’ai trouvé cette réponse intéressante, parce que la plupart des gens (moi y compris) ont appris le Javascript avec jQuery. Et il est très dur d’entrer dans l’esprit AngularJS si on ne se détache pas de l’esprit jQuery.

      L’article était un peu théorique. Si tu veux quelque chose de plus concret, je te conseille plutôt celui-ci http://www.angular-js.fr/angularjs-par-ou-je-commence/

  8. Ouais ça pête ton article, trop vrai

  9. cool

  10. ahmado

    y-a il des composants web comme primeface sur angularJS

  11. Marauder

    Article intéressant au moment où je suis justement confronté à des choix dans une application.
    JQuery/Angular/Les 2 ?
    Je pense créer des composants indépendant en JQuery et les intégrer ensuite dans l’application via de l’Angular.
    Cette approche vous semble t elle correcte ?
    Peut on développer des composants évolués réutilisables en Angular ?
    Peut on les intégrer ensuite sur une même page sans conflits facilement ? Comment vont cohabiter les nombreux contrôleurs & vues ?
    Bref peut on vraiment tout faire avec angular?

    • Jordi Maylin

      Bonjour Marauder,

      Pour voir le lien entre jQuery et Angular, je t’invite à lire cet article http://www.angular-js.fr/decouvrez-angularjs/, mais globalement il faut éviter de résonner en jQuery quand on fait de l’Angular. Les « composants réutilisables » en Angular s’appellent les directives.

      Si tu n’a pas encore commencé ton projet, tu peux aussi te renseigner sur le framework ReactJs, très orienté vers les composants réutilisables justement, ou bien Angular 2, encore en beta.

      Bonne chance

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>