Espere até que angular tenha avaliado a variável
Eu tinha mexido muito nisso e não consegui fazer funcionar mesmo com a variável definida "="
no escopo. Aqui estão três soluções, dependendo da sua situação.
Solução # 1
Descobri que a variável ainda não foi avaliada pelo angular 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 função do controlador de aplicativo, a menos que esperemos que seja avaliado.
Se sua variável estiver mudando ou for obtida por meio 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 colchetes!):
<div ng-controller="MyCtrl">
<div your-directive="{{ someObject.someVariable }}"></div>
<!-- use ng-bind in stead of {{ }}, when you can to avoids FOUC -->
<div ng-bind="variable"></div>
</div>
Observe que você não deve definir a variável "="
no escopo, se estiver usando a $observe
função. Além disso, descobri que ele passa objetos como strings, portanto, se você estiver passando objetos, use a solução 2 ou scope.$watch(attrs.yourDirective, fn)
(ou 3 se a variável não estiver mudando).
Solução # 2
Se sua variável for criada, por exemplo, em outro controlador , mas apenas precisar esperar até que o angular a avalie antes de enviá-la para o controlador de aplicativo, podemos $timeout
esperar até que $apply
seja executado. Além disso, precisamos usar $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!):
<div ng-controller="MyCtrl">
<div your-directive="someObject.someVariable"></div>
<!-- use ng-bind in stead of {{ }}, when you can to avoids FOUC -->
<div ng-bind="variable"></div>
</div>
Solução # 3
Se sua variável não está mudando e você precisa avaliá-la em sua diretiva, você pode usar a $eval
função:
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 colchetes!):
<div ng-controller="MyCtrl">
<div your-directive="{{ someObject.someVariable }}"></div>
<!-- use ng-bind instead of {{ }}, when you can to avoids FOUC -->
<div ng-bind="variable"></div>
</div>
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