Angularjs
Junior
Quiz-Angularjs-Junior
Angularjs-Services
Factory
Ngroute
Directives-Personnalisees
Promises-Q
Watch-Apply
Questions-Entretien-Angularjs-Junior
Qcm-Angularjs-Junior
Javascript
Legacy-Frontend
Intercepteurs-Http
📝
AngularJS — Entretien Junior
20 questions AngularJS niveau Junior : services, factory, provider, routage ngRoute, directives personnalisées, $q, $watch, validation de formulaires et intercepteurs HTTP.
Banque de révision : les 60 questions corrigées
Voici l'intégralité des 60 questions de « AngularJS — Entretien Junior », chacune avec sa bonne réponse et son explication. Le quiz interactif ci-dessus en tire une sélection aléatoire à chaque tentative — utilisez cette liste complète pour réviser.
Explication :
Avec
.service(), Angular instancie la fonction avec new et injecte l'instance — this est l'objet injecté. Avec .factory(), Angular appelle la fonction et injecte ce qu'elle retourne. La factory offre plus de contrôle sur l'objet créé.
Règle mnémotechnique : Service = new MaClasse(), Factory = return monObjet. En pratique, les deux peuvent tout faire. La factory est légèrement plus flexible.
Explication :
Le
Provider est le type le plus bas niveau. Il expose obligatoirement une méthode $get (équivalente à la factory) et est le seul injectable dans la phase .config(). Il permet de configurer le service avant l'instanciation de l'application.
Explication :
Le routage ngRoute se configure dans la phase
.config() du module via $routeProvider : app.config(function($routeProvider) {\n $routeProvider\n .when("/home", { templateUrl: "home.html", controller: "HomeCtrl" })\n .otherwise({ redirectTo: "/home" });\n});
La phase config() s'exécute avant le démarrage de l'application. C'est le seul endroit où on peut injecter des Providers (pas des instances de services).
Explication :
ng-view est le placeholder dans le HTML principal où ngRoute injecte les templates correspondant à la route active. Exemple : <div ng-view></div>. Un seul ng-view par application est supporté par ngRoute (contrairement à ui-router qui supporte plusieurs vues nommées).
Explication :
Le service
$routeParams expose les paramètres de la route active. Pour une route définie avec /user/:id, on accède à l'ID avec $routeParams.id. Il faut injecter $routeParams dans le contrôleur.
Explication :
$scope.$watch("expression", callback) enregistre un observateur sur une expression du scope. Le callback est appelé quand la valeur change lors d'un cycle $digest. Il prend les arguments (newValue, oldValue). Attention : chaque $watch ajoute un watcher au cycle digest.
Toujours dé-enregistrer les watchers dans $destroy pour éviter les memory leaks : var unwatch = $scope.$watch(...); $scope.$on("$destroy", unwatch);
Explication :
$watch() par défaut compare les références. Pour les tableaux/objets, ajouter true comme 3ème argument force une comparaison profonde (coûteux). $watchCollection() est un compromis : il détecte les changements de premier niveau dans les collections (ajout/suppression/réorganisation) sans comparaison profonde complète.
Explication :
$scope.$apply() déclenche manuellement le cycle $digest. Nécessaire quand on modifie le scope depuis un code externe à Angular (setTimeout natif, event listeners jQuery, callbacks de bibliothèques tierces). Les directives AngularJS et $timeout le font automatiquement.
Préférez toujours $timeout à window.setTimeout — $timeout appelle $apply automatiquement. Si vous devez utiliser $apply, enveloppez dans $apply(function() { }) pour bénéficier de la gestion d'erreurs.
Explication :
$apply() appelle $rootScope.$digest() — il déclenche le cycle sur toute la hiérarchie de scopes. $digest() ne traite que le scope courant et ses enfants. Préférez $apply() pour garantir que tout le modèle est synchronisé.
Explication :
On crée une directive avec
app.directive("camelCase", function() { return { restrict: "E", template: "...", ... }; }). Le nom en camelCase est automatiquement converti en kebab-case dans le HTML : monDirective → <mon-directive>.
La propriété "restrict" définit comment la directive peut être utilisée : "E" (élément), "A" (attribut), "C" (classe CSS), "M" (commentaire). "EA" est la combinaison la plus courante.
Explication :
La propriété
restrict contrôle comment la directive peut être déclarée dans le HTML : "E" = élément <mon-dir>, "A" = attribut <div mon-dir>, "C" = classe <div class="mon-dir">. "EA" combine les deux premiers.
Explication :
Un scope isolé (
scope: {}) crée un scope propre à la directive qui n'hérite pas prototypiquement du scope parent. On y passe des données explicitement via les bindings : "@" (string), "=" (two-way), "&" (callback/expression).
Le scope isolé est la bonne pratique pour les directives réutilisables. Il évite les dépendances cachées sur le scope parent et rend la directive portable.
Explication :
Dans
scope: { titre: "@" }, le binding "@" lit la valeur de l'attribut HTML comme une chaîne (après interpolation). "=" = two-way binding avec le scope parent. "&" = binding d'expression (callback). "<" = one-way binding (depuis AngularJS 1.5).
Explication :
compile s'exécute une seule fois sur le template avant sa duplication (utile pour ng-repeat). link s'exécute pour chaque instance de la directive. En pratique, utilisez link pour tout sauf les transformations de template pures (sans scope).
Quand compile retourne un objet {pre, post}, pre-link s'exécute avant les enfants, post-link (= link standard) après. L'ordre permet de contrôler l'initialisation.
Explication :
$q est le service de Promises d'AngularJS, inspiré de la bibliothèque Q. Il fournit $q.defer() (crée une promesse manuelle), $q.all() (attend plusieurs promesses), $q.when() (wrape une valeur en promesse), $q.reject().
Explication :
On utilise
$q.defer() pour créer un objet deferred : var d = $q.defer(). On résout avec d.resolve(valeur), on rejette avec d.reject(erreur), on notifie avec d.notify(update). On retourne d.promise pour que le consommateur y attache des callbacks.
Pattern typique dans un service : function getData() { var d = $q.defer(); $http.get(url).then(function(r) { d.resolve(r.data) }, function(e) { d.reject(e) }); return d.promise; }
Explication :
On crée un filtre avec
app.filter("nom", function() { return function(input, param1) { return output; }; }). La fonction externe peut recevoir des dépendances injectées. La fonction interne reçoit la valeur à filtrer et les paramètres optionnels.
Explication :
Un intercepteur est un service avec les méthodes
request, requestError, response, responseError. On l'enregistre dans .config() via $httpProvider.interceptors.push("NomIntercepteur"). Utile pour ajouter des headers d'auth, logger les erreurs, etc.
Pattern courant : ajouter le token JWT dans request, rediriger vers /login si responseError retourne 401.
Explication :
$q.all([promise1, promise2, promise3]) retourne une nouvelle promise qui se résout quand toutes les promises du tableau sont résolues. Si une seule est rejetée, $q.all est rejeté. Le résultat est un tableau des valeurs résolues dans le même ordre.
Explication :
Plusieurs approches : 1) Service partagé (recommandé) — le service étant un singleton, toutes ses propriétés sont partagées. 2) $rootScope — accessible partout mais pollue le scope global. 3) Événements —
$broadcast/$emit/$on pour la communication découplée.
Privilégiez toujours le service partagé. $rootScope doit être un dernier recours. Trop d'événements rend le flux de données difficile à tracer.
Explication :
La propriété
resolve permet de précharger des données avant l'activation d'une route. Angular attend la résolution de toutes les promises avant d'instancier le contrôleur. Les données résolues sont injectables directement dans le contrôleur par leur clé.
C'est très utile pour éviter l'affichage d'une vue vide avant le chargement des données.
Explication :
$scope.$watchGroup(["expr1", "expr2"], callback) observe plusieurs expressions simultanément. Le callback reçoit deux tableaux : newValues et oldValues avec les valeurs correspondantes. Plus lisible que plusieurs $watch séparés.
Explication :
$timeout(fn, delay) est l'équivalent Angular de window.setTimeout. Il déclenche automatiquement $apply après l'exécution du callback. Utiliser window.setTimeout directement nécessiterait un $apply manuel pour que les changements de scope soient reflétés.
Explication :
AngularJS intègre la validation HTML5.
<input type="email" ng-model="email"> active automatiquement la validation email. L'état est exposé via formName.fieldName.$error.email. Similairement pour type="url", type="number".
Accédez aux états de validation : form.email.$valid, form.email.$invalid, form.email.$dirty, form.email.$touched, form.email.$error.email.
Explication :
AngularJS expose l'état du formulaire via
formName.$valid, formName.$invalid, formName.$dirty, formName.$pristine. Le nom du formulaire correspond à l'attribut name de la balise <form>.
Explication :
Ces états reflètent l'interaction utilisateur :
$pristine (true si l'utilisateur n'a pas encore touché au champ), $dirty (true si le champ a été modifié). $touched devient true dès que l'utilisateur a cliqué dans le champ (même sans le modifier).
Utilisez $dirty pour n'afficher les erreurs de validation qu'après interaction : ng-show="form.email.$dirty && form.email.$invalid".
Explication :
Dans la phase
.config() : $httpProvider.defaults.headers.common["Authorization"] = "Bearer " + token. Dans le run (runtime) : $http.defaults.headers.common["Authorization"] = "Bearer " + token. Le premier permet de configurer avant tout démarrage, le second après.
Explication :
La phase
.run() s'exécute après la phase .config(), quand tous les services sont disponibles. Contrairement à .config() (Providers uniquement), .run() peut injecter des instances de services. Utilisé pour initialiser l'application : authentification, configuration, event listeners globaux.
Ordre d'exécution : config() → run() → contrôleurs. En run(), vous pouvez accéder à $rootScope pour définir des données globales.
Explication :
Le filtre
limitTo combiné avec un offset permet la pagination : ng-repeat="item in items | limitTo:pageSize:currentPage*pageSize". Le deuxième argument de limitTo est l'index de début.
Explication :
On surcharge
$exceptionHandler avec un décorateur : app.decorator("$exceptionHandler", function($delegate, $injector) { return function(exception, cause) { /* log */ $delegate(exception, cause); }; }). C'est le point central pour logger toutes les exceptions AngularJS.
Les intercepteurs $http gèrent les erreurs HTTP. $exceptionHandler gère les exceptions JavaScript dans les contrôleurs et services.
Explication :
ng-cloak est utilisée avec une règle CSS qui masque les éléments [ng-cloak]. Quand AngularJS compile le template, il retire cet attribut, révélant l'élément. Similaire à ng-bind, c'est une solution anti-FOUC pour les sections entières.
Explication :
$rootScope est le scope racine de l'application — tous les scopes héritent prototypiquement de lui. Il est accessible partout et persiste toute la durée de vie de l'application. Son utilisation doit être limitée car c'est un état global partagé.
N'abusez pas de $rootScope. Utilisez-le uniquement pour des données vraiment globales (utilisateur connecté, locale, thème). Pour le reste, préférez les services.
Explication :
$timeout.cancel(promise) annule un timeout en cours. La méthode $timeout() retourne une promise — on la passe à $timeout.cancel() pour annuler. Similairement, $interval.cancel(promise) annule un interval.
Explication :
Pattern typique : 1) Login → reçoit JWT → stocke dans
localStorage. 2) Un intercepteur $http ajoute Authorization: Bearer <token> à chaque requête. 3) La propriété resolve des routes vérifie l'authentification. 4) L'intercepteur responseError redirige sur 401.
localStorage persiste après fermeture. sessionStorage dure la session. Choisissez selon vos besoins. Pour une sécurité maximale, stockez le token en mémoire (mais il sera perdu au rechargement).
Explication :
Le service
$location encapsule window.location. Il expose : $location.path() (chemin actuel), $location.search() (paramètres de query), $location.hash(), $location.host(). Modifier $location.path("/nouvelle-route") navigue sans rechargement.
Explication :
AngularJS n'a pas de support natif du lazy loading. Des bibliothèques tierces comme
ocLazyLoad permettent de charger des modules à la demande. On peut aussi utiliser RequireJS ou Webpack avec des points de code splitting.
C'est une limitation majeure d'AngularJS qui a été résolue dans Angular 2+ avec le lazy loading natif des modules.
Explication :
ng-pluralize affiche des textes différents selon une valeur numérique, avec support des règles de pluralisation. Exemple : ng-pluralize count="nb" when="{'0': 'Aucun article', 'one': 'Un article', 'other': '{} articles'}".
Explication :
track by permet à AngularJS d'identifier les éléments d'un tableau par une clé stable : ng-repeat="item in items track by item.id". Sans track by, Angular recrée tout le DOM lors de chaque mise à jour. Avec, il réutilise les éléments existants, améliorant fortement les performances.
C'est une optimisation critique pour les grandes listes. Sans track by, ng-repeat crée et détruit le DOM à chaque $digest si le tableau change, même pour une petite modification.
Explication :
La notation tableau
["$http", function($http) {}] annote explicitement les dépendances. Un minificateur renomme les paramètres ($http → a), cassant la résolution par nom. La notation tableau préserve les noms en chaînes non renommables. Alternative : MonService.$inject = ["$http"].
Explication :
Pour naviguer programmatiquement avec ngRoute, on modifie
$location.path("/nouveau-chemin"). Angular détecte le changement et charge la route correspondante. Pour ui-router, on utilise $state.go("nom-etat").
Ne jamais utiliser window.location.href — cela rechargera toute l'application. $location est intégré au cycle digest.
Explication :
Le service
$log est un wrapper autour de console. Il expose $log.log(), $log.info(), $log.warn(), $log.error(), $log.debug(). Avantage : on peut le mocker facilement dans les tests.
Explication :
Le module
ngAnimate (dépendance séparée) intercepte les directives structurelles (ng-if, ng-show, ng-repeat, etc.) et ajoute des classes CSS pendant les transitions. Exemple : définir .my-class.ng-enter, .my-class.ng-enter.ng-enter-active suffit pour animer ng-repeat.
ngAnimate ajoute automatiquement les classes ng-enter, ng-leave, ng-move, ng-hide, ng-show selon l'état de la directive. Définissez les transitions CSS correspondantes.
Explication :
ng-form crée un sous-formulaire imbriqué avec son propre état de validation ($valid, $dirty, etc.). L'imbrication de balises <form> est invalide en HTML, donc ng-form permet de valider des sections indépendantes d'un formulaire plus large.
Explication :
Tous les services AngularJS sont des singletons : ils sont instanciés une seule fois à leur première injection et la même instance est réutilisée partout. Aucune configuration supplémentaire n'est nécessaire. L'initialisation peut se faire dans le constructeur (service) ou dans la valeur de retour (factory).
Profitez du pattern singleton pour stocker des états partagés. C'est la base de la gestion d'état dans les applications AngularJS.
Explication :
Avec ngMock :
var $controller; beforeEach(inject(function(_$controller_) { $controller = _$controller_; })); it("test", function() { var scope = $rootScope.$new(); var ctrl = $controller("MonCtrl", { $scope: scope }); expect(scope.valeur).toBe("..."); });
Explication :
La syntaxe
{{ ::expression }} (double deux-points) crée une liaison one-time : l'expression est évaluée une fois, le DOM est mis à jour, et le watcher est supprimé. Idéal pour les données statiques — réduit le nombre de watchers et améliore les performances.
Utilisez :: pour toutes les données qui ne changent pas après le premier rendu : titres, labels, données de référence. Peut réduire les watchers de 50%+ dans une grosse application.
Explication :
ngResource ($resource) fournit une abstraction de haut niveau pour interagir avec des APIs RESTful. Il génère automatiquement les méthodes CRUD : query(), get(), save(), delete(). Utile pour simplifier les interactions avec une API REST standard.
Explication :
AngularJS 1.3+ supporte
ng-model-options="{ debounce: 300 }" qui retarde la mise à jour du modèle de 300ms après la dernière frappe. Alternativement, un $timeout annulé à chaque frappe dans ng-change implémente le même comportement manuellement.
ng-model-options est la solution la plus propre. Utilisez aussi updateOn: "blur" pour ne mettre à jour le modèle qu'au blur.
Explication :
$scope.$destroy() retire le scope de la hiérarchie de scopes, supprime tous ses watchers et event listeners pour libérer la mémoire. AngularJS appelle cela automatiquement quand ng-if ou le routeur détruit un composant. L'événement $destroy est émis avant la destruction.
Explication :
$http.get(url, { cache: true }) utilise le cache par défaut $http. Pour un cache personnalisé : var cache = $cacheFactory("monCache"); $http.get(url, { cache: cache }). La première requête est mise en cache, les suivantes utilisent la version en cache.
Utile pour les ressources statiques (listes de référence, config). Pensez à invalider le cache après les mutations (POST/PUT/DELETE).
Explication :
Pour utiliser un filtre dans un contrôleur, injectez
$filter et appelez : $filter("nomFiltre")(valeur, param). Exemple : $filter("currency")(prix, "€"). On peut aussi injecter directement le filtre avec le suffixe "Filter" : app.controller("C", function(uppercaseFilter) { uppercaseFilter("text"); }).
Explication :
withCredentials: true indique au navigateur d'inclure les cookies, l'autorisation HTTP et les certificats client TLS dans les requêtes cross-origin (CORS). Le serveur doit répondre avec Access-Control-Allow-Credentials: true et une origine spécifique (pas *).
Explication :
AngularJS diffuse des événements de routage sur le
$rootScope : $routeChangeStart (avant navigation), $routeChangeSuccess (après navigation réussie), $routeChangeError (erreur). On les écoute avec $scope.$on("$routeChangeSuccess", fn).
Explication :
Pattern store AngularJS : un service factory avec un objet état privé, des méthodes get/set, et un broadcast pour notifier les changements. Les contrôleurs s'abonnent via
$scope.$on("storeUpdated", fn). Simple alternative à Redux pour les petites apps.
Pour les grandes applications, des librairies comme ngRedux portent le pattern Redux sur AngularJS.
Explication :
AngularJS utilise
$sce (Strict Contextual Escaping) pour protéger contre les injections. ng-bind-html requiert une valeur marquée comme sûre. $sce.trustAsHtml(htmlString) bypass cette protection — à utiliser uniquement pour du HTML dont vous contrôlez la source.
Explication :
AngularJS 1.5+ a introduit
.component() et le ngComponentRouter (déprécié) pour préparer la migration vers Angular 2+. Les composants (.component()) sont des directives simplifiées qui utilisent toujours controllerAs, ont un scope isolé par défaut et un lifecycle hook explicite.
Si vous maintenez une application AngularJS, migrez d'abord vers les composants .component() — c'est la première étape vers la migration Angular 2+.
Explication :
Le binding
"&" dans le scope isolé permet d'exprimer une référence à une expression du scope parent, typiquement une fonction. Dans le template parent : <ma-directive on-action="parentFn(param)">. Dans la directive : scope.onAction({ param: valeur }).
Explication :
ui-router est basé sur des états (pas des URLs) et supporte : vues nommées multiples (ui-view="nom"), états imbriqués, transitions d'état. ngRoute est plus simple, basé sur les URLs, avec un seul ng-view. Pour les SPA complexes, ui-router est généralement préféré.
ui-router est tiers (non officiel Angular) mais est devenu le standard de facto pour les applications complexes. C'est aujourd'hui une question courante d'entretien.
Explication :
AngularJS supporte JSONP via
$http.jsonp(url, { jsonpCallbackParam: "callback" }). Il injecte automatiquement un nom de callback dans l'URL et le nettoie après. Depuis AngularJS 1.6, la configuration de $sce est requise pour autoriser les URLs JSONP.
Explication :
Stratégies d'optimisation pour ng-repeat : 1)
track by item.id — évite la recréation DOM. 2) :: binding — supprime les watchers des données statiques. 3) Pagination ou virtual scroll (ng-virtual-scroll) — limite le nombre d'éléments dans le DOM. 4) $watchCollection au lieu de deep watch.
La règle des 2000 watchers : une application fluide devrait avoir moins de 2000 watchers actifs. Comptez avec $rootScope.$$watchersCount en dev.