Update Angular model after setting input value wit

2019-01-01 01:39发布

问题:

I have this simple scenario:

Input element which value is changed by jQuery\'s val() method.

I am trying to update the angular model with the value that jQuery set. I tried to write a simple directive, but it\'s not doing what I want.

Here\'s the directive:

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

this is the jQuery part:

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

and html:

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

<button>clickme</button>

Here is the fiddle with my try:
http://jsfiddle.net/U3pVM/743/

Can someone please point me in the right direction?

回答1:

ngModel listens for \"input\" event, so to \"fix\" your code you\'d need to trigger that event after setting the value:

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

For the explanation of this particular behaviour check out this answer that I gave a while ago: \"How does AngularJS internally catch events like \'onclick\', \'onchange\'?\"


But unfortunately, this is not the only problem you have. As pointed out with other post comments, your jQuery-centric approach is plain wrong. For more info take a look at this post: How do I “think in AngularJS” if I have a jQuery background?).



回答2:

Hope this is useful for someone.

I was unable to get the jQuery(\'#myInputElement\').trigger(\'input\') event to be picked up my angular app.

I was however, able to get angular.element(jQuery(\'#myInputElement\')).triggerHandler(\'input\') to be picked up.



回答3:

I don\'t think jQuery is required here.

You can use $watch and ng-click instead

<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>

In your controller :

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


回答4:

You have to use the following code in order to update the scope of the specific input model as follows

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


回答5:

The accepted answer which was triggering input event with jQuery didn\'t work for me. Creating an event and dispatching with native JavaScript did the trick.

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


回答6:

I made modifications on only controller initialization by adding listener on action button:

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

Other solutions did not work in my case.



回答7:

I know it\'s a bit late to answer here but maybe I may save some once\'s day.

I have been dealing with the same problem. A model will not populate once you update the value of input from jQuery. I tried using trigger events but no result.

Here is what I did that may save your day.

Declare a variable within your script tag in HTML.

Like:

<script>
 var inputValue=\"\";

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

</script>

Once you did that by using below service of angular.

$window

Now below getData function called from the same controller scope will give you the value you want.

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

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

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


回答8:

I\'ve written this little plugin for jQuery which will make all calls to .val(value) update the angular element if present:

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

Just pop this script in after jQuery and angular.js and val(value) updates should now play nice.


Minified version:

!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);

Example:

// 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>



回答9:

If you are using IE, you have to use: input.trigger(\"change\");



回答10:

add .change() after setting the value.

example:(\'id\').val.(\'value\').change();

also don\'t forget to add onchange or ng-change tag in html