web-dev-qa-db-fra.com

Les directives AngularJS attribuent l'accès à partir du contrôleur

J'essaie d'accéder aux attributs d'une directive dans la fonction de contrôleur. Cependant, au moment où j'y accède, il n'est pas défini. J'ai remarqué que si je fais une simple minuterie, cela fonctionne. Existe-t-il un moyen d'exécuter du code uniquement après la directive et ses étendues sont prêtes et définies pour être utilisées?

J'en ai fait un violon. Assurez-vous que votre console est ouverte. http://jsfiddle.net/paulocoelho/uKA2L/1/

Voici le code que j'utilise dans le violon:

<div ng-app="testApp" >
    <testcomponent text="hello!"></testcomponent>
</div>
var module = angular.module('testApp', [])
    .directive('testcomponent', function () {
    return {
        restrict: 'E',
        template: '<div><p>{{text}} This will run fine! </p></div>',
        scope: {
            text: '@text'
        },
        controller: function ($scope, $element) {
            console.log($scope.text); // this will return undefined
            setTimeout(function () {
                console.log($scope.text);    // this will return the actual value...
            }, 1000);
        },
        link: function ($scope, $element, $attrs) {
            console.log($scope.text);
            setTimeout(function () {
                console.log($scope.text);
            }, 1000);
        }
    };
});
37
PCoelho

Ce qui fonctionne, si vous définissez

scope.text = $attrs.text;

à l'intérieur des fonctions de liaison et de contrôleur. Cela ne fonctionnera qu'initialement, car il n'y a pas de liaison de données bidirectionnelle. Vous pouvez cependant utiliser $ attrs.observe .

Voir violon: http://jsfiddle.net/JohannesJo/nm3FL/2/

27

Dans une étendue isolée, une propriété d'étendue locale définie avec '@' n'est pas accessible dans la fonction de liaison. Comme @remigio l'a déjà mentionné, ces propriétés de portée locale sont undefined à ce stade. $ attrs. $ observ () ou $ scope. $ watch () doit être utilisé pour obtenir de manière asynchrone la valeur (interpolée).

Si vous passez une valeur constante dans l'attribut (c'est-à-dire qu'aucune interpolation n'est requise, c'est-à-dire que la valeur de l'attribut ne contient aucun {{}}), il n'est pas nécessaire de '@' ou $ observer ou $ watch. Vous pouvez utiliser $ attrs.nom d'attribut une fois comme le suggère @hugo, ou si vous passez un nombre ou un booléen et que vous voulez obtenir le bon type, vous pouvez utiliser $ scope. $ eval ($ attrs.nom d'attribut) une fois que.

Si vous utilisez '=' pour lier une propriété d'étendue locale à une propriété d'étendue parent, la valeur de la propriété sera disponible dans la fonction de liaison (pas besoin de $ observ ou $ watch ou $ eval).

25
Mark Rajcok

Depuis Angular 1.3, vous pouvez utiliser bindToController. Voici un exemple sur la façon dont je l'utilise. Ici, j'ajoute l'attribut à scope, puis j'utilise bindToController pour utiliser cela à l'intérieur du contrôleur:

var module = angular.module('testApp', [])
    .directive('testcomponent', function () {
    return {
        restrict: 'E',
        template: '<div><p>{{text}} This will run fine! </p></div>',
        scope: {
            text: '@text'
        },
        controller: function () {
            console.log(this.text);
        },
        controllerAs: 'vm',
        bindToController: true
    };
});

Angular 1.3 introduit une nouvelle propriété à l'objet de définition de directive appelée bindToController, qui fait exactement ce qu'il dit. Lorsqu'il est défini sur true dans une directive avec une portée isolée qui utilise controllerAs, les propriétés du composant sont liées au contrôleur plutôt qu'à la portée. Cela signifie que Angular s'assure que, lorsque le contrôleur est instancié, les valeurs initiales des liaisons de portée isolées sont disponibles à ce sujet et que les modifications futures sont également automatiquement disponibles.

8
Neel

Utilisez plutôt $scope pour obtenir la valeur des attributs de la directive, personnellement je préfère utiliser $attrs pour la fonction controller, ou simplement attrs au 3e paramètre de la fonction link. Je n'ai aucun problème lorsque j'obtiens la valeur des attributs d'un controller en suivant le code sans délai:

var module = angular.module('testApp', [])
    .directive('testcomponent', function () {
    return {
    restrict: 'E',
    template: '<div><p>{{text}} This will run fine! </p></div>',
    scope: {
        text: '@text'
    },
    controller: ['$scope','$attrs', function ($scope, $attrs) {
        console.log($attrs.text); // just call to the $attrs instead $scope and i got the actual value
        $scope.text = $attrs.text; //assign attribute to the scope
    }]
    };
});
6
Bayu

La fonction de liaison est appelée avant la boucle $ digest, à ce moment les variables de portée ne sont pas définies. Regardez ce chapitre et cet autre pour comprendre comment fonctionne la fonction de liaison. Vous utilisez uniquement la fonction de lien pour définir des montres et/ou des comportements pour la directive, pas pour manipuler le modèle, cela se fait dans les contrôleurs.

1
remigio

Si vous accédez à cette valeur à partir de votre directive pour l'insérer dans votre vue à l'aide d'une directive, vous pouvez accéder à cet attribut en utilisant l'api $ compile et en faisant quelque chose comme ça

var string = "<div> " + scope.text + "</div>";
$compile(string)(scope, function(cloned, scope){
       element.append(cloned);
});
0
cuterthanbacon