javascript - link - ng-model
Métodos de la directiva de llamadas desde el controlador principal en AngularJS (5)
Estoy usando AngularJS con el patrón de controladores de alias. No puedo acceder (o no sé cómo) los métodos de directiva de un controlador principal.
Tengo una función dentro de mi controlador que debe llamar a un método directivo, pero este método directivo no está disponible dentro del valor de this
controlador.
Esto es lo que tengo. ¿Que estoy haciendo mal?
JS
angular.module(''myApp'', []).
controller(''MyCtrl'', function(){
this.text = ''Controller text'';
this.dirText = ''Directive text'';
this.click = function(){
this.changeText();
}
})
.directive(''myDir'', function(){
return {
restrict: ''E'',
scope: {
text: ''=''
},
link: function(scope, element, attrs){
scope.changeText = function(){
scope.text = ''New directive text'';
};
},
template: ''<h2>{{text}}</h2>''
};
});
HTML
<div ng-app="myApp">
<div ng-controller="MyCtrl as ctrl">
<h1>{{ctrl.text}}</h1>
<my-dir text="ctrl.dirText"></my-dir>
<button ng-click="ctrl.click()">Change Directive Text</button>
</div>
</div>
Here un codepen con el código.
Después de probar tanto la solución de $broadcast
como la de objeto de control
, realmente recomendaría tratar de vincular valores o matrices. El objeto de control
es una forma simple de lograr el resultado deseado, pero en mi prueba es muy difícil de detectar y propenso a errores.
Este Codepen construye el ejemplo de BernardV , pero usa una matriz de mensajes como un enlace de control muy visible. Si lo desea, también puede $watch
fácilmente la matriz de mensajes dentro de la directiva. La idea central es en el uso de la directiva:
scope: { messages: "=", room: "@" },
Desde un controlador (que tiene una matriz de "salas") harías esto:
$scope.addMessages = function () {
angular.forEach($scope.rooms, function(room, index) {
room.messages.push("A new message! # " + (index+1);
})
}
Directivas independientes, mensajes independientes y altamente reconocibles. Por supuesto, en la directiva solo se podría mostrar el último mensaje, o simplemente enlazar una cadena en lugar de una matriz. Esta solución funcionó mucho mejor para nosotros al menos.
Está aislando el alcance cuando escribe:
scope: {
text: ''=''
},
Aquí hay una versión ligeramente modificada de su código, esta vez, le permite llamar al método directivo. En general, me deshice de ''scope''
directiva ''scope''
y la cambié a usar $ scope en el controlador, en lugar de esto, y el patrón Alias ...
ADVERTENCIA: Es posible que esto no refleje el comportamiento correcto, con respecto a las variables que cambian, pero responde a su pregunta mostrando cómo puede acceder al método de la directiva desde el controlador. Por lo general, esta no es una buena idea de diseño.
http://codepen.io/anon/pen/azwJBm
angular.module(''myApp'', []).
controller(''MyCtrl'', function($scope){
var that = this;
$scope.text = ''Controller text'';
$scope.dirText = ''Directive text'';
$scope.click = function(){
$scope.changeText();
}
}).
directive(''myDir'', function(){
return {
restrict: ''E'',
/* scope: {
text: ''=''
},*/
link: function(scope, element, attrs){
scope.changeText = function(){
scope.text = ''New directive text'';
};
},
template: ''<h2>{{text}}</h2>''
};
});
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<h1>{{text}}</h1>
<my-dir text="dirText"></my-dir>
<button ng-click="click()">Change Directive Text</button>
</div>
</div>
Puede lograr los métodos de directivas de llamada sin depender de $ broadcast o eliminar el aislamiento de ámbito. Los enfoques similares que se han publicado aquí hasta ahora se romperán si hay más de 2 instancias de la directiva en una página (todos reflejarán los mismos cambios).
Este codepen demuestra una forma más robusta de hacerlo.
angular.module(''myApp'', [])
.controller(''myChat'', function($scope) {
function room () {return { accessor:{} }; }
$scope.rooms = { ''RoomA'': new room, ''RoomB'': new room, ''RoomC'': new room };
$scope.addMessageTo = function(roomId, msg) {
if ($scope.rooms[roomId].accessor.setMessage)
$scope.rooms[roomId].accessor.setMessage(msg);
};
$scope.addMessages = function () {
$scope.addMessageTo("RoomA", "A message");
$scope.addMessageTo("RoomB", "Two messages");
$scope.addMessageTo("RoomC", "More messages");
}
}).directive(''myChatRoom'', function() {
return {
template: ''<div>{{room}} message = {{message}}<div />'',
scope: { accessor: "=", room: "@" },
link: function (scope) {
if (scope.accessor) {
scope.accessor.setMessage = function(msg) {
scope.message = msg;
};
}
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myChat">
<div ng-repeat="(roomId, room) in rooms">
<div my-chat-room room="{{roomId}}" accessor="room.accessor"></div>
</div>
<button ng-click="addMessages()">Add messages to rooms</button>
</div>
</div>
Si estrictamente desea utilizar el scope
aislado dentro de una directiva, entonces el método de directiva solo puede invocarse mediante el uso de eventos angulares tales como $broadcast
y $emit
En su caso, debe usar $broadcast
para enviar el evento a $rootScope
Tu código se volverá así.
HTML
<div ng-app="myApp">
<div ng-controller="MyCtrl as ctrl">
<h1>{{ctrl.text}}</h1>
<my-dir text="ctrl.dirText"></my-dir>
<button ng-click="ctrl.click()">Change Directive Text</button>
</div>
</div>
CÓDIGO
angular.module(''myApp'', []).
controller(''MyCtrl'', function($rootScope){
var that = this;
this.text = ''Controller text'';
this.dirText = ''Directive text'';
this.click = function(){
$rootScope.$broadcast(''changeText'',{});
}
}).
directive(''myDir'', function(){
return {
restrict: ''E'',
scope: {
text: ''=''
},
link: function(scope, element, attrs){
scope.changeText = function(){
scope.text = ''New directive text'';
};
scope.$on(''changeText'',function(event, data){
scope.changeText()
});
},
template: ''<h2>{{text}}</h2>''
};
});
En lugar de llamar al método del alcance del niño, necesita transmitir un evento que tendrá que ser escuchado por el alcance de la directiva y disparará el método changeText
después de escuchar ese evento.
NOTA
Usar el servicio / fábrica sería un mejor enfoque.
Espero que esto te ayude. Gracias.
Tengo otra solución que te permite usar el alcance aislado y no depender de la transmisión. En los métodos javascript se pueden usar como variables, co simplemente puede pasar el método que desee a la directiva.
entonces en html:
<my-dir text="ctrl.dirText" change-text="ctrl.changeText"></my-dir>
y en directiva
scope: {
text: ''='',
changeText: ''=''
}
Here hay un codepen ligeramente modificado, donde puedes ver lo que tengo en mente.