自定义事件绑定未正确运行$ digest

时间:2013-09-04 12:28:37

标签: javascript angularjs

我有一个简单的例子 - http://jsfiddle.net/E7crq/4/

var app = angular.module('myapp', []);

app.controller('TestController', function($scope) {
        $scope.selectOption = 1;
});

app.directive('selectableOption', function () {
    return {
         restrict: 'A',
         link: function (scope, element, attributes) {
             $(element[0]).on('myChange', function() {
                 scope.$digest();                 
             });             
             $(element[0]).on('change', function() {
                 scope.$digest();
             });
         }
    };
});

$('button').on('click', function() {
    $('#mainSelect option[value=' + $(this).attr('data-value') + ']').attr('selected', 'selected');
    $('#mainSelect').trigger('change');
});

HTML

<div ng-app="myapp">
    <div ng-controller="TestController">
        <select ng-model="selectOption" id="mainSelect" selectable-option>
            <option value="1">1</option>    
            <option value="2">2</option>    
            <option value="3">3</option>    
        </select>
        <div>
          Option: {{ selectOption }}
        <div>
            <button data-value="1" id="btn1">1</button>
            <button data-value="2" id="btn2">2</button>
            <button data-value="3" id="btn3">3</button>
    </div>
</div>

目前的编写方式,如果您点击任意123按钮,它会更新范围和所选值。如果您将最后一行代码触发的事件从'change'更改为'myChange',则该代码不再有效。

我想这是因为Angular已经拥有change事件的处理程序。我需要做些什么才能使myChange事件发挥作用?

2 个答案:

答案 0 :(得分:1)

这是因为只更改select的值不会更新model,select指令会监听change事件,并在何时发生更新模型。

在您的情况下,我建议您在指令中的change处理程序中触发myChange事件。

app.directive('selectableOption', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attributes) {
            $(element).on('myChange', function () {
                element.trigger('change')
            });
        }
    };
});

$('button').on('click', function () {
    $('#mainSelect').val($(this).data('value'));
    $('#mainSelect').trigger('myChange');
});

要设置select的值,请使用.val()

演示:Fiddle

答案 1 :(得分:1)

我完全不同意这一系列的解决方案,因为你要在Angular之外使用jQuery来执行Angular的事情。

首先 - 您可以在controller的$范围内执行您想要的所有操作。第二 - 您也可以在指令中解决这个问题 - 但如果您要在Angular中进行编码,使用Angular语法。

我已经在http://jsfiddle.net/m3DDK/1/中更改了jsFiddle,因此您可以看到如何摆脱您的jQuery。 (这是邪恶的; - )

要注意的两件事 - 您的控制器应如下所示:

$scope.setSelected = function (e) {
    e.preventDefault();
    e.stopPropagation();
    var valueNum = e.target.id.substr('btn'.length);
    $scope.selectOption = valueNum;
    $scope.$broadcast('myChange', valueNum);
};

和你这样的HTML代码:

        <div>
            <button ng-click="setSelected($event)" id="btn1">1</button>
            <button ng-click="setSelected($event)" id="btn2">2</button>
            <button ng-click="setSelected($event)" id="btn3">3</button>
        </div>

这可以进一步清理(如果你将使用ng-repeat)但我离开了你的处理。

然后在你的指令中,我为onChange事件创建了一个可选的监听器:

app.directive('selectableOption', function () {
return {
    restrict: 'A',
    link: function (scope, element, attributes) {
        scope.$on('myChange', function (event, valueNum) {
            //angular.element(element.children()[valueNum]).attr('selected', 'selected');
        });
    }
};

});

总之 - 查看小提琴,摆脱你的jQuery。你不需要它,Angular比那更强大。 另外一个重要提示 - 指令链接中的element已经是一个jQuery元素。