angularjs - switch - ¿Cómo invocar ng-click desde una directiva parcial?
ng-if (2)
Tengo una directiva que tiene un ámbito local donde un parcial contiene ng-clic.
El violín está allí: http://jsfiddle.net/stephanedeluca/QRZFs/13/
Desafortunadamente, como moví mi código a la directiva, ng-click ya no dispara.
El controlador y la directiva son los siguientes:
var app = angular.module(''myApp'', [''ngSanitize'']);
app.directive(''plantStages'', function ($compile) {
return {
restrict: ''E'',
transclude: true,
template: ''<figure class="cornStages">/
<p ng-transclude style="color: skyblue"></p>/
<hr/>/
<p ng-bind-html="title"></p>/
<p ng-bind-html="subtitle">{{subtitle}}</p>/
<ul>/
<li ng-repeat="stage in stages" ng-click="changePage(stage)">{{stage}}</li>/
</ul>/
</figure>'',
scope: {
stages:"=",
title:''@''
},
link: function (scope, element, attrs, ctrl, transclude) {
if (!attrs.title) scope.title = "Default title";
}
};
});
app.controller(''myCtrl'', function ($scope, $location, $http) {
$scope.stages = [''floraison'', ''montaison''];
$scope.changePage = function (page) {
var url = "corn.page.html#/"+page;
console.log("Change page "+page+" with url "+url);
alert("about to change page as follows: document.location.href = "+url);
};
});
El html que lo invoca es el siguiente:
<div ng-controller="myCtrl">
Stages,
<p ng-repeat="stage in stages">{{stage}}</p>
<hr/>
Plant stages
<plant-stages
title="<b>Exploration<br/>du cycle</b>"
subtitle="<em>This is a<br/>sub title</em>"
stages="stages"
>
Inner<br/>directive
</plant-stages>
</div>
¿Alguna idea?
La idea de las directivas es tratarlas como componentes reutilizables y evitar dependencias externas siempre que sea posible. Si tiene la posibilidad de definir el comportamiento de su directiva en su propio controlador, hágalo.
module.directive(''myDirective'', function () {
return {
restrict: ''E'',
controller: function() { /* behaviour here */ },
template: ''<div>Directive Template</div>'',
scope: {
/* directive scope */
}
};
});
Si esto no es posible, puede pasar la función como se explica en la pregunta vinculada (ver el comentario anterior). Compruebe el violín actualizado .
No se puede acceder a changePage()
definido en el ámbito del controlador directamente desde la directiva, ya que su directiva tiene un alcance aislado. Sin embargo, todavía hay varias formas de hacerlo:
Opción 1:
La opción 1 es la opción más simple. Sin embargo, es muy parecido a una solución alternativa y no recomiendo usarla ampliamente. Puede obtener el alcance de su controlador del elemento pasado a la función de enlace e invocar changePage
allí:
link: function (scope, element, attrs, ctrl, transclude) {
if (!attrs.title) scope.title = "Default title";
scope.changePage = element.scope().changePage; // <= Get parent scope from element, it will have changePage()
}
Opcion 2:
Si no tiene ninguna lógica que implique alcance definido en el controlador externo (como en su ejemplo), puede definir el controlador interno para su directiva y realizarlo allí:
app.directive(''plantStages'', function ($compile) {
return {
...
controller: [''$scope'', function($scope) {
$scope.changePage = function(page) {
var url = "corn.page.html#/"+page;
console.log("Change page "+page+" with url "+url);
alert("about to change page as follows: document.location.href = "+url);
}
}]
};
});
Opción 3:
Si desea reutilizar la lógica definida en changePage()
en diferentes directivas y controladores, la mejor manera de hacerlo es mover la lógica a algún servicio que pueda ser inyectado tanto al controlador como a la directiva:
app.service(''changePageService'', function() {
this.changePage = function(page) {
var url = "corn.page.html#/"+page;
console.log("Change page "+page+" with url "+url);
alert("about to change page as follows: document.location.href = "+url);
}
});
app.controller(''myCtrl'', function ($scope, $location, $http, changePageService) {
...
changePageService.changePage(''page'');
...
});
app.directive(''plantStages'', function ($compile) {
...
controller: [''$scope'', ''changePageService'', function($scope, changePageService) {
$scope.changePage = changePageService.changePage;
}]
...
});
Opción 4:
Puede pasar un fragmento de código como changePage(page)
como valor de algún atributo de la directiva y dentro de la directiva definir propiedad de alcance con ''&''
que creará una función que se ejecutará en el alcance del controlador externo con argumentos pasados a esa función. Ejemplo:
JavaScript
app.directive(''plantStages'', function ($compile) {
return {
restrict: ''E'',
transclude: true,
template: ''<figure class="cornStages">/
<p ng-transclude style="color: skyblue"></p>/
<hr/>/
<p ng-bind-html="title"></p>/
<p ng-bind-html="subtitle"></p>/
<ul>/
<li ng-repeat="stage in stages" ng-click="changePage({page: stage})">{{stage}}</li>/
</ul>/
</figure>'',
scope: {
stages:"=",
title:''@'',
changePage:''&''
},
link: function (scope, element, attrs, ctrl, transclude) {
if (!attrs.title) scope.title = "Default title";
}
};
});
HTML
<div ng-controller="myCtrl">
Stages,
<p ng-repeat="stage in stages">{{stage}}</p>
<hr/>
Plant stages
<plant-stages
title="<b>Exploration<br/>du cycle</b>"
subtitle="<em>This is a<br/>sub title</em>"
stages="stages"
change-page="changePage(page)"
>
Inner<br/>directive
</plant-stages>
Plunker: http://plnkr.co/edit/s4CFI3wxs0SOmZVhUkC4?p=preview