Maneira mais fácil de passar uma variável de escopo AngularJS da diretiva para o controlador?

Qual é a maneira mais fácil de passar uma variável de escopo AngularJS da diretiva para o controlador? Todos os exemplos que vi parecem tão complexos, não há como acessar um controlador de uma diretiva e definir uma das suas variables ​​de escopo?

Editado em 2014/8/25: Aqui foi onde eu bifurquei.

Obrigado @anvarik.

Aqui está o JSFiddle . Eu esqueci onde eu bifurcou isso. Mas este é um bom exemplo mostrando a diferença entre = 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; } }]); 

Aguarde até que o angular avalie a variável

Eu tive um monte de mexer com isso, e não consegui fazê-lo funcionar, mesmo com a variável definida com "=" no escopo. Aqui estão três soluções, dependendo da sua situação.


Solução nº 1


Descobri que a variável não foi avaliada pelo angular ainda quando foi passada para a diretiva. Isso significa que você pode acessá-lo e usá-lo no modelo, mas não dentro do link ou da function do controlador de aplicativo, a menos que esperemos que ele seja avaliado.

Se sua variável está mudando , ou é buscada através de uma solicitação, você deve usar $observe ou $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); } }); }]); 

E aqui está o html (lembre-se dos parênteses!):

 

Observe que você não deve definir a variável como "=" no escopo, se estiver usando a function $observe . Além disso, descobri que ele passa objects como strings, portanto, se você estiver passando objects, use a solução 2 ou o scope.$watch(attrs.yourDirective, fn) (ou # 3 se a variável não estiver mudando).


Solução 2


Se a sua variável é criada, por exemplo, em outro controlador , mas só precisa esperar até que o angular avalie-a antes de enviá-la ao controlador de aplicativo, podemos usar $timeout para esperar até que o $apply seja executado. Também precisamos usar o $emit para enviá-lo ao controlador de aplicativo do escopo pai (devido ao escopo isolado na diretiva):

 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; }); }]); 

E aqui está o html (sem colchetes!):

 

Solução 3


Se a sua variável não está mudando e você precisa avaliá-la na sua diretiva, você pode usar a function $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); } }); }]); 

E aqui está o html (lembre-se dos parênteses!):

 

Além disso, dê uma olhada nesta resposta: https://stackoverflow.com/a/12372494/1008519

Referência para o problema FOUC (flash de conteúdo não estilizado): http://deansofer.com/posts/view/14/AngularJs-Tips-and-Tricks-UPDATED

Para os interessados: aqui está um artigo sobre o ciclo de vida angular