Espere hasta que angular haya evaluado la variable
Tuve que jugar mucho con esto y no pude hacer que funcionara incluso con la variable definida "="
en el alcance. Aquí hay tres soluciones según su situación.
Solución # 1
Descubrí que la variable aún no había sido evaluada por angular cuando se pasó a la directiva. Esto significa que puede acceder a él y usarlo en la plantilla, pero no dentro del enlace o la función del controlador de la aplicación, a menos que esperemos a que se evalúe.
Si su variable está cambiando o se obtiene a través de una solicitud, debe usar $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);
}
});
}]);
Y aquí está el html (¡recuerde los corchetes!):
<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>
Tenga en cuenta que no debe establecer la variable en "="
en el alcance, si está utilizando la $observe
función. Además, descubrí que pasa objetos como cadenas, por lo que si está pasando objetos, use la solución n. ° 2 o scope.$watch(attrs.yourDirective, fn)
(, o n . ° 3 si su variable no está cambiando).
Solución # 2
Si su variable se crea, por ejemplo, en otro controlador , pero solo necesita esperar hasta que angular la haya evaluado antes de enviarla al controlador de la aplicación, podemos usar $timeout
para esperar hasta que se $apply
haya ejecutado. También necesitamos usar $emit
para enviarlo al controlador de la aplicación de alcance principal (debido al alcance aislado en la directiva):
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;
});
}]);
Y aquí está el html (¡sin corchetes!):
<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>
Solución # 3
Si su variable no cambia y necesita evaluarla en su directiva, puede usar la $eval
función:
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);
}
});
}]);
Y aquí está el html (¡recuerde los corchetes!):
<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>
Además, eche un vistazo a esta respuesta: https://stackoverflow.com/a/12372494/1008519
Referencia para el problema de FOUC (flash of unstyled content): http://deansofer.com/posts/view/14/AngularJs-Tips-and-Tricks-UPDATED
Para los interesados: aquí hay un artículo sobre el ciclo de vida angular.