AngularJs:使用Angular Directives传递跨多个隔离范围的函数参数

sfl*_*che 9 javascript angularjs

我有3个嵌套的,隔离的范围,指令(参见CodePen),我能够将一个函数(带参数)从最外层的指令传递给最里面的指令(将函数从外部指令传递给中间指令到内部指令) .

我无法理解的是将内部指令中的参数通过中间指令传递回外部指令需要做些什么.

再次,请参阅CodePen示例.

注意:鉴于只有2个隔离范围指令,我可以使用类似于以下内容的方法...

angular.module('myApp', [])
  .directive('myDir1', function() {
    return {
      template: '<div><my-dir-2 add-name="addName(name)"></my-dir-2></div>',
      controller: function($scope) {
        $scope.addName = function(name) {
          alert(name); // alerts 'Henry'
        };
      }
    }
  })
  .directive('myDir2', function() {
    return {
      scope: {
        addName: '&'
      },
      template: "<span ng-click='addName({name: testName})'>Click to Add {{testName}}!</span>",
      controller: function($scope) {
        $scope.testName = 'Henry';
      }
    }
  });
Run Code Online (Sandbox Code Playgroud)

上面的代码给了我一个带有'Henry'的警告框(就像我期望的那样).

当我添加第三个中间隔离范围指令时,我遇到了问题......

angular.module('myApp', [])
  .directive('myDir1', function() {
    return {
      template: '<div><my-dir-2 add-name="addName(name)"></my-dir-2></div>',
      controller: function($scope) {
        $scope.addName = function(name) {
          alert(name); // alerts 'Henry'
        };
      }
    }
  })
  .directive('myDir2', function() {
    return {
      scope: {
        addName: '&'
      },
      template: '<div><my-dir-3 add-name="addName({name: testName})"></my-dir-3></div>',
    }
  })
  .directive('myDir3', function() {
    return {
      scope: {
        addName: '&'
      },
      template: "<span ng-click='addName({name: testName})'>Click to Add {{testName}}!</span>",
      controller: function($scope) {
        $scope.testName = 'Henry';
      }
    }
  });
Run Code Online (Sandbox Code Playgroud)

这段代码给了我一个警告框undefined......

Joe*_*ger 23

一个常见的误解是"&是为了传递功能".这在技术上是不正确的.

什么&是在指令范围上创建一个函数,在调用时,它返回针对父范围计算的表达式的结果.

此函数将一个对象作为一个参数,该参数将覆盖表达式中的局部变量,{name: testName}在本例中使用指令范围()对象中的局部变量.

如果你要深入了解,那么$scope.addName方法myDir2将如下所示(简化):

$scope.addName = function(locals) {
    return $parse(attr.addName)($scope.$parent, locals);
}
Run Code Online (Sandbox Code Playgroud)

你的第二个指令是有效的,因为它绑定的表达式是

addName(name)
Run Code Online (Sandbox Code Playgroud)

该表达式有一个局部变量name,在执行时用指令覆盖testName的值

addName({name: testName}) //in the directive. 
Run Code Online (Sandbox Code Playgroud)

记住-该addName函数myDir2是不相同addName的功能myDir1.它是一个评估表达式的新函数

addName(name) 
Run Code Online (Sandbox Code Playgroud)

针对父作用域并返回结果.

将此逻辑应用于时myDir3,计算的表达式为:

addName({name: testName})
Run Code Online (Sandbox Code Playgroud)

请注意,此表达式中唯一的局部变量是"testName".所以,当你调用myDir3

addName({name: testName})
Run Code Online (Sandbox Code Playgroud)

没有name要覆盖的局部变量,并且testName未定义.

唷!难怪这只会让每个人都感到困惑!

如何解决您的示例:

您希望表达式计算为实际函数myDir1.

angular.module('myApp', [])
  .directive('myDir1', function() {
    return {
      template: '<div><my-dir-2 add-name="addName"></my-dir-2></div>',
      controller: function($scope) {
        $scope.addName = function(name) {
          alert(name); // alerts 'Henry'
        };
      }
    }
  })
  .directive('myDir2', function() {
    return {
      scope: {
        addName: '&'
      },
      // addName() returns the actual function addName from myDir1
      template: '<div><my-dir-3 add-name="addName()"></my-dir-3></div>',
    }
  })
  .directive('myDir3', function() {
    return {
      scope: {
        addName: '&'
      },
      //calls addName() on myDir2, which returns addName from myDir1, then invokes it passing testName as an argument
      template: "<span ng-click='addName()(testName)'>Click to Add {{testName}}!</span>",
      controller: function($scope) {
        $scope.testName = 'Henry';
      }
    }
  });
Run Code Online (Sandbox Code Playgroud)

这是工作笔

最后的注意事项 - 之所以'&''='这更合适的原因是,'='它实际上是建立一个$watch双向绑定指令之间的变量.这意味着,myDir2实际上可以改变功能appNamemyDir1,不要求并不可取.它还需要设置两个$watchs,我试图避免在Angular中出于性能原因.


Avi*_*ked 5

有两种方法可以在隔离范围内传递函数。虽然“&”将确保您传递的实际上是一个函数,但您也可以将函数作为带有“=”的绑定变量传递,并仅在需要时调用它。这种方法有缺点,但它将调用的控制权留给负责该调用的组件。

你的代码笔工作

angular.module('myApp', [])
 .directive('myDir1', function() {
    return {
      template: '<div><my-dir-2 add-name="addName"></my-dir-2></div>',
      controller: function($scope) {
        $scope.addName = function(name) {
        alert(name);
      };
    }
  }
})
.directive('myDir2', function() {
  return {
    scope: {
      addName: '='
    },
    template: '<div><my-dir-3 add-name="addName"></my-dir-3></div>'
  }
})
.directive('myDir3', function() {
  return {
    scope: {
      addName: '='
    },
    template: "<span ng-click='addName(testName)'>Click to Add {{testName}}!</span>",      
    controller: function($scope) {
      $scope.testName = "Henry"
    }
  }
});
Run Code Online (Sandbox Code Playgroud)