【问题标题】:Is it 'bad practice' for an Angular controller to call a function on a directive?Angular 控制器在指令上调用函数是“不好的做法”吗?
【发布时间】:2014-10-22 23:27:59
【问题描述】:

我有一个 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

控制器可以向模型发送命令以更新模型的状态(例如, 编辑文档)。 它还可以向其关联视图发送命令 更改模型的视图表示(例如,通过滚动 通过文件)。

如果“发送命令”与“调用函数”同义,并且如果您将指令视为“视图”,我会这样做,这听起来就像我正在做的事情,因为指令本质上是 HTML 的扩展。

我已经看到 StackOverflow 的帖子,例如 this one,这也表明这是一个坏主意(没有理由证明该立场),但实施单独服务来处理这种状态的推荐替代方案似乎是一个不必要的复杂解决方案,尤其是因为我有这些组合框指令的多个实例。你最终会得到一个甚至不知道自己的视图状态的指令,这看起来非常错误。

我不明白为什么调用 SomeService.clearFilter(),然后设置一些指令必须 $watch() 的“状态”,比仅仅调用 someDirective.clearFilter() 并避免所有开销要好。控制器仍然必须知道清除过滤器。它只需要注入 SomeService 而不是连接到指令。

所以,Angular/MVC 专家,请告诉我为什么这是错误的(或者为什么没问题)! :-)

谢谢。

【问题讨论】:

  • MVC 是一个 .. 存储桶术语。考虑 Angular(就像 KO 和 Kendo 一样)基于声明式可观察模型工作;这意味着bucket-term语句需要在上下文中进一步应用。
  • 无论如何,不​​要问“这是好还是坏的做法......”问题(然后为他们辩护),只需询问概述情况的给定任务 -为什么使用当前方法以及与之相关的问题/问题是什么。
  • user2864740:我采取的方法“有效”。 “问题/问题”来自代码审查,其中一位同事认为如果没有控制器到指令的函数调用,设计会更好,并认为这很“奇怪”。此外,任何关于好/坏做法的讨论都必然涉及描述为什么一种方法比另一种更好(也称为“捍卫”它),并且通常需要权衡取舍。

标签: javascript angularjs model-view-controller controller angularjs-directive


【解决方案1】:

过滤器是一个视图问题。我会将它们注入控制器中,但不会在服务中实现它们。

服务(代表模型)不应该知道关于视图的任何信息。

在您的示例中,视图应该调用控制器,然后控制器调用范围方法。 scope 方法应该定义过滤逻辑(这是控制器的工作 - 调解视图和模型(由服务表示)之间的交互)。

这种关注点分离代表了一种分层设计,其中模型、视图和控制器的职责被明确定义。有一个最佳做法,就是将它们分开。

在我看来,在服务内部定义一个过滤器,它会暴露一个模型,然后由作用域监视是不好的设计。

注意:当我说过滤是视图关注点时,我指的是角度过滤器——它们旨在通过使过滤后的模型和视图保持同步来工作,所以我认为它们是视图关注点。

【讨论】:

  • 其实服务不一定是模型。在这个视频中,Mïsko 解释了视图逻辑应该在控制器中,但业务逻辑应该在服务中,这实际上是人们最常犯的错误之一youtube.com/watch?v=ZhfUv0spHCY
  • 我松散地使用术语模型。它代表您的业务层级,因此您和我是一致的。该模型与视图无关,并且不耦合到任何控制器。因此是商业服务。
  • 我的条款可能有点不清楚。它不是 Angular 意义上的“过滤器”。它是指令使用的 Angular 过滤器的输入文本。还有其他一些事情,比如组合框指令是打开还是关闭。如果用户单击组合框外部的某个位置(再次通过调用方法),控制器也能够关闭组合框指令。
【解决方案2】:

看到这一点的简单方法是指令被认为是独立的或添加行为。当您通过控制器调用它们的函数时,您实际上是在使您的指令依赖于该控制器的存在,而不是像它可以/应该那样可重用。

还有其他方法可以在不将 viewController 耦合到指令的情况下实现相同的结果,但这取决于每个具体情况,所以如果没有更多信息,我无法为您提供帮助:(

干杯

【讨论】:

  • 指令不依赖于控制器。控制器使用对指令的引用来通过方法调用更改指令中的某些表示或视图状态。
  • 如果该方法仅通过控制器调用,那么它确实依赖,因为指令本身不足以解决所有问题
  • 看这个的简单方法是,如果你想创建可重用和可测试的组件,你不应该在视图控制器中执行指令函数
  • 抱歉,但这不是定义依赖项的方式。没有人会说指令“取决于”使用它的东西。就像你不会说一个球取决于你扔它。指令不知道使用它们的事物。不过,使用指令的东西肯定取决于它。此外,您的第二条评论中的逻辑是您不应该从控制器执行指令的原因是“您不应该从控制器执行指令”。很圆,你会说吗?
  • 我可能误解了一些东西,但我会问一个问题:“如果删除此控制器,该指令是否仍能达到预期目的?”。如果答案是“是”,则该指令不依赖于该控制器。否则,有。
【解决方案3】:

This article,虽然它没有专门解决“不良做法”问题,但确实提供了一种组织指令和控制器的好方法,并且恰好是关于下拉指令。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多