我有一个Angular指令,它实现了一个本质上是自定义的组合框。单击输入控件会在其下方显示另一个div,并显示模型对象中包含的div列表。您可以在输入控件中键入文本,并过滤下面的div列表。
我有几个单独的按钮对象(不是指令的一部分,但在同一范围内)调用$ scope.clearFilter()或$ scope.unselectAll()等方法,而这些方法又调用directiveScope.clearFilter ()或directiveScope.unselectAl()。 directiveScope是组合框指令和主控制器之间的共享对象。它使控制器能够直接调用指令上的方法。
我整理了一个小Plunker,展示了我目前的表现。这是"本着"的精神。示例类型,而不是我的确切代码(许可证问题)。
// HTML
<my-directive sharedobj="myDirective1"></my-directive>
<input type="button" ng-click="clearFilterText1()" value="Clear"/><br/><br/>
// JS
var app = angular.module( 'Test', [] );
app.controller( 'MyController', [ '$scope', function( $scope ) {
$scope.myDirective1 = {};
$scope.myDirective2 = {};
$scope.clearFilterText1 = function() {
console.log("Calling directive 1");
$scope.myDirective1.clearFilterText();
}
$scope.clearFilterText2 = function() {
console.log("Calling directive 2");
// QUESTION: If calling this directive method is bad practice, what is
// equivalent good practice?
$scope.myDirective2.clearFilterText();
}
}]);
app.directive( 'myDirective', function() {
return {
template: "<div><input type='text' ng-model='filterText'/></div>",
scope: {
sharedobj: "="
},
restrict: 'E',
replace: true,
link: function( scope, elem, attrs ) {
// This is the text that the directive will show, and it is conceptually private
// to the directive, so I'd rather not put this into the controller scope.
scope.filterText = "filter this!";
// This method is on the "sharedobj" that is linked into the controller.
// The controller is able to call this method directly, which updates
// the view state. This simply updates "view state".
scope.sharedobj.clearFilterText = function() {
console.log("Setting filter text!");
scope.filterText = "";
}
}
};
});
我被告知有一个Angular控制器直接调用指令上的方法并不是一个好设计,但根据Wikipedia's page on MVC:
控制器可以向模型发送命令以更新模型的状态(例如, 编辑文件)。 它还可以将命令发送到其关联的视图 改变视图的模型表示(例如,通过滚动 通过文件)。
如果&#34;发送命令&#34;这听起来就像我在做什么是&#34;调用函数&#34;的同义词,如果你考虑指令a&#34; view&#34;,我这样做,因为指令本质上是HTML的扩展。
我已经看到像this one这样的StackOverflow帖子也暗示它是一个坏主意(没有理由担任该职位),但是实施单独服务来处理这种状态的建议替代方案似乎就像一个不必要的复杂解决方案,特别是因为我有这些组合框指令的多个实例。你最终得到的指令甚至不知道它自己的视图状态,这看起来非常错误。
我不明白为什么要调用SomeService.clearFilter(),然后设置一些&#34; state&#34;该指令必须为$ watch(),比调用someDirective.clearFilter()并避免所有开销更好。控制器仍然需要知道清除过滤器。它只需要注入SomeService而不是连接到指令。
所以,Angular / MVC专家,请告诉我为什么这是错误的(或者为什么它没问题)! : - )
感谢。
答案 0 :(得分:1)
过滤器是一个视图问题。我会将它们注入控制器,但我不会在服务中实现它们。
服务(代表模型)不应该对视图有任何了解。
在您的示例中,视图应调用控制器,然后控制器调用范围方法。范围方法应该定义过滤逻辑(这是控制器的工作 - 调解视图和模型之间的交互(由服务表示))。
这种关注点分离代表了一种分层设计,其中明确定义了模型,视图和控制器的职责。有一种最佳实践,那就是将它们分开。
在我看来,在服务中定义了一个过滤器,它暴露了一个模型,然后被范围观察是糟糕的设计。
注意:当我说过滤是一个视角问题时,我的意思是角度过滤器 - 它们的目的是保持过滤后的模型和视图同步,所以我认为它们是视图关注点。
答案 1 :(得分:1)
看到这个的简单方法是,指令被认为是独立的或添加行为。当你通过一个控制器调用它们的函数时,实际上你的指令取决于该控制器的存在,而不是它可能/应该是可重用的。
还有其他方法可以在不将viewController与指令结合的情况下实现相同的结果,但它取决于每个特定情况,所以如果没有更多信息我无法帮助您:(
干杯
答案 2 :(得分:-1)
This article,虽然没有专门解决“不良做法”问题,但确实提供了一种组织指令和控制器的好方法,而恰好是关于下拉指令。