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

Posted

技术标签:

【中文标题】使用 jQuery 设置输入值后更新 Angular 模型【英文标题】:Update Angular model after setting input value with jQuery 【发布时间】:2013-06-11 04:24:03 【问题描述】:

我有一个简单的场景:

输入元素的值被 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/

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

【问题讨论】:

在指令之外混合 AngularJS 和 jQuery 通常是个坏主意。 jQuery 对于您想要做的事情是强制性的吗? 为什么不给控制器中的一个函数设置带角度的点击事件来改变模型的值呢? @Blackhole,我正在使用 jquery 上传插件来完成它的工作,并将上传文件的路径放入隐藏的输入中。我只需要在角度模型中访问该路径。所以我想我会将其设置为隐藏输入的值,并在更改后更新角度模型。 我没有在你的小提琴中看到 Jquery 调用...你能检查并指出你用 JQ 更改值的位置吗? 您的小提琴链接到 Todo 示例应用程序,该应用程序与此问题无关。 【参考方案1】:

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

$('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
);

有关此特定行为的解释,请查看我不久前给出的答案:“How does AngularJS internally catch events like 'onclick', 'onchange'?”


但不幸的是,这不是您遇到的唯一问题。正如其他帖子 cmets 所指出的,您以 jQuery 为中心的方法是完全错误的。有关更多信息,请查看此帖子:How do I “think in AngularJS” if I have a jQuery background?)。

【讨论】:

酷!除了一个例外:为什么它不适用于隐藏输入?当我将输入类型切换为文本时,它按预期工作。 这解决了使用 jquery 日历插件时的一个主要问题。通过破解插件在 input.val() 之后触发('input'),ng-change 事件会在用户选择日历日期后触发。谢谢! 在隐藏输入上完美运行:element.triggerHandler("change"); 这对我不起作用。 $("#Distance").val(数据); $("#Distance").trigger('input'); 对于 Angular 1.4.3,input 事件在包括 IE11 在内的 IE 上不起作用。 input event works only when $sniff.hasEvent('input') is true 但$sniff.hasEvent('input') is false even on IE11! 我们可以改用change event。【参考方案2】:

希望这对某人有用。

我无法获取 jQuery('#myInputElement').trigger('input') 事件以获取我的 Angular 应用程序。

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

【讨论】:

请解释解决方案不要只写代码。我得到 angular is not $ is not a function $ 在这里代表 jQuery。它在问题中被标记。 这对我也有用,而 $('myInputElement').trigger('input') 是不稳定的。它有时似乎随机工作,但其他人则不然,我永远无法建立一个模式。此解决方案每次都有效。 我的使用 # 前缀:angular.element($('#myInputElement')).triggerHandler('input') 这个 triggerHandler 也为我工作,我处理的是 textarea 而不是输入。谢谢【参考方案3】:

使用 jQuery 触发 input 事件的已接受答案对我不起作用。创建一个事件并使用本机 javascript 进行调度就可以了。

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

【讨论】:

这也是我的解决方案。使用 Angular 1.1.5、jQuery 2.2.4 和 Jasmine 2.5.3。非常非常奇怪,没有其他触发机制起作用。 我正在寻找在脚本中设置输入时触发表单验证的原生 JS 方法,这对我有用,谢谢。 即使在 Angular 5 上也能使用,很棒! 谢谢。在 webview.evaluatejavascript 中特别有用【参考方案4】:

我认为这里不需要 jQuery。

您可以改用$watch 和ng-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);
);

【讨论】:

谢谢 Utopik,你是对的,当有办法使用 angular 完成这项工作时,我不应该将 jquery 与 angular 混合使用。【参考方案5】:

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

$('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;
    );
);

【讨论】:

var scope = angular.element($("select")).scope(); scope.$apply(function() scope.selectValue = newVal; ); 那部分对我帮助很大。我的问题是在成功函数中调用 jquery ajax 后更新角度模型。 $http 很慢,因为有重复的更改事件侦听器用于执行其他操作的元素,所以我将它合并到 jQuery 中。 使用 element.scope() 是个坏主意,因为它只适用于启用日志记录。如果您在生产站点上,则应使用 $compileProvider.debugInfoEnabled(false);$logProvider.debugEnabled(false); 禁用登录配置,请参阅 code.angularjs.org/1.4.0/docs/guide/production 了解更多信息。 我为隐藏变量尝试了这种方法,它奏效了。 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; );隐藏变量定义为:【参考方案6】:

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

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

其他解决方案不适用于我的情况。

【讨论】:

【参考方案7】:

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

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

这就是我所做的可能会为您节省一天的时间。

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

喜欢:

<script>
 var inputValue="";

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

</script>

一旦你通过使用下面的 angular 服务来做到这一点。

$窗口

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

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

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

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

【讨论】:

【参考方案8】:

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

例子:

// the function
(function($, ng) 
  'use strict';
  
  var $val = $.fn.val;
  
  $.fn.val = function (value) 
    if (!arguments.length) 
      return $val.call(this);
    
    
    var result = $val.call(this, value);
    
    ng.element(this[0]).triggerHandler('input');
    
    return result;
    
  
)(window.jQuery, window.angular);

(function(ng) 
  ng.module('example', [])
    .controller('ExampleController', function($scope) 
      $scope.output = "output";
      
      $scope.change = function() 
        $scope.output = "" + $scope.input;
      
    );
)(window.angular);

(function($)  
  $(function() 
    var button = $('#button');
  
    if (button.length)
      console.log('hello, button');
    
    button.click(function() 
      var input = $('#input');
      
      var value = parseInt(input.val());
      value = isNaN(value) ? 0 : value;
      
      input.val(value + 1);
    );
  );
)(window.jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div ng-app="example" ng-controller="ExampleController">
  <input type="number" id="input" ng-model="input" ng-change="change()" />
  <span>output</span>
  <button id="button">+</button>
</div>

【讨论】:

很抱歉把这个挖出来,但是知道这将/可以如何与复选框或选择一起使用,因为那些使用.prop而不是.val?这至少对于输入 .val 更改非常有效,所以谢谢! @Austin 恐怕我不知道。这是一个关于两种被广泛认为过时的技术的 5 年老问题,因此我没有将这些知识留在脑海中。不过,祝您获得所需的解决方案好运。【参考方案9】:

如果你使用的是IE,你必须使用:input.trigger("change");

【讨论】:

【参考方案10】:

设置值后添加.change()

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

别忘了在html中添加onchangeng-change标签

【讨论】:

【参考方案11】:

我这样做是为了能够使用 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");

【讨论】:

【参考方案12】:

不是 OP 所要求的,而是任何可能编写一个 用户脚本 的灵魂,该用户脚本通过输入字段并填写所需的详细信息。没有(完全)对我有用,但最终设法以这种方式完成:

var el = $('#sp_formfield_fw_ip');
el.val("some value");
angular.element(el).triggerHandler('focus');
angular.element(el).triggerHandler('input');
angular.element(el).triggerHandler('change');
angular.element(el).triggerHandler('blur');

打开开发者工具,并检查 input 字段中添加的事件。在那里我找到了所有这些(就我而言):focusinputchangeblur

【讨论】:

以上是关于使用 jQuery 设置输入值后更新 Angular 模型的主要内容,如果未能解决你的问题,请参考以下文章

输入字段在设置值后扩展?

使用x-editable更新行中的值后jquery数据表未排序

更改值后反应组件未更新

Grafana:从面板插件配置 InfluxDB 查询。在从 typescript 设置值后使用 html 输入元素出现问题

当用js动态的改变一个输入框中的值后,并不能触发它的onchange事件why?

如何在 JQuery 的文本框中获取空值?