Problèmes de portée avec certaines directives intégrées dans Angular

Considérons le code HTML suivant :


<ul>
    <li>
        <input type="text" ng-model="valeurPrincipale"/>
    </li>
    <li ng-repeat="i in [1, 2, 3]">
        <input type="text" ng-model="valeurPrincipale"/>
    </li>
</ul>
<script>
    angular.module('monApp', []);
</script>

Ce code génère quatre champs de saisie, tous liés à la même variable valeurPrincipale. Idéalement, la modification de l'un d'eux devrait se refléter sur les autres. Cependant, le premier champ fonctionne comme prévu, mais les champs générés par ngRepeat ne se mettent pas à jour mutuellement. De plus, si vous modifiez l'un des champs dans la boucle, le premier champ ne reflétera plus ces changements.

La raison de ce comportement réside dans la création d'une nouvelle portée (scope) pour chaque itération de ngRepeat. Ces nouvelles portées héritent de la portée parente. Lors de la lecture d'une propriété, si elle n'est pas définie dans la portée enfant, JavaScript la recherche dans la portée parente. Cependant, lors de l'écriture d'une propriété, elle est diretcement créée dans la portée enfant, rompant ainsi le lien avec la portée parente pour cette propriété spécifique.

Pour résoudre ce problème et garantir que les modifications sont propagées à la portée parente, vous pouvez utiliser le préfixe $parent :


<ul>
    <li>
        <input type="text" ng-model="valeurPrincipale"/>
    </li>
    <li ng-repeat="i in [1, 2, 3]">
        <input type="text" ng-model="$parent.valeurPrincipale"/>
    </li>
</ul>

Dans cet exemple, nous avons explicitement lié les champs dans la boucle à $parent.valeurPrincipale.

Une autre difficulté peut survenir si vous avez besoin d'accéder directement à la portée créée par ngRepeat. Dans de tels cas, vous pouvez la transmettre via une fonction :


<ul>
    <li>
        <input type="text" ng-model="valeurPrincipale"/>
    </li>
    <li ng-repeat="element in elements">
        <input type="text" ng-model="element.valeur"/>
        <button ng-click="mettreAJourValeurPrincipale(this)">Mettre à jour</button>
    </li>
</ul>
<script>
    angular.module('monApp', [])
        .controller('ControleurExemple', ['$scope', function($scope) {
            $scope.elements = [{ valeur: '' }, { valeur: '' }, { valeur: '' }];
            $scope.valeurPrincipale = '';

            $scope.mettreAJourValeurPrincipale = function(porteeEnfant) {
                $scope.valeurPrincipale = porteeEnfant.element.valeur;
            };
        }]);
</script>

Outre ngRepeat, d'autres directives créent égalmeent leur propre portée. Les plus courantes incluent :

  • ng-include
  • ng-switch
  • ng-repeat
  • ng-view
  • ng-controller

Étiquettes: angularjs scope ngrepeat directives

Publié le 2 août à 06h13