在AngularJS指令内调用传入的函数

时间:2014-08-22 18:53:10

标签: javascript angularjs angularjs-directive

我正在创建一个drag指令来向dragstart事件添加一个事件监听器。我想将一个函数从我的控制器传递给指令。当我添加事件监听器时,它不会调用传入的函数。

这是我的控制器:

angular.module('testApp').controller('testCtrl', [testCtrl]);

function testCtrl() {
    var vm = this;
    vm.dragStart = dragStart;

    function dragStart(e){
        alert('drag started!', e);
    }

}

这是我的指示:

angular.module('testApp').directive('testDraggable', function(){
    var directive = {
        scope: {
            dragStart: '&',
        },
        restrict: 'A',
        link: link
    };

    function link(scope, element, attrs){
        var dragStartCallback = function(event){
            alert('dragStartCallback!');
            scope.dragStart({e: event});
        }

        element[0].addEventListener('dragstart', dragStartCallback, false);
    }
    return directive;
});

我遇到的问题是调用了dragStartCallback函数,但从未调用内部scope.dragStart函数。我已经阅读了关于映射参数的信息,这正是我正在做的事情,但它仍然失败了。在dragStartCallback中,我也正确地传递了事件。如果有更好的方法可以做任何建议,我们将不胜感激。

提前感谢您的任何输入。这里有一个JS小提琴:http://jsfiddle.net/6sk4dbre/

3 个答案:

答案 0 :(得分:2)

在指令范围绑定中使用名称dragStart时出现问题。将其更改为其他内容,您的代码将起作用。

var directive = {
    scope: {
        ds: '&',
    },

http://jsfiddle.net/wittwerj/7vnxjxsq/

正如@miensol所指出的,这是由于Migrating from 1.0 to 1.2 guide中记录的变化:

  

指令不能以-start或-end结尾
  此更改是启用多元素指令所必需的。最好的解决方法是重命名现有指令,以便它们不会以这些后缀结束。

显然这也适用于属性。

答案 1 :(得分:2)

正如@ j.wittwer所述,如果您更改范围绑定的名称,即

scope: {
  dragStart:'&startDragging'
}

然后在指令中使用它start-dragging="vm.startDrag(e)"它将起作用。

这与ng-repeat(版本1.2)中引入的功能有关,您可以使用{{1}在重复的元素中定义标题正文和页脚 }和ng-repeat-start。您可以在documentation中找到有关此语法的更多信息。

似乎相当不幸的是,影响角度中的所有指令(和属性)(至少在版本1.2.1中)的这种变化仅在migration guide 中提及,并且非常容易如果你不知道该找什么,特别想念。

然而,有趣的是要知道为什么这种行为存在于角度中。

罪魁祸首代码可以在ng-repeat-end(版本1.2.1中的第5600行)中找到,您可以在其中看到:

collectDirectives

current source on github中提到的代码更改为:

var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
if (ngAttrName === directiveNName + 'Start') {
    attrStartName = name;
    attrEndName = name.substr(0, name.length - 5) + 'end';
    name = name.substr(0, name.length - 6);
}

所以有问题的行为只会影响var directiveNName = ngAttrName.replace(/(Start|End)$/, ''); if (directiveIsMultiElement(directiveNName)) { if (ngAttrName === directiveNName + 'Start') { 的{​​{1}}指令,这是this pull request中引入的更改。

答案 2 :(得分:1)

@ j.wittwer是正确的,它必须与元素属性dragStart的名称有关,但它不是因为名称是什么,因为出于某种原因,Angular在传递时不喜欢带连字符的属性函数指令属性。这只会将父控制器函数传递给指令。如果你使它dragstart而不是drag-start它会工作正常,当然你的指令需要:

scope : {
    ds : '&dragstart'
}

http://jsfiddle.net/6sk4dbre/5/