La Directive isoler portée avec ng-repeat portée en AngularJS
J'ai une directive avec un isolat-portée (de sorte que je peux réutiliser la directive dans d'autres lieux), et quand j'utilise cette directive avec une ng-repeat
, cela ne fonctionne pas.
J'ai lu l'ensemble de la documentation et de la Pile Dépassement de réponses sur ce sujet et de comprendre les enjeux. Je crois que j'ai évité tous les pièges.
Donc, je comprends que mon code ne fonctionne pas parce que le champ créé par le ng-repeat
directive. Mon propre directive crée un isolat-champ d'application et fait dans les deux sens de la liaison de données à un objet de la portée parent. Mon directive assigne un nouvel objet-valeur de cette variable liée et cela fonctionne parfaitement lors de mon directive est utilisée sans ng-repeat
(la variable parent est correctement mis à jour). Cependant, avec ng-repeat
, la cession crée une nouvelle variable dans la ng-repeat
portée et la variable parent ne voit pas le changement. Tout cela est prévu sur la base de ce que j'ai lu.
J'ai aussi lu que lorsqu'il y a plusieurs directives sur un élément donné, qu'un seul champ est créé. Et qu'un priority
peut être définie dans chaque directive pour définir l'ordre dans lequel les directives sont appliquées; les directives sont classées par ordre de priorité, puis leur compiler les fonctions sont appelés (de recherche pour le mot priorité à http://docs.angularjs.org/guide/directive).
Alors j'espérais que je pourrais utiliser en priorité pour faire en sorte que mon directive s'exécute en premier et finit par créer un isolat-champ, et quand ng-repeat
s'exécute, il ré-utilise l'isolat-champ d'application au lieu de la création d'un champ qui fait hérite de la portée parent. Le ng-repeat
documentation indique que celle-ci s'exécute à un niveau de priorité 1000
. Il n'est pas clair si 1
est d'un plus haut niveau de priorité ou une diminution du niveau de priorité. Lorsque j'ai utilisé le niveau de priorité 1
dans mon directive, il n'est pas de faire une différence, alors j'ai essayé 2000
. Mais cela ne fait qu'aggraver les choses: mon liaisons bidirectionnelles devenir undefined
et mon directive ne pas afficher quoi que ce soit.
J'ai créé un violon pour montrer mon problème. J'ai commenté la priority
paramètre dans mon directive. J'ai une liste de nom des objets et une directive appelée name-row
qui montre les champs prénom et nom dans le nom de l'objet. Quand un nom affiché est cliqué, je le veux pour définir un selected
variable dans le champ d'application principal. Le tableau de noms, la selected
variable sont passés à la name-row
directive à l'aide de deux voies de liaison de données.
Je sais comment obtenir que cela fonctionne par appel à des fonctions dans le champ d'application principal. Je sais aussi que si selected
est à l'intérieur d'un autre objet, et je la lie à l'objet extérieur, les choses allaient tourner. Mais je ne suis pas intéressé par ces solutions à l'heure actuelle.
Au lieu de cela, les questions que j'ai sont:
- Comment puis-je empêcher
ng-repeat
de la création d'un champ qui fait hérite de la portée parent, et, au lieu de l'avoir utiliser mon directive isoler le-champ? - Pourquoi le niveau de priorité
2000
dans mon directive ne fonctionne pas? - À l'aide de Batarang, est-il possible de savoir quel type de champ d'application est en cours d'utilisation?
- Normalement, vous ne voulez pas utiliser un isolat la portée si votre directive sur le même élément avec d'autres directives. Puisque vous êtes la création de vos propres propriétés de l'étendue, et vous avez besoin de travailler avec ng-repeat, je vous suggère d'utiliser
scope: true
pour votre directive. Voir aussi (si vous ne l'avez pas déjà) stackoverflow.com/questions/14914213/... Aussi, juste parce que une directive sera utilisé dans plusieurs endroits ne signifie pas que nous devrions utiliser automatiquement un isolat portée. - J'ai lu beaucoup de vos réponses (elles sont au-delà excellent, merci pour l'écriture), mais il n'a jamais eu lieu pour moi de lire vos questions :-). J'ai lu ce que vous avez lié. Il me semble que les isoler-champ d'application les directives ne peuvent pas être mélangé avec d'autres directives. Je suis d'accord avec le sentiment que ces directives sont des composants et, par conséquent, ils ne doivent pas être mélangés avec d'autres directives. La seule exception (à ce jour) pour moi, ce serait
ng-repeat
. Je pense qu'il est utile d'être capable de mélanger autonome des directivesng-repeat
. À suivre... - Suite de la ci-dessus... Donc si il doit y avoir qu'une directive avec un champ d'application pour un élément, puis
ng-repeat
ne doit pas avoir une portée.ng-repeat
avoir un champ d'application ne font sens pour le type de cas d'utilisation, donc je ne veux pas dire qu'il soit changé. Au lieu de cela, comme je l'ai commenté dans Alex Osborn réponse, je pense que je vais créer une répétition de la directive fondée sur l'ng-repeat
ne pas créer son propre champ. Cela peut ensuite être utilisé pour la répétition des directives qui ont leur propre isoler étendues. À suivre... - Le code qui se répète d'une directive doit maintenant de savoir si l'utilisation de
ng-repeat
ou la portée personnalisée-moins de répéter la directive. Je pense que c'est correct pour le "visiteur" pour le connaître, mais il n'est pas acceptable pour un "appelé" (la directive être répétés) pour savoir si elle est répétée, ou pas. À suivre... - Un peu fou avec les commentaires ici... 🙂 ngRepeat doit créer son propre champ d'application. Pourquoi avez-vous besoin d'un isolat de portée ici?
- Aussi, je pense que c'est important pour un composant (directive) pour être en mesure de changer dans le futur, sans casser le code qui l'utilise, surtout si le composant est simplement l'ajout d'un comportement sans changer son "API" (c'est à dire qu'il n'a pas besoin de liaisons supplémentaires pour soutenir le nouveau comportement). Le nouveau comportement pourrait avoir besoin d'un isolat-champ où aucun n'a été nécessaire avant de pouvoir stocker de la composante spécifique de l'état. Je pense donc qu'il n'est pas idéal d'avoir à décider quel type de champ à utiliser pour un composant "directive", basée sur les habitudes d'utilisation de ce composant. </soapbox>
- désolé pour le firehose de commentaires :-). Ma première fois avec stackoverflow; peut-être que cela aurait été mieux dans la AngularJS Groupe Google. J'ai fait le plus petit possible violon pour montrer que je ne pouvais pas mélanger mon directive
ng-repeat
. Mon code a la directive spécifique de l'état que je ne veux isoler de la portée parent. Pensez-vous que je vais pouvoir créer mon propre variante deng-repeat
qui utilise une autre directive, ou est-il quelque chose de fondamental dansng-repeat
qui ne peuvent pas fonctionner avec un autre directive? Je suis un JS newb & n'ont pas pris un coup d'oeil au Angulaire code encore. - ngRepeat passe par la création d'un ensemble d'éléments DOM, l'ajout d'une portée de chacun, et puis la création de certaines variables sur chaque champ contenant l'itération de la valeur et de certaines métadonnées. Il ne peut pas fonctionner sans une couverture différente. Si vous avez écrit votre propre, il serait enclin à l'erreur - il exiger qu'il y a déjà un champ créé par une priorité plus élevée de la directive, puis votre nouveau répéteur ne pollue champ d'application. Tant pour l'isolation! Cela dit, vous pouvez l'utilisation ngRepeat et un isolat portée, donc je ne suis pas sûr de ce qu'est la question.
- Ma question: l'Écriture d'un 2-way liaison de données dans un personnalisé directive isoler-champ d'application échoue avec
ng-repeat
. Votre plunker utilise 2 voies de la liaison de données, mais il ne lit que la variable liée; il n'est pas d'écrire une variable liée. Je n'ai pas besoin d'écrire à la variable pointant vers l'itération en cours (val
dans votre plunker), mais j'ai d'autres variables que j'lier à dans mon de la directive isoler-champ d'application et j'ai besoin d'être en mesure de modifier ces variables à partir de l'intérieur de mon directive. Par exemple, dans mon violon (lié à ma question), j'ai besoin de modifierioSelected
, et qui ne fonctionne pas lorsque j'utiliseng-repeat
. - Oh, eh bien la réponse est encore plus simple. Utilisation
io-selected="$parent.selected"
. - Mais aussi garder à l'esprit que votre problème n'est pas avec ngRepeat mais avec la façon dont l'héritage par prototype fonctionne en JavaScript. Le problème est que vous êtes à l'aide d'une primitive. Modèle de valeurs doivent toujours avoir un
.
en AngularJS. - Je pense que vous êtes la création d'une directive, lorsque l'un n'est pas nécessaire. Apparemment, de ce que vous tentez de le faire peut être réalisé par une combinaison de ng-inclure et ng-repeat. Mettre dans un Contrôleur pour chaque élément répété et vous êtes bon pour aller.
- Je pensais que l'utilisation de
$parent
est un code-odeur. Que faire si mon directive est imbriquée dans plusieursng-repeat
directives? Puis mon directive aurait pour savoir à quelle profondeur le terrier du lapin va de la chaîne et tout un tas de$parent.$parent...
, droit?ng-repeat
introduit une portée parce qu'il a besoin de faire de l'itération en cours à la disposition de chaque répétition. Mais que faire si j'ai une répétition de la variante qui lie l'itération courante à une entrée dans la directive? Ensuite, la répétition de la directive n'a pas besoin d'introduire une portée de tous. Mais j'ai besoin de regarder dans les métadonnées que vous avez ditng-repeat
besoins. - mon violon est le plus petit exemple pour illustrer, je ne peut pas écrire dans un 2-way de liaison lorsque j'utilise
ng-repeat
. J'aime le concept de directives (et 2 voies de la liaison de données) et j'ai une très minime contrôleur autonome dans mon (pleine page) app (j'espère que je vais être capable d'en finir avec ce contrôleur, mais je m'égare). Donc, je suis à la recherche d'un moyen de faire mon directives de travail dans n'importe quel scénario avec 2 voies de la liaison de données. - Quelqu'un peut m'aider avec ça? stackoverflow.com/questions/22000201/...
Vous devez vous connecter pour publier un commentaire.
D'accord, par le biais de beaucoup de commentaires ci-dessus, j'ai découvert la confusion. Tout d'abord, quelques points d'éclaircissement:
Voici un exemple du même code mais avec la directive supprimée:
Ici est un JSFiddle démontrant que cela ne fonctionne pas. Vous obtenez les mêmes résultats que dans la directive.
Pourquoi ne pas travailler? Parce que les étendues dans AngularJS utiliser l'héritage par prototype. La valeur
selected
sur votre parent est un primitive. En JavaScript, ce qui signifie qu'il sera écrasé lorsqu'un enfant définit de la même valeur. Il y a une règle d'or dans AngularJS étendues des valeurs de modèle devrait toujours ont un.
en eux. Qui est, ils ne doivent jamais être primitives. Voir cette SORTE de réponse pour plus d'informations.Voici une photo de ce que les étendues d'abord ressembler.
Après avoir cliqué sur le premier point, les étendues maintenant ressembler à ceci:
Avis qu'une nouvelle
selected
propriété a été créé sur le ngRepeat portée. Le contrôleur de portée 003 a pas été modifié.Vous pouvez probablement deviner ce qui se passe lorsque l'on clique sur le deuxième point:
Si votre problème est en fait pas causée par ngRepeat à tous - il est causé par la rupture d'une règle d'or dans AngularJS. Le moyen pour résoudre ce problème est d'utiliser simplement une propriété de l'objet:
Ici est un deuxième JSFiddle montrant cela fonctionne aussi.
Voici ce que les étendues de ressembler au départ:
Après avoir cliqué sur le premier élément:
Ici, le contrôleur de la portée en est affectée, comme souhaité.
Aussi, pour prouver que cela va continuer à travailler avec votre directive avec un isolat de la portée (car, encore une fois, cela n'a rien à voir avec votre problème, ici, est un JSFiddle pour que, aussi, la vue doit refléter l'objet. Vous remarquerez que le seul changement nécessaire était d'utiliser un objet au lieu d'un primitive.
Étendues d'abord:
Étendues après avoir cliqué sur le premier élément:
Pour conclure: encore une fois, le problème n'est pas avec l'isolat champ d'application et il n'est pas avec la façon dont ngRepeat œuvres. Votre problème est que vous êtes briser une règle qui est connu pour conduire à ce problème. Les modèles en AngularJS devriez toujours avoir une
.
..
règle d'or n'est nécessaire que pour des lunettes de visée à l'héritage par prototype. Avec isoler les étendues, les variables qui vous intéressent sont définis dans lescope: {}
définition dans la directive, et, par conséquent, ces variables n'existent pas dans l'isolat-portée depuis le début. Aussi, ils ne masquent pas le parent de variables car l'isoler de la portée n'a pas fait hériter de la portée parent. c'est à dire il n'y a pas de "parent" champ d'application d'un masque.=
dansscope: {}
) provoque la variable correspondante à l'extérieur de la portée de changer en raison de la liaison de données bidirectionnelle. Je ne me souviens pas d'essayer avec primitive variables dans l'isolat-champ, mais j'ai certainement vu ce travail avec les objets/variables de référence. Notez que je parle de l'affectation d'un nouvel objet de valeur à la variable, pas la modification d'une propriété à l'intérieur de l'objet. c'est à dire que je ne suis pas à la suite de la.
règle d'or dans mon directive et il fonctionne toujours.ng-repeat
avec un manuel de répétition: jsfiddle.net/jtjk4/1 (j'ai créé des variables pour chaque index deMainController
parce que mon directive utilise uninIndex : '='
de liaison pour l'indice). Vous verrez que cela fonctionne bien. Mon directive assigne une nouvelle valeur àioSelected
sans l'aide de.
et il fonctionne correctement (à l'extérieur de la portée voit le changement et affiche le nom sélectionné dans la sortie HTML). C'est ce qui m'amène à dire qu'il estng-repeat
(plus précisément son champ d'application) qui me casse les deux voies de liaison de données isoler-champ d'application de la directive. Ce qui me manque?.
règle d'or) devient une abstraction qui fuit qui m'oblige à réécrire mes directives..
. Lorsque vous n'en avez pas, vous êtes le rendant fragile et elle finira par cesser de travailler. Ce que je n'ai vraiment pas obtenir est pourquoi vous êtes résister à la première place..
.Sans directement en essayant d'éviter de répondre à vos questions, au lieu de prendre un coup d'oeil à la suite de violon:
http://jsfiddle.net/dVPLM/
Point clé est qu'au lieu d'essayer de combattre et de modifier le comportement classique Angulaire, vous pouvez structurer votre directive de travailler avec
ng-repeat
plutôt que d'essayer de le remplacer.Dans votre modèle:
Dans votre directive:
En réponse à vos questions:
ng-repeat
va créer un champ, vous ne devriez pas essayer de changer cela.ng-repeat
ou pas. Peut-être quand il est d'abord écrit, il n'est jamais utilisé avecng-repeat
. Et un peu de temps à l'avenir, il peut être utilisé avecng-repeat
, et à ce point dans le temps, il devrait fonctionner sans une réécriture. Espérons que les prochaines versions de AngularJS va rendre cela possible.ng-repeat
ou pas. Mais il semble que j'aurais à passer d'une fonction à la directive, de sorte qu'elle peut modifier les variables dans la portée parent, au lieu de pouvoir muter une liaison bidirectionnelle dans le cadre de la directive propre champ d'application. Les deux sens de la liaison et de la réutilisation des directives sont mes deux coups de coeur sur AngularJS etng-repeat
se révèle être une mouche dans la pommade. Je peux peut-être écrire unng-repeat
équivalent à ne pas créer son propre champ.