Préparation d'entretien 100% Gratuit angularforall.com

AngularJS — Entretien Junior

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
Intermédiaire 🔀 Mixte 20 questions ⏱ 15 min
📝

AngularJS — Entretien Junior

20 questions AngularJS niveau Junior : services, factory, provider, routage ngRoute, directives personnalisées, $q, $watch, validation de formulaires et intercepteurs HTTP.

20 questions ⏱ ~15 min Niveau Intermédiaire

Partager

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.

  • Il n'y a aucune différence fonctionnelle entre les deux
  • Service utilise une fonction constructeur (new), Factory retourne un objet explicitement (bonne réponse)
  • Factory est plus rapide que Service
  • Service est déprécié depuis AngularJS 1.4
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.

  • Un Provider ne peut pas être injecté dans un contrôleur
  • Un Provider expose une méthode $get et peut être configuré dans la phase config() (bonne réponse)
  • Un Provider est uniquement pour les requêtes HTTP
  • Un Provider est moins puissant qu'une Factory
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.

  • En utilisant $routeConfig dans le contrôleur principal
  • En appelant $routeProvider.when() dans la phase .config() (bonne réponse)
  • En ajoutant des attributs ng-route sur les balises <a>
  • En déclarant les routes dans le module avec .routes()
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).

  • ng-route
  • ng-view (bonne réponse)
  • router-outlet
  • ng-template
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).

  • $route.params.id
  • $location.params().id
  • $routeParams.id (bonne réponse)
  • $params.id
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.

  • Il surveille les requêtes HTTP entrantes
  • Il enregistre un watcher qui exécute un callback quand une expression change (bonne réponse)
  • Il met en pause le cycle $digest
  • Il observe les modifications du DOM
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);

  • $watchCollection est déprécié depuis AngularJS 1.3
  • $watchCollection détecte l'ajout/suppression d'éléments dans un tableau ou objet (bonne réponse)
  • $watch et $watchCollection sont identiques
  • $watchCollection ne fonctionne qu'avec les tableaux
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.

  • Pour appliquer des styles CSS au scope
  • Pour déclencher manuellement le cycle $digest après une opération asynchrone externe (bonne réponse)
  • Pour initialiser les propriétés du scope
  • Pour partager le scope entre plusieurs contrôleurs
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.

  • Ils sont identiques et interchangeables
  • $apply déclenche le digest sur le $rootScope entier, $digest seulement sur le scope courant (bonne réponse)
  • $digest est plus sécurisé car il gère les erreurs
  • $apply est déprécié depuis AngularJS 1.5
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é.

  • app.directive("monDirective", function() { return {} }) (bonne réponse)
  • app.createDirective("monDirective", {})
  • angular.directive("monDirective", function() {})
  • ng-directive="monDirective" dans le HTML
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.

  • La directive est restreinte aux éléments Angular seulement
  • La directive peut être utilisée comme élément ET comme attribut (bonne réponse)
  • EA signifie "Extended Attribute"
  • La directive est expérimentale et asynchrone
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.

  • Un scope qui ne peut pas être modifié
  • Un scope propre à la directive qui n'hérite pas du scope parent (bonne réponse)
  • Un scope accessible uniquement en mode debug
  • Un scope partagé entre toutes les instances de la directive
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.

  • Binding bidirectionnel (two-way)
  • Binding de callback/expression
  • Binding d'attribut en tant que chaîne de caractères (bonne réponse)
  • Binding asynchrone
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).

  • compile s'exécute une fois pour modifier le DOM avant clonage, link s'exécute pour chaque instance (bonne réponse)
  • link est plus rapide que compile dans tous les cas
  • compile gère les événements, link gère le template
  • Il n'y a pas de différence — utiliser l'un ou l'autre revient au même
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.

  • Un service de gestion des requêtes HTTP
  • Le service de gestion des Promises d'AngularJS (bonne réponse)
  • Un filtre pour les opérations asynchrones
  • L'objet de configuration globale
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().

  • return new Promise(resolve => resolve(data))
  • var d = $q.defer(); d.resolve(data); return d.promise (bonne réponse)
  • $q.create().resolve(data)
  • $q(function(resolve) { resolve(data) })
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; }

  • app.filter("monFiltre", function() { return function(input) { return output; } }) (bonne réponse)
  • app.createFilter("monFiltre", function(input) { return output })
  • $filter.create("monFiltre", function(input) {})
  • angular.filter("monFiltre", function(input) {})
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.

  • En ajoutant une fonction à $http.interceptors
  • En créant un service avec les méthodes request/response et en l'ajoutant à $httpProvider.interceptors dans .config() (bonne réponse)
  • En utilisant ng-interceptor dans le template
  • En surchargeant $http dans le contrôleur
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.

  • Il résout la première promise qui se termine
  • Il attend que toutes les promises du tableau se résolvent (bonne réponse)
  • Il crée une promise qui se résout immédiatement
  • Il annule toutes les promises en cours
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.

  • Uniquement via le $rootScope
  • Via un service singleton partagé ou $rootScope ou événements $broadcast/$emit (bonne réponse)
  • En passant les données dans les paramètres d'URL uniquement
  • En utilisant ng-model avec un nom identique dans les deux contrôleurs
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.

  • Elle définit l'URL de redirection en cas d'erreur
  • Elle charge des données asynchrones AVANT l'activation de la route (bonne réponse)
  • Elle résout les conflits entre routes similaires
  • Elle définit les paramètres obligatoires de la route
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.

  • Il observe un groupe de scopes enfants
  • Il observe plusieurs expressions et exécute le callback si l'une d'elles change (bonne réponse)
  • Il regroupe plusieurs watchers en un seul pour la performance
  • Il est identique à plusieurs $watch() séparés
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.

  • window.setTimeout
  • $timer
  • $timeout (bonne réponse)
  • $interval.once
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.

  • En ajoutant ng-validate="email" sur le champ
  • En utilisant le type HTML5 type="email" — Angular le détecte automatiquement (bonne réponse)
  • En créant un filtre personnalisé
  • En appelant $scope.validateEmail()
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.

  • $form.$valid
  • formName.$valid (bonne réponse)
  • ng-form.valid
  • $scope.form.isValid
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>.

  • $pristine = valide, $dirty = invalide
  • $pristine = champ non modifié, $dirty = champ modifié par l'utilisateur (bonne réponse)
  • $pristine = vide, $dirty = contient du texte
  • $pristine = nouveau champ, $dirty = champ existant
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".

  • $http.defaults.headers.common["Authorization"] = token
  • $httpProvider.defaults.headers.common["Authorization"] = token dans .config() (bonne réponse)
  • $http.setHeader("Authorization", token)
  • ng-headers="{Authorization: token}" sur chaque requête
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.

  • La phase de compilation des templates
  • Une phase qui s'exécute après la configuration et l'injection de dépendances (bonne réponse)
  • La phase de destruction de l'application
  • Le point d'entrée pour créer des routes
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.

  • En utilisant le service $paginate
  • En combinant ng-repeat avec les filtres limitTo et un index de page (bonne réponse)
  • En chargeant chaque page avec $http.get()
  • En utilisant ng-paginate dans le template
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.

  • En utilisant window.onerror
  • En surchargeant le service $exceptionHandler (bonne réponse)
  • En ajoutant try/catch dans chaque contrôleur
  • En utilisant ng-error dans le template
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.

  • Elle chiffre les données affichées
  • Elle masque l'élément jusqu'à ce qu'Angular ait compilé le template (anti-FOUC) (bonne réponse)
  • Elle crée un overlay sur l'élément
  • Elle désactive les animations
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.

  • Le scope du contrôleur principal
  • Le scope ancêtre de tous les scopes dans l'application (bonne réponse)
  • L'objet de configuration globale
  • Le scope accessible uniquement dans les services
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.

  • clearTimeout(timeoutRef)
  • $timeout.clear(timeoutRef)
  • $timeout.cancel(timeoutRef) (bonne réponse)
  • timeoutRef.cancel()
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.

  • En utilisant le service $auth
  • En stockant le token dans localStorage et en l'ajoutant via un intercepteur HTTP (bonne réponse)
  • En passant le token dans chaque requête ng-click
  • En utilisant ng-auth sur les routes protégées
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).

  • $url
  • $router
  • $location (bonne réponse)
  • $path
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.

  • AngularJS supporte nativement le lazy loading via ng-lazy
  • En utilisant ocLazyLoad ou RequireJS avec des hooks AngularJS (bonne réponse)
  • En définissant les modules avec defer: true
  • Le lazy loading n'est pas possible avec AngularJS
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.

  • Elle pluralise automatiquement les mots en anglais
  • Elle affiche différents textes selon la valeur numérique (internationalisation des pluriels) (bonne réponse)
  • Elle compte le nombre d'éléments dans un ng-repeat
  • Elle traduit les chaînes de caractères
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'}".

  • Une façon de trier les éléments ng-repeat par un champ
  • Un mécanisme pour éviter la recréation DOM lors des mises à jour de tableau (bonne réponse)
  • Un filtre pour suivre les modifications d'un tableau
  • Un service de debugging pour ng-repeat
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.

  • app.service("MonService", function($http) {})
  • app.service("MonService", ["$http", function($http) {}]) (bonne réponse)
  • Les deux précédentes sont équivalentes pour la minification
  • app.service("MonService", {$inject: ["$http"], fn: function($h) {}})
Explication : La notation tableau ["$http", function($http) {}] annote explicitement les dépendances. Un minificateur renomme les paramètres ($httpa), cassant la résolution par nom. La notation tableau préserve les noms en chaînes non renommables. Alternative : MonService.$inject = ["$http"].

  • $router.navigate("/chemin")
  • $location.path("/chemin") (bonne réponse)
  • $route.go("/chemin")
  • window.location.href = "/chemin"
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.

  • $console
  • $logger
  • $log (bonne réponse)
  • $debug
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.

  • En utilisant ng-animation sur les éléments
  • En ajoutant ngAnimate comme dépendance et en définissant des transitions CSS sur les classes ng-* (bonne réponse)
  • En écrivant des animations JavaScript dans ng-click
  • AngularJS ne supporte pas les animations
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.

  • Elle remplace la balise &lt;form&gt; HTML standard
  • Elle permet d'imbriquer des formulaires et d'obtenir leur état de validation séparément (bonne réponse)
  • Elle désactive la validation HTML5 native
  • Elle soumet automatiquement le formulaire
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.

  • En utilisant app.singleton("nom", fn)
  • Les services AngularJS sont déjà des singletons par nature (bonne réponse)
  • En ajoutant ng-init="serviceInit()" dans le template racine
  • En utilisant app.config() pour initialiser le service
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.

  • En instanciant directement new MonCtrl($scope)
  • En utilisant inject() et $controller() pour instancier le contrôleur avec un $scope de test (bonne réponse)
  • En utilisant angular.test.controller()
  • Les contrôleurs ne peuvent pas être testés unitairement
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("..."); });

  • Une liaison qui se brise après la première modification
  • Une liaison qui s'évalue une fois et ne crée pas de watcher permanent (bonne réponse)
  • Un pattern de composant qui ne peut être monté qu'une fois
  • Une liaison uniquement disponible dans les directives
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.

  • ngHttp
  • ngResource (bonne réponse)
  • ngRest
  • ngApi
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.

  • En utilisant ng-debounce sur l'input
  • En ajoutant ng-model-options="{debounce: 300}" sur l'input
  • En utilisant $timeout manuellement dans ng-change
  • Les deux dernières options fonctionnent (bonne réponse)
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.

  • Elle détruit le contrôleur associé
  • Elle supprime le scope de la hiérarchie et nettoie ses watchers (bonne réponse)
  • Elle efface les données du localStorage
  • Elle réinitialise le scope à son état initial
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.

  • En utilisant ng-cache sur les requêtes
  • En passant cache: true ou un objet $cacheFactory dans la config de $http (bonne réponse)
  • En utilisant $http.cache.enable()
  • AngularJS ne supporte pas le cache HTTP
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).

  • $filter.apply("uppercase", valeur)
  • $filter("uppercase")(valeur) (bonne réponse)
  • angular.filter("uppercase")(valeur)
  • $filters.uppercase(valeur)
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"); }).

  • Il ajoute les credentials Basic Auth à la requête
  • Il envoie les cookies et headers d'auth dans les requêtes cross-origin (CORS) (bonne réponse)
  • Il active le chiffrement de la requête
  • Il force l'authentification par certificat
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 *).

  • $route.on("routeChange", fn)
  • $scope.$on("$routeChangeSuccess", function(event, current) {}) (bonne réponse)
  • $location.watch("change", fn)
  • ng-route-change="fn()"
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).

  • En utilisant $rootScope directement
  • En créant un service singleton avec des getters/setters et notification par $rootScope.$broadcast (bonne réponse)
  • En utilisant ng-store
  • AngularJS ne supporte pas la gestion d'état
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.

  • Il encode le HTML pour éviter les attaques XSS
  • Il marque une chaîne HTML comme sûre pour ng-bind-html (bonne réponse)
  • Il valide la syntaxe HTML
  • Il convertit du Markdown en HTML
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.

  • Un remplaçant de ngRoute basé sur les composants, préparant la migration vers Angular 2 (bonne réponse)
  • Un router pour les Web Components
  • La même chose que ngRoute avec une nouvelle syntaxe
  • Un système de routage uniquement pour les applications mobiles
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+.

  • scope: { onAction: "=" }
  • scope: { onAction: "&" } (bonne réponse)
  • scope: { onAction: "@" }
  • scope: { onAction: "
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 }).

  • ui-router est officiel, ngRoute est tiers
  • ui-router supporte plusieurs vues nommées et des états imbriqués, ngRoute ne supporte qu'une vue (bonne réponse)
  • ngRoute est plus performant que ui-router
  • Il n'y a pas de différence significative
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.

  • $jsonp
  • $http avec jsonpCallbackParam (bonne réponse)
  • $resource en mode JSONP
  • Ce n'est pas supporté par AngularJS
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.

  • En augmentant la limite de watchers dans la config
  • En combinant track by, one-time binding (::), $watchCollection et pagination/virtual scroll (bonne réponse)
  • En remplaçant ng-repeat par du DOM manipulation jQuery
  • En désactivant le $digest pour cette partie de la page
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.