escape - ng-bind-html angularjs
La forma más fácil de pasar una variable de ámbito AngularJS de directiva a controlador? (2)
Espere hasta que angular haya evaluado la variable
He tenido muchas vueltas con esto, y no pude hacerlo funcionar incluso con la variable definida con "="
en el alcance. Aquí hay tres soluciones dependiendo de su situación.
Solución n. ° 1
Descubrí que la variable no se evaluó por angular aún cuando se pasó a la directiva. Esto significa que puede acceder y usarlo en la plantilla, pero no dentro de la función del enlace o 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 (¡recuerda 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 función $observe
. 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 la variable no está cambiando).
Solución n. ° 2
Si su variable se crea, por ejemplo, en otro controlador , pero solo necesita esperar hasta que angular lo haya evaluado antes de enviarlo al controlador de la aplicación, podemos usar $timeout
para esperar hasta que se haya ejecutado $apply
. También tenemos que usar $emit
para enviarlo al controlador de 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 n. ° 3
Si su variable no está cambiando y necesita evaluarla en su directiva, puede usar la función $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);
}
});
}]);
Y aquí está el html (¡recuerda 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 FOUC (flash de contenido sin estilo): http://deansofer.com/posts/view/14/AngularJs-Tips-and-Tricks-UPDATED
Para el interesado: he aquí un artículo sobre el ciclo de vida angular
¿Cuál es la forma más fácil de pasar una variable de ámbito AngularJS de directiva a controlador? Todos los ejemplos que he visto parecen tan complejos, ¿no hay alguna forma de que pueda acceder a un controlador desde una directiva, y establecer una de sus variables de ámbito?
Editado en 2014/8/25: Here fue donde lo bifurqué.
Gracias @anvarik.
Aquí está el JSFiddle . Olvidé dónde bifurqué esto. Pero este es un buen ejemplo que te muestra la diferencia entre = y @
<div ng-controller="MyCtrl">
<h2>Parent Scope</h2>
<input ng-model="foo"> <i>// Update to see how parent scope interacts with component scope</i>
<br><br>
<!-- attribute-foo binds to a DOM attribute which is always
a string. That is why we are wrapping it in curly braces so
that it can be interpolated. -->
<my-component attribute-foo="{{foo}}" binding-foo="foo"
isolated-expression-foo="updateFoo(newFoo)" >
<h2>Attribute</h2>
<div>
<strong>get:</strong> {{isolatedAttributeFoo}}
</div>
<div>
<strong>set:</strong> <input ng-model="isolatedAttributeFoo">
<i>// This does not update the parent scope.</i>
</div>
<h2>Binding</h2>
<div>
<strong>get:</strong> {{isolatedBindingFoo}}
</div>
<div>
<strong>set:</strong> <input ng-model="isolatedBindingFoo">
<i>// This does update the parent scope.</i>
</div>
<h2>Expression</h2>
<div>
<input ng-model="isolatedFoo">
<button class="btn" ng-click="isolatedExpressionFoo({newFoo:isolatedFoo})">Submit</button>
<i>// And this calls a function on the parent scope.</i>
</div>
</my-component>
</div>
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;
}
}]);