当使用jQuery的element.val()时,ng-model不会更新。

4

点击此处查看 PLUNKR 示例

我正在使用一些版本的jquery自动完成作为angularjs指令。当jquery使用element.val()更新输入值时,直到下一次脏检查后(我猜)angular才会注意到更改。

我的第一个想法是在使用$timeout执行ng-model post digest上的操作,但是正如您所看到的,这并没有起到帮助作用。

我的第二种方法是覆盖元素的val函数以触发一个input事件,但我还没有成功使其工作。

尝试从自动完成列表中选择一个值,您会发现上面的ng-model没有更新。

更新

感谢回复。我不知道onSelect选项。

这是基于您的建议的代码:

// clone user provided options 
scope.options = _.extend({}, scope.AutoCompleteOptions());

// Wrap onSelect - Force update before manipulation on ng-model
var fn = _.has(scope.AutoCompleteOptions(), 'onSelect')  ? scope.AutoCompleteOptions().onSelect : _.noop;
scope.options.onSelect = function () { 
  ngModelCtrl.$setViewValue(element.val()); 
  scope.$apply(fn);
};

scope.autocomplete = $(element).autocomplete(scope.options);

这样做可以保持指令的界面,同时确保ng-model的更新。谢谢。
4个回答

6

正如你已经知道的那样,问题在于Angular不知道jQuery插件所做的更新。幸运的是,你可以使用插件的onSelect回调来更新ngModel,就像这样:

.directive("autoComplete", function() {
    return {
        restrict: "A" , 
        require: 'ngModel', // require ngModel controller
        scope: {
            AutoCompleteOptions : "=autoCompleteOptions", // use '=' instead of '&'
        },
        link: function (scope, element, attrs, ngModelCtrl) {

            // prevent html5/browser auto completion
            attrs.$set('autocomplete','off');

            // add onSelect callback to update ngModel
            scope.AutoCompleteOptions.onSelect = function() {
                scope.$apply(function() {
                    ngModelCtrl.$setViewValue(element.val());
                });
            };

            scope.autocomplete = $(element).autocomplete(scope.AutoCompleteOptions);
        }
    }
});

1
你正在使用的插件具有一个 onSelect 回调函数,因此你可以简单地修改自动完成参数来包括更新作用域的回调函数。
{
    lookup      : $scope.current,
    width       : 448,
    delimiter   : /,/,
    tabDisabled : true,
    minChars    : 1,
    onSelect: function(v, data) {
        $scope.selected_tags = v.value;
        $scope.$apply();
}

编辑

为了进一步改进,您可以在回调中删除使用模型名称的需求:

function(v, data) {
    var model = $(this).attr("ng-model");
    $scope[model] = v.value;
    $scope.$apply();
}

0

你的jQuery插件正在更新输入框的视图值,但没有更新模型。

你需要修改插件以便访问你的模型或作用域,或者你需要绑定一个事件来手动从视图值更新模型。也许可以像这样:

$scope.format_tags = function () { 

  $scope.selected_tags = $('#myInput').val();
  $scope.selected_final = _.omit($scope.selected_tags.split(','),_.isEmpty);

};

这里是使用此方法更新的您代码的版本。

您可以将事件绑定到实际建议标签元素的单击上,以获得更好的效果。


嘿@Nick,为了使这个指令DRY和自包含,有没有办法在auto-complete指令中设置ngmodel.$setViewValue(element.val())以响应element.val()的更改?这意味着我将不得不监视$element.val(),但是Angular目前不允许 - 你知道有什么解决方法吗? - haki

0

我不建议更新插件本身,你可以改变你的指令,比如这样...

app.directive("autoComplete", function() { 
    return {
        restrict : "A" , 
        require  : '^ngModel', 
        scope    : 
        {
            ngModel: '=',
            AutoCompleteOptions : "&autoCompleteOptions"
        },
        link     : function (scope, element, 
                // prevent html5/browser auto 
                attrs.$set('autocomplete','off');
                var options = scope.
                options.onSelect = function(elem) {
                     scope.$apply(function() {
                         scope.ngModel = elem.value;
                     });
                };
            scope.autocomplete = $(element).autocomplete(scope.AutoCompleteOptions());
        }
    }
});

正如您在指令的作用域对象初始化中所注意到的,我选择了ngModel属性作为AutoComplete Jquery插件的onSelect事件要使用的内容,我使用scope.$apply()方法更新了模型。在指令中使用scope.$apply,以便调用scope.$digest()并直接影响模型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接