Метод вызова в директивном контроллере от другого контроллера
У меня есть директива с собственным контроллером. См. Приведенный ниже код:
var popdown = angular.module('xModules',[]);
popdown.directive('popdown', function () {
var PopdownController = function ($scope) {
this.scope = $scope;
}
PopdownController.prototype = {
show:function (message, type) {
this.scope.message = message;
this.scope.type = type;
},
hide:function () {
this.scope.message = '';
this.scope.type = '';
}
}
var linkFn = function (scope, lElement, attrs, controller) {
};
return {
controller: PopdownController,
link: linkFn,
replace: true,
templateUrl: './partials/modules/popdown.html'
}
});
Это означает систему уведомлений об ошибках/уведомлениях/предупреждениях. Я хочу сделать это с другого контроллера (а не на директиву), чтобы вызвать функцию show
на этом контроллере. И когда я это сделаю, я также хочу, чтобы моя функция ссылок обнаружила, что некоторые свойства изменены и выполняют некоторые анимации.
Вот пример кода, который иллюстрирует то, о чем я прошу:
var app = angular.module('app', ['RestService']);
app.controller('IndexController', function($scope, RestService) {
var result = RestService.query();
if(result.error) {
popdown.notify(error.message, 'error');
}
});
Таким образом, при вызове show
в директивном контроллере popdown
функция ссылки также должна запускаться и выполнять анимацию. Как я могу это достичь?
Ответы
Ответ 1
Это интересный вопрос, и я начал думать о том, как бы реализовать что-то подобное.
Я придумал этот (скрипка);
В принципе, вместо того, чтобы пытаться вызвать директиву с контроллера, я создал модуль для размещения всей логики всплытия:
var PopdownModule = angular.module('Popdown', []);
Я вложил две вещи в модуль: factory
для API, который можно вставить в любом месте, и directive
для определения поведения фактического элемента всплывающего окна:
factory просто определяет пару функций success
и error
и отслеживает пару переменных:
PopdownModule.factory('PopdownAPI', function() {
return {
status: null,
message: null,
success: function(msg) {
this.status = 'success';
this.message = msg;
},
error: function(msg) {
this.status = 'error';
this.message = msg;
},
clear: function() {
this.status = null;
this.message = null;
}
}
});
Директива получает API, введенный в его контроллер, и наблюдает за api для изменений (я использую bootstrap css для удобства):
PopdownModule.directive('popdown', function() {
return {
restrict: 'E',
scope: {},
replace: true,
controller: function($scope, PopdownAPI) {
$scope.show = false;
$scope.api = PopdownAPI;
$scope.$watch('api.status', toggledisplay)
$scope.$watch('api.message', toggledisplay)
$scope.hide = function() {
$scope.show = false;
$scope.api.clear();
};
function toggledisplay() {
$scope.show = !!($scope.api.status && $scope.api.message);
}
},
template: '<div class="alert alert-{{api.status}}" ng-show="show">' +
' <button type="button" class="close" ng-click="hide()">×</button>' +
' {{api.message}}' +
'</div>'
}
})
Затем я определяю модуль app
, который зависит от Popdown
:
var app = angular.module('app', ['Popdown']);
app.controller('main', function($scope, PopdownAPI) {
$scope.success = function(msg) { PopdownAPI.success(msg); }
$scope.error = function(msg) { PopdownAPI.error(msg); }
});
И HTML выглядит так:
<html ng-app="app">
<body ng-controller="main">
<popdown></popdown>
<a class="btn" ng-click="success('I am a success!')">Succeed</a>
<a class="btn" ng-click="error('Alas, I am a failure!')">Fail</a>
</body>
</html>
Я не уверен, что он полностью идеален, но казалось разумным способом настроить связь с директивой global-ish popdown.
Снова для справки скрипка.
Ответ 2
Вы также можете использовать события для запуска Popdown.
Здесь сценарий на основе решения satchmorun. Он распределяет с PopdownAPI и контроллер верхнего уровня вместо $broadcast
'success' и 'error' события вниз по цепочке видимости:
$scope.success = function(msg) { $scope.$broadcast('success', msg); };
$scope.error = function(msg) { $scope.$broadcast('error', msg); };
Затем модуль Popdown регистрирует функции обработчика для этих событий, например:
$scope.$on('success', function(event, msg) {
$scope.status = 'success';
$scope.message = msg;
$scope.toggleDisplay();
});
Это работает, по крайней мере, и кажется мне приятным решением. Я позволю другим перезвонить, если по какой-то причине это считается плохой практикой.
Ответ 3
Вы также можете выставить контроллер директивы в родительскую область, например, ngForm
с атрибутом name
: http://docs.angularjs.org/api/ng.directive:ngForm
Здесь вы можете найти очень простой пример того, как это может быть достигнуто http://plnkr.co/edit/Ps8OXrfpnePFvvdFgYJf?p=preview
В этом примере у меня есть myDirective
с выделенным контроллером с методом $clear
(вроде простого простого публичного API для директивы). Я могу опубликовать этот контроллер в родительской области и использовать этот метод вне директивы.
Ответ 4
Я получил гораздо лучшее решение.
вот моя директива, я ввел в ссылку на объект в директиве и расширил ее, добавив функцию invoke в директивный код.
app.directive('myDirective', function () {
return {
restrict: 'E',
scope: {
/*The object that passed from the cntroller*/
objectToInject: '=',
},
templateUrl: 'templates/myTemplate.html',
link: function ($scope, element, attrs) {
/*This method will be called whet the 'objectToInject' value is changes*/
$scope.$watch('objectToInject', function (value) {
/*Checking if the given value is not undefined*/
if(value){
$scope.Obj = value;
/*Injecting the Method*/
$scope.Obj.invoke = function(){
//Do something
}
}
});
}
};
});
Объявление директивы в HTML с параметром:
<my-directive object-to-inject="injectedObject"></ my-directive>
my Controller:
app.controller("myController", ['$scope', function ($scope) {
// object must be empty initialize,so it can be appended
$scope.injectedObject = {};
// now i can directly calling invoke function from here
$scope.injectedObject.invoke();
}];