After hours of frustrating searches I feel I need to submit my question here. I apologize in advance if this question is somehow answered before but none of my searches has helped so far. So here's my question:
My JavaScript code is creating an object, which is modified and monitored by AngularJS. On some events (like loading a previous setting of the object), I wish to change the properties of this object from outside the scope. The problem is that the inputs does not change...
Here's an example of how I wish to perform these changes:
HTML code:
<div ng-app="myApp" ng-controller="FirstCtrl">
<input type="number" ng-model="data.age">
<h1>{{data.age}}</h1>
<input type="button" value="Change to 20" ng-model="data" onclick="change()">
JavaScript Code:
var person = {
age: 16
};
// Create module
var myApp = angular.module('myApp', []);
myApp.factory('Data', function() {
return person;
});
function FirstCtrl($scope, Data) {
$scope.data = Data;
}
function change() {
person.age = 20;
}
When I now press the "Change to 20" button, nothing happens. How can I modify the person's age from the change
function?
Using Jeremy Banks' perfect answer, done in one line, though I'm referencing the controller vs the app:
Simply use a short $timeout
and you are done.
I tried all those $apply hacks from around the www before and they all didn't work. But this $timeout works always like a charme and in every case. All you need is a reference of your $scope and $timeout.
Wy and how it works:
It works basically like a queue. But be aware that it is async.
MaxPRafferty's answer is correct - using a function in the scope is often the nicer way to do this - but there is another option. You can use the
angular.element(...).scope()
method to access an Angular scope from unrelated JavaScript. Select the top-level scope for the app by targeting the element that has theng-app
attribute specified, with something like in your click handler:Try it out in this Fiddle.
Shaun just pointed out that Angular will only process any "watches" or "bindings" during a
$digest()
call. If you just modify the properties of the$scope
directly, the changes may not be reflected immediately and you may gets bugs.To trigger this you can call
$scope.$apply()
which will check for dirty scopes and update anything bound correctly. Passing a function that does the work inside$scope.$apply
will allow Angular to catch any exceptions as well. This behaviour is explained in the documentation for Scope.Jeremy's answer is really good, though now Angular has changed, and will no longer work, unless you add this line of code:
So, the changed function should look like this
http://jsfiddle.net/MaxPRafferty/GS6Qk/
You want set your ng-click attribute to a function in your scope, as follows:
With $render method is called by the ng-model directive when the value has been modified outside the directive. Get new value by reading the $viewValue property. Look: https://jsfiddle.net/cesar_ade/g5ybs6ne/