独自のコントローラーを持つディレクティブがあります。以下のコードを参照してください。
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
を呼び出すと、リンク関数もトリガーされ、アニメーションを実行する必要があります。どうすればそれを達成できますか?
これは興味深い質問であり、私はこのようなものをどのように実装するかについて考え始めました。
this(fiddle) ;を思いつきました。
基本的に、コントローラーからディレクティブを呼び出そうとする代わりに、すべてのポップダウンロジックを格納するモジュールを作成しました。
var PopdownModule = angular.module('Popdown', []);
モジュールには2つの要素を配置します。どこにでも挿入できるAPIのfactory
と、実際のポップダウン要素の動作を定義するdirective
です。
ファクトリは、いくつかの関数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>
それが完全に理想的かどうかはわかりませんが、グローバルなポップダウンディレクティブとの通信を設定するための合理的な方法のように思えました。
繰り返しますが、参照用に、 フィドル 。
イベントを使用してポップダウンをトリガーすることもできます。
これはフィドルです satchmorunのソリューションに基づきます。 PopdownAPIが不要になり、代わりにトップレベルのコントローラーが$broadcast
sの「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();
});
これは少なくとも動作し、私にはうまく分離されたソリューションのようです。何らかの理由でこれが悪い習慣だと思われる場合は、他の人に声をかけさせます。
ngForm
属性を指定したname
のように、ディレクティブのコントローラーを親スコープに公開することもできます。 http://docs.angularjs.org/api/ng.directive:ngForm
ここでは、どのようにそれを達成できるかという非常に基本的な例を見つけることができます http://plnkr.co/edit/Ps8OXrfpnePFvvdFgYJf?p=preview
この例では、$clear
メソッド(ディレクティブ用の非常に単純なパブリックAPI)を備えた専用コントローラーを備えたmyDirective
があります。このコントローラーを親スコープに公開し、ディレクティブの外部でこのメソッドを呼び出すことができます。
私ははるかに良い解決策を得た。
ここに私のディレクティブがあり、ディレクティブ内のオブジェクト参照に注入し、ディレクティブコードに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>
私のコントローラー:
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();
}];