70 votes

Comment "détacher" une expression

Dire que j'ai une ng-repeat avec un grand tableau.

Lorsque ng-repeat s'exécute, il ajoute chaque élément de ce tableau pour un isolé champ d'application, ainsi que le tableau lui-même dans un champ. Cela signifie que $digest vérifie l'ensemble de la matrice pour des changements, et en plus de cela, il vérifie chaque élément de ce tableau pour les changements.

Voir ce plunker comme un exemple de ce dont je parle.

Dans mon cas d'utilisation, je n'ai jamais changer un seul élément de mon tableau donc je n'ai pas besoin de les avoir vu. Je ne jamais changer l'ensemble de la matrice, dans lequel cas ng-repeat re-rendre le tableau dans son intégralité. (Si je me trompe sur cette s'il vous plaît laissez-moi savoir..)

Dans un tableau de (disons) de 1000 lignes, c'est plus de 1000 expressions que je n'ai pas besoin évalué.

Comment puis-je radier chaque élément de l'observateur tout en continuant à regarder le tableau principal?

Peut-être, au lieu de révocation de l'enregistrement j'ai pu avoir plus de contrôle sur mon $digest et en quelque sorte sauter chaque ligne individuelle?

Ce cas est un exemple d'une question plus générale. Je sais que $watch retourne un 'deregisteration la fonction, mais ça n'aide pas lorsqu'une directive est en cours d'enregistrement les montres, ce qui est la plupart du temps.

90voto

Ben Lesh Points 39290

Pour avoir un répéteur avec un grand tableau que vous ne regardez pas de regarder chaque élément.

Vous aurez besoin de créer un personnalisé directive qui prend un argument, et l'expression de votre tableau, puis dans la fonction de liaison de vous venais de regarder ce tableau, et vous auriez la fonction de liaison par programme actualiser le code HTML (plutôt que d'utiliser un ng-repeat)

quelque chose comme (pseudo-code):

app.directive('leanRepeat', function() {
    return {
        restrict: 'E',
        scope: {
           'data' : '='
        },
        link: function(scope, elem, attr) {
           scope.$watch('data', function(value) {
              elem.empty(); //assuming jquery here.
              angular.forEach(scope.data, function(d) {
                  //write it however you're going to write it out here.
                  elem.append('<div>' + d + '</div>');
              });
           });
        }
    };
});

... ce qui semble être une douleur dans le cul.

Suppléant hackish méthode

Vous pourriez être en mesure de faire une boucle par $scope.$$watchers et examiner $scope.$$watchers[0].exp.exp pour voir si elle correspond à l'expression que vous souhaitez supprimer, puis l'enlever avec un simple splice() appel. La PITA ici, c'est que des choses comme Blah {{whatever}} Blah entre les balises seront l'expression, et même inclure des retours chariot.

Sur le plan positif, vous pourriez être en mesure de simplement faire une boucle par le $portée de votre ng-repeat et d'effacer tout, puis ajouter explicitement la montre que vous voulez... je ne sais pas.

De toute façon, il semble comme un hack.

Pour supprimer un observateur faite par $scope.$regarder

Vous pouvez annuler l'inscription d'un $watch avec la fonction renvoyée par l' $watch appel:

Par exemple, pour avoir un $watch seulement du feu une fois:

var unregister = $scope.$watch('whatever', function(){ 
     alert('once!');
     unregister();
});

Vous pouvez, bien sûr, appelez la fonction désinscription à tout moment vous voulez... c'était juste un exemple.

Conclusion: Il n'y a pas vraiment une bonne façon de faire exactement ce que vous demandez

Mais une chose à considérer: Est-il même la peine de s'inquiéter? Par ailleurs est-ce vraiment une bonne idée d'avoir des milliers de documents chargés dans des dizaines de DOMElements chaque? De la nourriture pour la pensée.

J'espère que ça aide.


EDIT 2 (supprimé mauvaise idée)

8voto

r3m0t Points 913

Edit: voir la réponse que j'ai posté.

Je suis allé et mis en œuvre blesh l'idée dans un seperable. Mon ngOnce directive simplement détruit l'enfant qu' ngRepeat crée sur chaque élément. Cela signifie que le champ d'application n'a pas obtenir de l'atteinte de ses parents' scope.$digest et les observateurs ne sont jamais exécutées.

Source et exemple sur JSFiddle

La directive elle-même:

angular.module('transclude', [])
 .directive('ngOnce', ['$timeout', function($timeout){
    return {
      restrict: 'EA',
      priority: 500,
      transclude: true,
      template: '<div ng-transclude></div>',
        compile: function (tElement, tAttrs, transclude) {
            return function postLink(scope, iElement, iAttrs, controller) {
                $timeout(scope.$destroy.bind(scope), 0);
            }
        }
    };
}]);

En l'utilisant:

      <li ng-repeat="item in contents" ng-once>
          {{item.title}}: {{item.text}}
      </li>

Note ng-once ne pas créer son propre champ qui signifie qu'il peut affecter les éléments frères. Ces tous la même chose:

  <li ng-repeat="item in contents" ng-once>
      {{item.title}}: {{item.text}}
  </li>
  <li ng-repeat="item in contents">
      <ng-once>
          {{item.title}}: {{item.text}}
      </ng-once>
  </li>
  <li ng-repeat="item in contents">
      {{item.title}}: {{item.text}} <ng-once></ng-once>
  </li>

Remarque c'est peut être une mauvaise idée

3voto

r3m0t Points 913

Vous pouvez ajouter l' bindonce directive à votre ng-repeat. Vous aurez besoin de télécharger à partir de https://github.com/pasvaz/bindonce.

edit: quelques mises en garde:

Si vous utilisez {{}} d'interpolation dans votre modèle, vous devez le remplacer avec de l' <span bo-text>.

Si vous utilisez ng- directives, vous devez les remplacer avec le droit bo- directives.

Aussi, si vous êtes de mettre bindonce et ng-repeat sur le même élément, vous devriez essayer de déplacement de l' bindonce pour un parent de l'élément (voir https://github.com/Pasvaz/bindonce/issues/25#issuecomment-25457970 ) ou l'ajout d' track by votre ng-repeat.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X