Il modo più semplice per passare una variabile di ambito AngularJS dalla direttiva al controller?

Qual è il modo più semplice per passare una variabile di ambito AngularJS dalla direttiva al controller? Tutti gli esempi che ho visto sembrano così complessi, non c’è un modo per accedere a un controller da una direttiva e impostare una delle sue variabili scope?

Modificato il 2014/8/25: qui era dove l’ho forked.

Grazie a @anvarik.

Ecco il JSFiddle . Ho dimenticato dove ho biforcato questo. Ma questo è un buon esempio che mostra la differenza tra = e @

Parent Scope

// Update to see how parent scope interacts with component scope

Attribute

get: {{isolatedAttributeFoo}}
set: // This does not update the parent scope.

Binding

get: {{isolatedBindingFoo}}
set: // This does update the parent scope.

Expression

// And this calls a function on the parent scope.
 var myModule = angular.module('myModule', []) .directive('myComponent', function () { return { restrict:'E', scope:{ /* NOTE: Normally I would set my attributes and bindings to be the same name but I wanted to delineate between parent and isolated scope. */ isolatedAttributeFoo:'@attributeFoo', isolatedBindingFoo:'=bindingFoo', isolatedExpressionFoo:'&' } }; }) .controller('MyCtrl', ['$scope', function ($scope) { $scope.foo = 'Hello!'; $scope.updateFoo = function (newFoo) { $scope.foo = newFoo; } }]); 

Attendere fino a quando l’angular ha valutato la variabile

Ho avuto un sacco di giocherellare con questo, e non riuscivo a farlo funzionare anche con la variabile definita con "=" nell’ambito. Ecco tre soluzioni a seconda della situazione.


Soluzione n. 1


Ho scoperto che la variabile non è stata valutata da angular ma quando è stata passata alla direttiva. Ciò significa che è ansible accedervi e utilizzarlo nel modello, ma non all’interno del collegamento o della funzione del controller di app, a meno che non si aspetti che venga valutato.

Se la tua variabile sta cambiando , o viene recuperata attraverso una richiesta, dovresti usare $observe o $watch :

 app.directive('yourDirective', function () { return { restrict: 'A', // NB: no isolated scope!! link: function (scope, element, attrs) { // observe changes in attribute - could also be scope.$watch attrs.$observe('yourDirective', function (value) { if (value) { console.log(value); // pass value to app controller scope.variable = value; } }); }, // the variable is available in directive controller, // and can be fetched as done in link function controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) { // observe changes in attribute - could also be scope.$watch $attrs.$observe('yourDirective', function (value) { if (value) { console.log(value); // pass value to app controller $scope.variable = value; } }); } ] }; }) .controller('MyCtrl', ['$scope', function ($scope) { // variable passed to app controller $scope.$watch('variable', function (value) { if (value) { console.log(value); } }); }]); 

Ed ecco l’html (ricorda le parentesi!):

 

Si noti che non si deve impostare la variabile su "=" nell’ambito, se si utilizza la funzione $observe . Inoltre, ho scoperto che passa gli oggetti come stringhe, quindi se passi oggetti usa la soluzione # 2 o l’ scope.$watch(attrs.yourDirective, fn) (, o # 3 se la tua variabile non sta cambiando).


Soluzione n. 2


Se la variabile è creata, ad esempio, da un altro controller , ma è necessario attendere che l’angular lo abbia valutato prima di inviarlo al controller dell’app, possiamo usare $timeout per attendere fino all’esecuzione di $apply . Inoltre, è necessario utilizzare $emit per inviarlo all’app controller genitore (a causa dell’ambito isolato nella direttiva):

 app.directive('yourDirective', ['$timeout', function ($timeout) { return { restrict: 'A', // NB: isolated scope!! scope: { yourDirective: '=' }, link: function (scope, element, attrs) { // wait until after $apply $timeout(function(){ console.log(scope.yourDirective); // use scope.$emit to pass it to controller scope.$emit('notification', scope.yourDirective); }); }, // the variable is available in directive controller, // and can be fetched as done in link function controller: [ '$scope', function ($scope) { // wait until after $apply $timeout(function(){ console.log($scope.yourDirective); // use $scope.$emit to pass it to controller $scope.$emit('notification', scope.yourDirective); }); }] }; }]) .controller('MyCtrl', ['$scope', function ($scope) { // variable passed to app controller $scope.$on('notification', function (evt, value) { console.log(value); $scope.variable = value; }); }]); 

Ed ecco l’html (nessuna parentesi!):

 

Soluzione n. 3


Se la variabile non sta cambiando ed è necessario valutarla nella direttiva, è ansible utilizzare la $eval :

 app.directive('yourDirective', function () { return { restrict: 'A', // NB: no isolated scope!! link: function (scope, element, attrs) { // executes the expression on the current scope returning the result // and adds it to the scope scope.variable = scope.$eval(attrs.yourDirective); console.log(scope.variable); }, // the variable is available in directive controller, // and can be fetched as done in link function controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) { // executes the expression on the current scope returning the result // and adds it to the scope scope.variable = scope.$eval($attrs.yourDirective); console.log($scope.variable); } ] }; }) .controller('MyCtrl', ['$scope', function ($scope) { // variable passed to app controller $scope.$watch('variable', function (value) { if (value) { console.log(value); } }); }]); 

Ed ecco l’html (ricorda le parentesi!):

 

Inoltre, dai un’occhiata a questa risposta: https://stackoverflow.com/a/12372494/1008519

Riferimento per il problema FOUC (flash of unstyled content): http://deansofer.com/posts/view/14/AngularJs-Tips-and-Tricks-UPDATED

Per gli interessati: ecco un articolo sul ciclo di vita angular