Recherche…


La liaison de données bidirectionnelle cesse de fonctionner

On devrait avoir en tête que:

  1. La liaison de données d'Angular s'appuie sur l'héritage prototypique de JavaScript, donc sujet à l' observation de variables .
  2. Une portée enfant hérite normalement de sa portée parent. Une exception à cette règle est une directive qui a une portée isolée car elle n’hérite pas de manière prototypique.
  3. Il existe certaines directives qui créent une nouvelle portée enfant: ng-repeat , ng-switch , ng-view , ng-if , ng-controller , ng-include , etc.

Cela signifie que lorsque vous essayez de lier certaines données à une primitive située à l'intérieur d'une étendue enfant (ou vice versa), les choses risquent de ne pas fonctionner comme prévu. Voici un exemple de la facilité avec laquelle "casser" AngularJS.

Ce problème peut facilement être évité en suivant ces étapes:

  1. Avoir un "." à l'intérieur de votre modèle HTML à chaque fois que vous liez des données
  2. Utiliser la syntaxe controllerAs pour promouvoir l'utilisation de la liaison à un objet "pointillé"
  3. $ parent peut être utilisé pour accéder aux variables de scope parent plutôt qu'à la portée enfant. comme dans ng-if on peut utiliser ng-model="$parent.foo" ..

Une alternative à ce qui précède consiste à lier ngModel à une fonction getter / setter qui mettra à jour la version mise en cache du modèle lorsqu'elle est appelée avec des arguments, ou la renverra lorsqu'elle sera appelée sans arguments. Pour utiliser une fonction getter / setter, vous devez ajouter ng-model-options="{ getterSetter: true }" à l'élément avec l'attribut ngModal et appeler la fonction getter si vous souhaitez afficher sa valeur dans l'expression ( Exemple de travail ).

Exemple

Vue:

<div ng-app="myApp" ng-controller="MainCtrl">
    <input type="text" ng-model="foo" ng-model-options="{ getterSetter: true }">
    <div ng-if="truthyValue">
        <!-- I'm a child scope (inside ng-if), but i'm synced with changes from the outside scope -->
        <input type="text" ng-model="foo">
    </div>
    <div>$scope.foo: {{ foo() }}</div>
</div>

Manette:

angular.module('myApp', []).controller('MainCtrl', ['$scope', function($scope) {
    $scope.truthyValue = true;
      
    var _foo = 'hello'; // this will be used to cache/represent the value of the 'foo' model 
      
    $scope.foo = function(val) {
        // the function return the the internal '_foo' varibale when called with zero arguments,
        // and update the internal `_foo` when called with an argument
        return arguments.length ? (_foo = val) : _foo;
    };
}]);

Meilleure pratique : Il est préférable de garder les lecteurs rapidement car Angular est susceptible de les appeler plus fréquemment que les autres parties de votre code ( référence ).

Choses à faire lors de l'utilisation de html5Mode

Lorsque vous utilisez html5Mode([mode]) il est nécessaire que:

  1. Vous spécifiez l'URL de base de l'application avec un <base href=""> dans la tête de votre index.html .

  2. Il est important que la balise de base vienne avant les balises contenant des requêtes URL. Sinon, cela pourrait entraîner cette erreur - "Resource interpreted as stylesheet but transferred with MIME type text/html" . Par exemple:

    <head>
        <meta charset="utf-8">
        <title>Job Seeker</title>
    
        <base href="/">
    
        <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="/styles/main.css">
    </head>
    
  3. Si vous ne voulez pas spécifier une balise de base , configurez $locationProvider pour ne pas exiger base balise de base en transmettant un objet définition avec requireBase:false à $locationProvider.html5Mode() comme ceci:

    $locationProvider.html5Mode({
        enabled: true,
        requireBase: false
    });
    
  4. Afin de prendre en charge le chargement direct des URL HTML5, vous devez activer la réécriture d'URL côté serveur. De AngularJS / Guide du développeur / Utilisation de $ location

    L'utilisation de ce mode nécessite la réécriture d'URL côté serveur. En gros, vous devez réécrire tous vos liens vers le point d'entrée de votre application (par exemple, index.html ). Exiger une <base> est également important dans ce cas, car cela permet à Angular de différencier la partie de l'URL qui est la base de l'application et le chemin devant être traité par l'application.

    Une excellente ressource pour des exemples de réécriture de requêtes pour différentes implémentations de serveurs HTTP peut être trouvée dans la FAQ de ui-router - Comment: configurer votre serveur pour qu'il fonctionne avec html5Mode . Par exemple, Apache

     RewriteEngine on
    
     # Don't rewrite files or directories
     RewriteCond %{REQUEST_FILENAME} -f [OR]
     RewriteCond %{REQUEST_FILENAME} -d
     RewriteRule ^ - [L]
    
     # Rewrite everything else to index.html to allow html5 state links
     RewriteRule ^ index.html [L]
    

    nginx

     server {
         server_name my-app;
    
         root /path/to/app;
    
         location / {
             try_files $uri $uri/ /index.html;
         }
     }
    

    Express

     var express = require('express');
     var app = express();
    
     app.use('/js', express.static(__dirname + '/js'));
     app.use('/dist', express.static(__dirname + '/../dist'));
     app.use('/css', express.static(__dirname + '/css'));
     app.use('/partials', express.static(__dirname + '/partials'));
    
     app.all('/*', function(req, res, next) {
         // Just send the index.html for other files to support HTML5Mode
         res.sendFile('index.html', { root: __dirname });
     });
    
     app.listen(3006); //the port you want to use
    

7 péchés capitaux d'AngularJS

Vous trouverez ci-dessous la liste des erreurs souvent commises par les développeurs lors de l'utilisation des fonctionnalités d'AngularJS, de quelques leçons apprises et des solutions qui leur sont apportées.

1. Manipulation des DOM via le contrôleur

C'est légal, mais doit être évité. Les contrôleurs sont les endroits où vous définissez vos dépendances, liez vos données à la vue et développez une logique métier supplémentaire. Vous pouvez manipuler techniquement le DOM dans un contrôleur, mais chaque fois que vous avez besoin d'une manipulation identique ou similaire dans une autre partie de votre application, un autre contrôleur sera nécessaire. La meilleure pratique de cette approche consiste donc à créer une directive incluant toutes les manipulations et à utiliser la directive dans toute votre application. Par conséquent, le contrôleur laisse la vue intacte et fait son travail. Dans une directive, la fonction de liaison est le meilleur endroit pour manipuler le DOM. Il a un accès complet à la portée et à l'élément. En utilisant une directive, vous pouvez également profiter de la possibilité de réutilisation.

link: function($scope, element, attrs) {
    //The best place to manipulate DOM
}

Vous pouvez accéder aux éléments DOM dans la fonction de liaison de plusieurs manières, telles que le paramètre element , la méthode angular.element() ou le Javascript pur.

2. Liaison de données en transclusion

AngularJS est célèbre pour sa liaison de données bidirectionnelle. Cependant, il se peut que vous rencontriez parfois que vos données ne soient liées que dans un sens à l'intérieur des directives. Arrêtez-vous là, AngularJS n'a pas tort mais probablement vous. Les directives sont des endroits un peu dangereux car des champs d’enfants et des portées isolées sont impliqués. Supposons que vous ayez la directive suivante avec une transclusion

<my-dir>
    <my-transclusion>
    </my-transclusion>
</my-dir>

Et dans my-transclusion, vous avez des éléments liés aux données de la portée externe.

<my-dir>
    <my-transclusion>
        <input ng-model="name">
    </my-transclusion>
</my-dir>

Le code ci-dessus ne fonctionnera pas correctement. Ici, la transclusion crée une étendue enfant et vous pouvez obtenir la variable name, mais tout changement apporté à cette variable restera là. Donc, vous pouvez vraiment accéder à cette variable en tant que $ parent.name . Cependant, cette utilisation peut ne pas être la meilleure pratique. Une meilleure approche serait d'encapsuler les variables à l'intérieur d'un objet. Par exemple, dans le contrôleur, vous pouvez créer:

$scope.data = {
    name: 'someName'
}

Ensuite, dans la transclusion, vous pouvez accéder à cette variable via un objet 'data' et voir que la liaison bidirectionnelle fonctionne parfaitement!

<input ng-model="data.name">

Non seulement dans les transclusions, mais dans toute l'application, c'est une bonne idée d'utiliser la notation en pointillés.

3. directives multiples ensemble

Il est en effet légal d'utiliser deux directives dans le même élément, à condition que vous obéissiez à la règle: deux portées isolées ne peuvent pas exister sur le même élément. D'une manière générale, lors de la création d'une nouvelle directive personnalisée, vous allouez une étendue isolée pour faciliter le passage des paramètres. En supposant que les directives myDirA et myDirB ont isolé les portées et que myDirC ne l’a pas, l’élément suivant sera valide:

<input my-dir-a my-dirc>

alors que l'élément suivant provoquera une erreur de console:

<input my-dir-a my-dir-b>

Par conséquent, les directives doivent être utilisées à bon escient, en tenant compte des domaines d'application.

4. Mauvaise utilisation de $ emit

$ emit, $ broadcast et $ on, ils fonctionnent dans un principe émetteur-récepteur. En d'autres termes, ils constituent un moyen de communication entre contrôleurs. Par exemple, la ligne suivante émet le 'someEvent' du contrôleur A, qui sera capturé par le contrôleur concerné B.

$scope.$emit('someEvent', args);

Et la ligne suivante attire le «someEvent»

$scope.$on('someEvent', function(){});

Jusqu'à présent, tout semble parfait. Mais rappelez-vous que si le contrôleur B n'est pas encore appelé, l'événement ne sera pas intercepté, ce qui signifie que les contrôleurs d'émetteur et de récepteur doivent être appelés pour que cela fonctionne. Encore une fois, si vous n'êtes pas certain de devoir utiliser $ emit, la création d'un service semble être une meilleure solution.

5. Mauvaise utilisation de $ scope. $ Watch

$ scope. $ watch est utilisé pour regarder un changement de variable. Chaque fois qu'une variable a changé, cette méthode est appelée. Cependant, une erreur courante est de changer la variable dans $ scope. $ Watch. Cela provoquera une incohérence et une boucle $ digest infinie à un moment donné.

$scope.$watch('myCtrl.myVariable', function(newVal) {
    this.myVariable++;
});

Donc, dans la fonction ci-dessus, assurez-vous de ne pas avoir d'opérations sur myVariable et newVal.

6. Méthodes de liaison aux vues

C'est l'un des péchés les plus mortels. AngularJS a une liaison bidirectionnelle et chaque fois que quelque chose change, les vues sont mises à jour plusieurs fois. Donc, si vous liez une méthode à un attribut d'une vue, cette méthode peut potentiellement être appelée cent fois, ce qui vous rend également fou lors du débogage. Cependant, seuls certains attributs sont créés pour la liaison de méthode, tels que ng-click, ng-blur, ng-on-change, etc., qui attendent des méthodes comme paramètres. Par exemple, supposons que vous ayez la vue suivante dans votre balisage:

<input ng-disabled="myCtrl.isDisabled()" ng-model="myCtrl.name">

Ici, vous vérifiez l'état désactivé de la vue via la méthode isDisabled. Dans le contrôleur myCtrl, vous avez:

vm.isDisabled = function(){
    if(someCondition)
        return true;
    else
        return false;
}

En théorie, cela peut sembler correct, mais techniquement, cela entraînera une surcharge, car la méthode fonctionnera d'innombrables fois. Pour résoudre ce problème, vous devez lier une variable. Dans votre contrôleur, la variable suivante doit exister:

vm.isDisabled

Vous pouvez relancer cette variable lors de l'activation du contrôleur

if(someCondition)
    vm.isDisabled = true
else
    vm.isDisabled = false

Si la condition n'est pas stable, vous pouvez lier ceci à un autre événement. Ensuite, vous devez lier cette variable à la vue:

<input ng-disabled="myCtrl.isDisabled" ng-model="myCtrl.name">

Maintenant, tous les attributs de la vue ont ce qu'ils attendent et les méthodes ne seront exécutées que lorsque cela est nécessaire.

7. Ne pas utiliser les fonctionnalités d'Angular

AngularJS offre une grande commodité avec certaines de ses fonctionnalités, non seulement pour simplifier votre code, mais aussi pour le rendre plus efficace. Certaines de ces fonctionnalités sont énumérées ci-dessous:

  1. angular.forEach pour les boucles (Attention, vous ne pouvez pas "casser", vous ne pouvez que vous empêcher d'entrer dans le corps, alors pensez à la performance ici.)
  2. angular.element pour les sélecteurs DOM
  3. angular.copy : Utilisez ceci lorsque vous ne devez pas modifier l'objet principal
  4. Les validations de formulaires sont déjà géniales. Utilisez sale, vierge, touché, valide, requis, etc.
  5. Outre le débogueur Chrome, utilisez également le débogage à distance pour le développement mobile.
  6. Et assurez-vous d'utiliser Batarang . C'est une extension gratuite de Chrome où vous pouvez facilement inspecter les étendues
  7. .


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow