使用jQuery设置输入值后更新Angular模型


160

我有一个简单的场景:

输入元素,其值由jQuery的val()方法更改。

我试图用jQuery设置的值更新角度模型。我试图编写一个简单的指令,但是它没有执行我想要的操作。

这是指令:

var myApp = angular.module('myApp', []);
myApp.directive('testChange', function() {
    return function(scope, element, attrs) {        
        element.bind('change', function() {
            console.log('value changed');
        })
    }
})

这是jQuery部分:

$(function(){
    $('button').click(function(){
        $('input').val('xxx');
    })
})

和html:

<div ng-app="myApp">
    <div ng-controller="MyCtrl">
        <input test-change ng-model="foo" />
        <span>{{foo}}</span>
    </div>
</div>

<button>clickme</button>

这是我尝试的小提琴:http :
//jsfiddle.net/U3pVM/743/

有人能指出我正确的方向吗?


2
在指令之外混合使用AngularJS和jQuery通常不是一个好主意。jQuery是否对您要执行的操作具有强制性?
Blackhole 2013年

为什么不将带有角度的click事件设置为控制器中的函数以更改模型的值?
吉米·凯恩

@Blackhole,我正在使用jquery上载插件来完成其工作,并将上载文件的路径放入隐藏的输入中。我所需要的只是可以访问角度模型中的该路径。因此,我想将其设置为隐藏输入的值,并在更改后更新角度模型。
Michal J.

我在您的小提琴中看不到Jquery调用...您可以检查并指出使用JQ更改值的位置吗?
Valentyn Shybanov 2013年

您的小提琴链接到一个Todo示例应用程序,该应用程序与此问题无关。
Stewie 2013年

Answers:


322

ngModel侦听“ input”事件,因此要“修复”您的代码,需要在设置值后触发该事件:

$('button').click(function(){
    var input = $('input');
    input.val('xxx');
    input.trigger('input'); // Use for Chrome/Firefox/Edge
    input.trigger('change'); // Use for Chrome/Firefox/Edge + IE11
});

有关此特定行为的解释,请查看我前一段时间给出的答案:“ AngularJS如何在内部捕获诸如'onclick','onchange'之类的事件?


不幸的是,这不是您遇到的唯一问题。正如其他评论所指出的那样,以jQuery为中心的方法是完全错误的。有关更多信息,请查看这篇文章:如果我有jQuery背景,如何“思考AngularJS”?)。


5
凉!除了一个例外:为什么它不适用于隐藏的输入?当我将输入类型切换为文本时,它可以正常工作。
Karol 2013年

8
这解决了使用jquery日历插件时的主要问题。通过在input.val()之后入侵插件触发('input')触发ng-change事件,直到用户选择了日历日期。谢谢!
Drone Brain

3
在隐藏的输入上工作完美:element.triggerHandler(“ change”);
falko 2013年

2
这对我不起作用。$(“#Distance”)。val(data); $(“#Distance”)。trigger('input');
Stas Svishov

10
使用Angular 1.4.3,input事件不适用于包括IE11在内的IE。 input事件仅在$sniff.hasEvent('input')为true 时才有效,$sniff.hasEvent('input')即使在IE11上为false! 我们可以改用change事件
香川修平

61

希望这对某人有用。

我无法使该jQuery('#myInputElement').trigger('input')事件被我的有角度的应用程序接走。

但是,我能够angular.element(jQuery('#myInputElement')).triggerHandler('input')被接住。


2
请解释解决方案,不要只写代码。我得到的角不是$不是函数
Thakhani Tharage 2015年

1
$在这里代表jQuery。它被标记在问题中。
曼2015年

当$('myInputElement')。trigger('input')不稳定时,这也对我有用。有时似乎随机工作,但其他人却没有,我永远无法建立模式。该解决方案每次都有效。
BryanP

2
Mine使用#前缀:angular.element($('#myInputElement')).triggerHandler('input')
Ebru Yener 2015年

这个triggerHandler也为我工作,我正在处理textarea,而不是输入。谢谢
Mounir

25

inputjQuery 触发事件的可接受答案对我不起作用。创建事件并使用本机JavaScript进行调度可以解决问题。

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

这也是我的解决方案。使用Angular 1.1.5,jQuery 2.2.4和Jasmine 2.5.3。非常,很奇怪,没有其他触发机制起作用。
拉尔斯·埃里克

我一直在寻找在脚本中设置输入时触发表单验证的本机JS方法,这对我有用,谢谢。
驱散

即使在Angular 5上也可以使用,太好了!
伊戈尔(Igor),

谢谢。在webview.evaluatejavascript中特别有用
Berry Wing

22

我认为这里不需要jQuery。

您可以使用$ watchng-click代替

<div ng-app="myApp">
  <div ng-controller="MyCtrl">
    <input test-change ng-model="foo" />
    <span>{{foo}}</span>

    <button ng-click=" foo= 'xxx' ">click me</button>
    <!-- this changes foo value, you can also call a function from your controller -->
  </div>
</div>

在您的控制器中:

$scope.$watch('foo', function(newValue, oldValue) {
  console.log(newValue);
  console.log(oldValue);
});

1
谢谢Utopik,您是对的,当有一种方法可以使用angular进行工作时,我不应该将jquery与angular混合使用。
Michal J.

17

您必须使用以下代码来更新特定输入模型的范围,如下所示

$('button').on('click', function(){
    var newVal = $(this).data('val');
    $('select').val(newVal).change();

    var scope = angular.element($("select")).scope();
    scope.$apply(function(){
        scope.selectValue = newVal;
    });
});

1
var scope = angular.element($("select")).scope(); scope.$apply(function(){ scope.selectValue = newVal; }); 那部分对我帮助很大。我的问题是在成功函数中的jquery ajax调用后更新角度模型。$ http的速度很慢,因为存在重复的事件更改监听器,该元素正在执行其他操作,因此我将其合并到jQuery中。
Emmanuel Mahuni

1
使用element.scope()是个坏主意,因为它仅在启用日志记录的情况下起作用。如果您在生产现场,你应该在你的配置与禁用日志$compileProvider.debugInfoEnabled(false);$logProvider.debugEnabled(false);code.angularjs.org/1.4.0/docs/guide/production获取更多信息。
RWAM '16

我尝试了此方法的隐藏变量,它的工作。var li_cuboid_id = $('#li_cuboid_id'); li_cuboid_id.val(json.cuboidId).change(); var scope = angular.element($(“#li_cuboid_id”))。scope(); scope。$ apply(function(){scope.cuboidId = json.cuboidId;}); 隐藏的变量定义为:<input id =“ li_cuboid_id” type = hidden ng-model =“ cuboidId”>
Rahul Varadkar,

7

通过在操作按钮上添加侦听器,我仅对控制器初始化进行了修改:

$(document).on('click', '#action-button', function () {
        $timeout(function () {
             angular.element($('#input')).triggerHandler('input');
        });
});

在我的情况下,其他解决方案无效。


4

我知道在这里回答有点晚了,但也许我可以节省一些时间。

我一直在处理同样的问题。一旦您更新了jQuery的输入值,就不会填充模型。我尝试使用触发事件,但没有结果。

这是我所做的,可以节省您的时间。

在HTML的脚本标签中声明一个变量。

喜欢:

<script>
 var inputValue="";

// update that variable using your jQuery function with appropriate value, you want...

</script>

一旦您通过使用以下角度服务完成了这一点。

$窗口

现在,从同一控制器作用域调用的getData函数下面将为您提供所需的值。

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

app.controller('imageManagerCtrl',['$scope','$window',function($scope,$window) {

$scope.getData = function () {
    console.log("Window value " + $window.inputValue);
}}]);

3

我已经为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);

例:


抱歉,对此进行了深入研究,但是由于这些复选框使用.prop而不是.val,因此知道如何将其与复选框或选择一起使用吗?至少对于输入.val更改而言,这是完美的工作,谢谢!
奥斯丁

@奥斯汀,我恐怕不知道。这是一个已有5年历史的问题,涉及两种被普遍认为过时的技术,因此我没有将这些知识牢记在心。祝您获得所需的解决方案好运。
dav_i

2

如果使用的是IE,则必须使用:input.trigger(“ change”);


2

.change()设置值后添加。

例:('id').val.('value').change();

也不要忘记在html中添加onchangeng-change标记


0

我这样做是为了能够使用Vanilla / jQuery从外部更新ngModel的值:

function getScope(fieldElement) {
    var $scope = angular.element(fieldElement).scope();
    var nameScope;
    var name = fieldElement.getAttribute('name');
    if($scope) {
        if($scope.form) {
            nameScope = $scope.form[name];
        } else if($scope[name]) {
            nameScope = $scope[name];
        }
    }
    return nameScope;
}

function setScopeValue(fieldElement, newValue) {
    var $scope = getScope(fieldElement);
    if($scope) {
        $scope.$setViewValue(newValue);
        $scope.$validate();
        $scope.$render();
    }
}

setScopeValue(document.getElementById("fieldId"), "new value");
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.