【问题标题】:Passing parameters to scope function from directive inside ng-repeat从 ng-repeat 中的指令将参数传递给作用域函数
【发布时间】:2015-02-26 06:23:37
【问题描述】:

我正在尝试从指令调用函数并传递参数。回调函数被传递到隔离范围。我有两个问题。首先,当嵌套在 ng-repeat 中时,这根本不起作用;其次,即使不在 ng-repeat 中,我也不知道如何将参数传递给回调函数。这是一个显示问题的 plunker:http://plnkr.co/edit/3FN0o3UE99wsmUpxMe4x?p=preview

请注意,当您单击“This works”时,它至少会从父作用域执行该函数,但是当单击其他作用域时,它什么也不做(因为它们在 ng-repeat 中)。这是第一个问题。

第二个问题是当你点击“This works”时,即使它成功调用了该函数,我也无法弄清楚如何从指令范围传递用户(注意它警告未定义)。

这是一个示例指令(从我的实际应用程序中大大简化):

var app = angular.module('plunker', []);
app.controller("AppCtrl", function($scope) {
  $scope.click = function(user) {
    alert(user)
  }
  $scope.users = [{
    name: 'John',
    id: 1
  }, {
    name: 'anonymous'
  }];
});
app.directive("myDir", function($compile) {
  return {
    scope: {
      user: '=',
      click: '&'
    },
    compile: function(el) {
      el.removeAttr('my-dir');
      el.attr('ng-click', 'click(user)')
      var fn = $compile(el);
      return function(scope, el){
        fn(scope);
      };
    }
  };
});

这里是html:

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angular.js@1.2.x" src="http://code.angularjs.org/1.2.12/angular.js" data-semver="1.2.12"></script>
    <script src="app.js"></script>
  </head>

  <body>
    <div ng-controller="AppCtrl">
        <a my-dir user="{name: 'Works', id: 0}" click="click()">This works</a>
        <a my-dir user="user" click="click()" ng-repeat="user in users"><br>{{user.name}}</a>
    </div>
  </body>

</html>

谢谢!

【问题讨论】:

    标签: angularjs angularjs-directive angularjs-ng-repeat


    【解决方案1】:

    当然,对于这样的事情,编译功能是不需要的。事实上,从 1.2 开始,编译功能几乎不再需要。我见过的唯一可能需要编译函数的指令是 ng-repeat 指令本身,我什至不相信这是真的。

    要记住的重要一点是,当将函数传递给要调用的指令时,当在 html 中指定该函数时,就是绑定参数的时候。所以给定以下控制器(请注意,我将被调用的函数重命名为更明确)

    app.controller("AppCtrl", function($scope) {
      $scope.raiseNotification = function(user) {
        alert(user.name)
      }
    ....
    

    以及以下指令:

    app.directive("myDir", function($compile) {
      return {
        restrict: 'E',
        scope: {
          user: '=',
          click: '&'
        },
        template: '<a ng-click="click()" ><br>{{user.name}}</a>'
      };
    });
    

    如果你想调用这个方法,那么下面的 HTML 就是你想要的

    <div ng-repeat="user in users">
      <my-dir user="user" click="raiseNotification(user)" ></my-dir>
    </div>
    

    当 click 被调用时(注意,指令模板中的 click() 没有自己的参数。这是因为模板中的 click() 本质上是调用 raiseNotification(user) 的包装器,即

    function click() {
      raiseNotification(user);
    }
    

    如果您想从指令中的某处调用 click 函数并覆盖用户绑定的内容,那么您可以这样做:

    click({user:myOtherUser})
    

    这将覆盖“用户”参数所绑定的内容。这是一个非常极端的案例。

    Here's 对 pixelbit 代码的调整,其中包括对指令模板中未指定的用户参数的修复。

    另外,为了好玩,here's 另一个版本更接近您正在做的事情,但使用了链接功能。它不像前面给出的代码那样简洁或优雅,但使用链接函数提供了更多控制,以防您需要对节点上的事件执行更具体的操作。

    【讨论】:

    • 我认为这是我在互联网上看到的关于如何将参数传递给绑定到 AngularJS 中指令的方法的最准确和最全面的解释。谢谢! :)
    【解决方案2】:

    当您尝试重新编译/重新链接已编译或正在编译的指令时,可能会导致此问题。当您尝试重新编译/重新链接指令时,这是一个重要的危险信号,表明您正在做不应该做的事情。

    与其与框架抗争,让它去做不该做的晦涩的事情,不如尝试在框架内工作,你会发现完成这些任务要容易得多。

    首先,这是一个有效的demo

    提示 1: 如果您要重新编译指令 - 不要。这有很多陷阱,而且麻烦多于其价值。而是重新组织您的 HTML,这样您就不必:

    <div ng-controller="AppCtrl">
        <div ng-init="user = {name: 'Works', id: 0}">
          <my-dir user="user"  click="click(user)"></my-dir>
        </div>
    
        <div ng-repeat="user in users">
          <my-dir user="user" click="click(user)" ></my-dir>
        </div>
    </div>
    

    提示 2:如果您使用隔离范围,请在指令中使用模板。模板可以利用隔离范围,并有助于使您的指令更加模块化和可重用。

    app.directive("myDir", function($compile) {
      return {
        restrict: 'E',
        scope: {
          user: '=',
          click: '&'
        },
        template: '<a ng-click="click(user)" ><br>{{user.name}}</a>'
      };
    });
    

    提示 3:不要使用“替换”,因为它已被弃用。相反,如果必须,请使用元素指令。

    Angular 确实对您应该遵循的 HTML 格式施加了一些约定,这可能意味着您的 HTML 包含一些您不希望在最终 HTML 中出现的额外标签。但我了解到,鉴于生产力的提高,这是一个很小的代价。

    【讨论】:

    • 您不需要模板中的“user”参数。这有效:模板:'
      {{user.name}}
      '
    • 像这样在模板中包含用户参数实际上有点误导。它什么也不做,但看起来确实如此。
    • 我只能假设这是个玩笑,因为它真的什么也没做。请参阅以下代码,它完美地工作 plnkr.co/edit/sL01BCEtU5uaA5i8MnBU?p=preview 使用此模板:模板:'
      {{user.name}}
      '跨度>
    • 现在这很愚蠢。我将向 Angular 团队提出这个问题来解决。
    猜你喜欢
    • 2015-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多