Join the Stack Overflow Community
Stack Overflow is a community of 6.3 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

This is my HTML:

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

When I type into the box, the model is updated via the 2-way-binding mechanism. Sweet.

However when I do this via JQuery...

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

It doesn't update the model. Why?

share|improve this question
    
Why would you do the second one to begin with ? You're using a framework and then deciding to bypass it and set the value through DOM manipulation. Best advice one can give with angular to beginners: forget jquery exists. in 90% of cases angular will be enough and the remaining 10% can be achieved through jqlite inside a directive's link (element is actually a jqlite wrapped element ready to be manipulated). – Void Jul 1 at 8:00
    
very important question – Syed Muhammad Kamruzzaman Sep 5 at 19:14
up vote 102 down vote accepted

Angular doesn't know about that change. For this you should call $scope.$digest() or make the change inside of $scope.$apply():

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

See this to better understand dirty-checking

UPDATE: Here is an example

share|improve this answer
    
I made this like you say: fiddle.jshell.net/AladdinMhaimeed/agvTz/8 but it does not work – Aladdin Mhemed Oct 16 '12 at 5:58
1  
See this fiddle.jshell.net/agvTz/38 You should call the function $scope.$apply passing a function as argument. And $apply should be call when you will make the changes on $scope, so, inside of onSelect. Ah, I expect that you put DOM manipulation inside of controller just for the example, in a real app this is wrong ;) – Renan Tomal Fernandes Oct 16 '12 at 15:05
    
then what should I do to make good angular practice? separate DOM manipulation into a directive? – Aladdin Mhemed Oct 17 '12 at 3:16
2  
Yes, here an example fiddle.jshell.net/agvTz/39 the directive can be used as many times you want with a simple datepicker="scopeKeyThatYouWant" in the input – Renan Tomal Fernandes Oct 17 '12 at 3:45
    
Just call.. $scope.$digest() to settle. will it slow down ? – Thant Zin Jun 4 '13 at 2:52

Just use;

$('#selectedDueDate').val(dateText).trigger('input');
share|improve this answer
    
Doesn't work for me unfortunately. – dav_i Mar 12 '15 at 17:23
    
I used trigger('input') with a datepicker in its onSelect event. It updates the value correctly. – iman Mar 17 '15 at 19:55
    
This did the trick for me. I was updating the value of a bound input from a directive test and wrapping the .val('something' call in an $apply (or calling $digest afterward) didn't work. – Tom Seldon Apr 29 '15 at 11:38
    
After hours of searching, this was the one that worked! Thank you! – Dan Oct 28 '15 at 18:24
    
Perfect....working for me ...thumbs up..thanks – Kandarp Apr 29 at 11:24

I have found that if you don't put the variable directly against the scope it updates more reliably.

Try using some "dateObj.selectedDate" and in the controller add the selectedDate to a dateObj object as so:

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

This worked for me.

share|improve this answer
4  
This worked for me as well. I'd wasted over 2 hours trying to figure out why two-way binding wasn't working. It worked fine on the page, but the scope in the controller was not being updated. Then I tried your approach out of desperation (because it made no sense to me that this should be true) and hot damn, it worked! Thanks! – TMc May 25 '14 at 1:47
3  
Same here - can any angularJs guru explain why this works? It's like the view has it's own nested scope and sometimes you get stuck updating just the view-scope, not the controller-scope – Tom Carver Sep 15 '14 at 16:13
1  
Works well for me! I wonder why in the heck it doesn't work the same on the bare scope. – Stephen Nov 19 '14 at 3:40
    
Actually worked, very weird indeed! Thanks! – Luke Turnbull Dec 15 '15 at 9:07
    
It has little to do with angular, and a lot to do with how javascript works. When you assign the scope variable to an object, you are assigning it by reference, as opposed to by value as done when a var is set equal to a primitive value. I talked about about it in my post here. stackoverflow.com/questions/14527377/…. I referenced this plunk I made in that post to illustrate plnkr.co/edit/WkCT6aYao3qCmzJ8t5xg?p=preview. – Nick Brady Mar 10 at 6:41

Try this

var selectedDueDateField = document.getElementById("selectedDueDate");
var element = angular.element(selectedDueDateField);
element.val('new value here');
element.triggerHandler('input');
share|improve this answer
    
It is usable when you don't have the access to the angular's controller $scope. When you write a script with a Tampermonkey, for example. – wassertim Oct 8 '15 at 9:13

AngularJS pass string, numbers and booleans by value while it passes arrays and objects by reference. So you can create an empty object and make your date a property of that object. In that way angular will detect model changes.

In controller

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

In html

<div ng-controller="yourController">
<input id="selectedDueDate" type="text" ng-model="vm.selectedDate" />
</div>
share|improve this answer

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>


This answer was copied verbatim from my answer to another similar question.

share|improve this answer

Angular doesn't know about that change using jquery.

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

<div ng-bind="selectedDate"></div>
share|improve this answer

Whatever happens outside the Scope of AngularJS, Angular will never knew it.

Digest cycle put the changes from model -> controller and then from controller -> model.

So you need to trigger the digest cycle so as update the stuff. But there is a chance that there might be a digest cycle which is already running and would throw an error.

So, always do a safe apply.

       $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.
      });
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.