AngularJS:当用jQuery更改时,ng-model绑定不会更新


98

这是我的HTML:

<input id="selectedDueDate" type="text" ng-model="selectedDate" />

当我在框中输入内容时,该模型会通过2向绑定机制进行更新。甜。

但是,当我通过JQuery执行此操作时...

$('#selectedDueDate').val(dateText);

它不会更新模型。为什么?


1
为什么要从第二个开始呢?您正在使用一个框架,然后决定绕过它并通过DOM操作来设置值。可以给初学者一些忠告的最佳建议:忘记jquery的存在。在90%的情况下,角度就足够了,剩下的10%可以通过指令链接内的jqlite实现(元素实际上是一个jqlite包装的元素,随时可以对其进行操作)。
无效

1
一个非常重要的问题
Syed Kamruzzaman博士

有很多很好的理由说明为什么您想通过dom操作来更改角度模型,也许您是一位使用A / B测试工具的开发人员,并且想在幕后填写表格,或者您正在使用油腻的猴子脚本自动填写表格。
Shadaez

Answers:


134

Angular不知道这种变化。为此,您应该在以下位置致电$scope.$digest()或进行更改$scope.$apply()

$scope.$apply(function() { 
   // every changes goes here
   $('#selectedDueDate').val(dateText); 
});

看到这个以更好地了解脏检查

更新是一个例子


我像您说的那样做了: fiddle.jshell.net/AladdinMhaimeed/agvTz/8,但它不起作用
Aladdin Mhemed 2012年

1
请参阅此fiddle.jshell.net/agvTz/38您应该调用function$ scope。$ apply传递一个函数作为参数。在$ scope上进行更改时,应该调用$ apply,因此,在onSelect内。嗯,我希望您仅以示例为例,将DOM操作放入控制器内,这在实际应用中是错误的;)
Renan Tomal Fernandes 2012年

那我该怎么做才能进行良好的角度练习呢?单独的DOM操作变成指令?
阿拉丁(3

2
是的,这里的例子fiddle.jshell.net/agvTz/39指令可以用很多次你想用一个简单的datepicker="scopeKeyThatYouWant"输入
雷南TOMAL费尔南德斯

只需调用.. $ scope。$ digest()即可解决。会慢下来吗?
Thant Zin

29

只需使用;

$('#selectedDueDate').val(dateText).trigger('input');

trigger('input')onSelect事件处理程序中使用了日期选择器。它会正确更新值。
iman

这帮了我大忙。我正在从指令测试更新绑定输入的值,并包装.val('something'调用在$apply(或$digest随后调用)中不起作用。
汤姆·塞尔登

2
经过数小时的搜索,这才是可行的!谢谢!

Alhamdulillah,完美,它为我工作。感谢救我小时
赛义德马里兰州Kamruzzaman。

真正。我在用$('#selectedDueDate').val(dateText).trigger('change');对我不起作用的东西。.trigger('input');像魔术一样工作
jafarbtech

17

我发现,如果不将变量直接放在范围内,它将更可靠地进行更新。

尝试使用一些“ dateObj.selectedDate”,然后在控制器中将selectedDate添加到dateObj对象,如下所示:

$scope.dateObj = {selectedDate: new Date()}

这对我有用。


4
这也为我工作。我浪费了两个多小时,试图弄清为什么双向装订不起作用。它在页面上工作正常,但未更新控制器中的范围。然后,我绝望地尝试了您的方法(因为对我来说这应该是对的,这是没有道理的),而且该死的,它行得通!谢谢!
TMc 2014年

3
同样在这里-任何angularJs大师都可以解释为什么这样做有效吗?就像视图具有其自己的嵌套范围一样,有时您只能更新视图范围,而不能更新控制器范围
Tom Carver 2014年

1
对我来说效果很好!我想知道为什么它在裸露范围内无法正常工作。
斯蒂芬

1
它与angular无关,而与javascript的工作原理有很大关系。当您将范围变量分配给对象时,您是按引用分配它,而不是像将var设置为等于原始值时所做的按值分配一样。我在这里的帖子中谈到了这一点。stackoverflow.com/questions/14527377/…。我引用了我在该帖子中制作的这个小插图,以说明plnkr.co/edit/WkCT6aYao3qCmzJ8t5xg?p=preview
尼克·布雷迪

4

试试这个

var selectedDueDateField = document.getElementById("selectedDueDate");
var element = angular.element(selectedDueDateField);
element.val('new value here');
element.triggerHandler('input');

当您无法访问Angular的控制器$ scope时,它可以使用。例如,当您使用Tampermonkey编写脚本时。
wassertim


2

无论在Angular范围之外发生什么,Angular都不会知道。

摘要循环将更改从模型->控制器,然后从控制器->模型更改。

如果需要查看最新型号,则需要触发摘要周期

但是有可能正在进行一个摘要循环,因此我们需要检查并初始化该循环。

最好始终执行安全的申请。

       $scope.safeApply = function(fn) {
            if (this.$root) {
                var phase = this.$root.$$phase;
                if (phase == '$apply' || phase == '$digest') {
                    if (fn && (typeof (fn) === 'function')) {
                        fn();
                    }
                } else {
                    this.$apply(fn);
                }
            }
        };


      $scope.safeApply(function(){
          // your function here.
      });

1

AngularJS通过值传递字符串,数字和布尔值,而通过引用传递数组和对象。因此,您可以创建一个空对象,并使日期成为该对象的属性。以这种方式,角度将检测模型的变化。

在控制器中

app.module('yourModule').controller('yourController',function($scope){
$scope.vm={selectedDate:''}
});

在html中

<div ng-controller="yourController">
<input id="selectedDueDate" type="text" ng-model="vm.selectedDate" />
</div>

1

您必须触发输入元素的change事件,因为ng-model会监听输入事件,并且范围将被更新。但是,常规jQuery触发器对我不起作用。但这就像魅力一样

$("#myInput")[0].dispatchEvent(new Event("input", { bubbles: true })); //Works

追踪无效

$("#myInput").trigger("change"); // Did't work for me

您可以阅读有关创建和调度综合事件的更多信息。


0

我已经为jQuery写了这个小插件,它将进行所有调用以.val(value)更新angular元素(如果存在):

(function($, ng) {
  'use strict';

  var $val = $.fn.val; // save original jQuery function

  // override jQuery function
  $.fn.val = function (value) {
    // if getter, just return original
    if (!arguments.length) {
      return $val.call(this);
    }

    // get result of original function
    var result = $val.call(this, value);

    // trigger angular input (this[0] is the DOM object)
    ng.element(this[0]).triggerHandler('input');

    // return the original result
    return result; 
  }
})(window.jQuery, window.angular);

只需在jQuery和angular.js之后弹出该脚本,val(value)更新现在就可以正常播放了。


缩小版:

!function(n,t){"use strict";var r=n.fn.val;n.fn.val=function(n){if(!arguments.length)return r.call(this);var e=r.call(this,n);return t.element(this[0]).triggerHandler("input"),e}}(window.jQuery,window.angular);

例:


这个答案从我的答案逐字复制到另一个类似的问题


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.