Attendi che angular abbia valutato la variabile
Ho dovuto giocherellare molto con questo e non sono riuscito a farlo funzionare anche con la variabile definita "="
nell'ambito. Ecco tre soluzioni a seconda della tua situazione.
Soluzione n. 1
Ho scoperto che la variabile non è stata ancora valutata da angular quando è stata passata alla direttiva. Ciò significa che puoi accedervi e utilizzarlo nel modello, ma non all'interno del collegamento o della funzione del controller dell'app a meno che non aspettiamo che venga valutato.
Se la tua variabile sta cambiando o viene recuperata tramite 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!):
<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>
Nota che non dovresti impostare la variabile su "="
nell'ambito, se stai usando la $observe
funzione. Inoltre, ho scoperto che passa gli oggetti come stringhe, quindi se stai passando gli oggetti usa la soluzione # 2 o scope.$watch(attrs.yourDirective, fn)
(, o # 3 se la tua variabile non sta cambiando).
Soluzione n. 2
Se la tua variabile viene creata ad esempio in un altro controller , ma devi solo aspettare che angular la abbia valutata prima di inviarla al controller dell'app, possiamo usare $timeout
per aspettare fino a quando non $apply
è stato eseguito. Inoltre dobbiamo usarlo $emit
per inviarlo al controller dell'app dell'ambito padre (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 (senza parentesi!):
<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>
Soluzione n.3
Se la tua variabile non sta cambiando e devi valutarla nella tua direttiva, puoi usare la $eval
funzione:
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!):
<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>
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 angolare