angularjs: 无法通过独立指令范围内的“&”绑定将参数传递给父控制器方法

angularjs: can' t pass parameter to the parent controller method via '&' binding in isolated directive scope

在我的 angular 应用程序中,我定义了一个指令 foo-directive,它被放置在父控制器中,如下所示:

<div ng-app="app">
    <div ng-controller="ParentCtrl as parent">
       <foo-directive data="parent.city" tab-click="parent.tClick()" tab-click2="parent.tClick2(v)"></foo-directive>
    </div>
</div>

将两个方法:parent.tClick()parent.tClick2(v) 传递到指令中并分别绑定到 tab-clicktab-click2 属性。不同的是第二个有个参数

JS代码如下:

function ParentCtrl($timeout){
    this.city= "London";
    this.tClick = function(){
        console.log("debugging parent tclick...");
    }
    this.tClick2 = function(v){
        console.log("debugging parent tclick2...");
        console.log(v)
    }
}

function FirstCtrl() {
    this.$onInit = function(){
         this.click = function(){
             this.tabClick();
             this.tabClick2("abc");
         }
    }
}

function fooDirective() {
    return {
        scope: {
            data: '=',
            tabClick : "&",
            tabClick2: "&"
        },
        controller: 'FirstCtrl',
        controllerAs: 'foo',
        bindToController: true,
        template: '<div ng-click="foo.click()">{{ foo.data }}</div>',
        link: function ($scope, $element, $attrs, $ctrl) {
            //console.log($ctrl.name);
        }
   };
}

现在问题来自第二种方法this.tabClick2("abc")。有 TypeError 消息。我已经通过这个现场演示重现了这个问题:

https://jsfiddle.net/baoqger/sv4d03hk/1/

有什么帮助吗?

为您的 "FirstCtrl" 尝试以下代码片段:

function FirstCtrl() {
    this.$onInit = function(){
        this.click = function(){
            this.tabClick({v: this.data});
        }
    }
}

当您使用表达式绑定 (&) 时,您需要使用包含 "v" 及其值的 JSON 显式调用它。像下面这样:

this.tabClick({v: this.data});

将函数传递给指令时,应将 "reference" 传递给函数,而不是函数的 "result"。加上括号,其实就是执行函数,返回结果给指令。由于函数 returns 都不是一个值,因此它们都将传递 undefined.

鉴于您要传递给函数的参数值 (v) 在指令范围内,而不是父级的范围内,您甚至不需要告诉指令函数接受一个参数。您只需将它传递给指令内的函数即可。即

<foo-directive data="parent.city" tab-click="parent.tClick" tab-click2="parent.tClick2"></foo-directive>

According to the docs,使用&就是你要评估属性的结果:

The & binding allows a directive to trigger evaluation of an expression in the context of the original scope, at a specific time.

相反,我们希望能够执行传递的属性,特别是给它一个变量。因此,=(双向绑定)或 @(单向绑定)可能更适合我们所追求的。

tabClick: "=",
tabClick2: "="

您也可以通过更新模板完全取消控制器。

template: '<div ng-click="foo.tabClick();foo.tabClick2(data)">{{ foo.data }}</div>'

Updated JSFiddle

function ParentCtrl($timeout) {
  this.city = "London";
  this.tClick = function() {
    console.log("debugging parent tclick...");
  }
}

function FirstCtrl() {}

function fooDirective() {
  return {
    scope: {
      data: '=',
      tabClick: "="
    },
    controller: 'FirstCtrl',
    controllerAs: 'foo',
    bindToController: true,
    template: '<div ng-click="foo.tabClick(data)">{{ foo.data }}</div>',
    link: function($scope, $element, $attrs, $ctrl) {
      //console.log($ctrl.name);
    }
  };
}

angular
  .module('app', [])
  .directive('fooDirective', fooDirective)
  .controller('FirstCtrl', FirstCtrl)
  .controller('ParentCtrl', ParentCtrl)
<script src="https://code.angularjs.org/1.6.2/angular.min.js"></script>
<div ng-app="app">
  <div ng-controller="ParentCtrl as parent">
    <foo-directive data="parent.city" tab-click=":: parent.tClick"></foo-directive>
  </div>
</div>

PS。如果您担心使用 @= 的性能,请考虑使用 :: 的一次性绑定。 IE。 <foo-directive data="parent.city" tab-click=":: parent.tClick" tab-click2=":: parent.tClick2"></foo-directive>