How to change AngularJS data outside the scope?

Solution 1:

⚠️ Warning: This answer is old, does not reflect best practices, and may not be compatible with newer versions of Angular.

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 the ng-app attribute specified, with something like in your click handler:

function change() {
    var appElement = document.querySelector('[ng-app=myApp]');
    var $scope = angular.element(appElement).scope();
    $scope.$apply(function() {
        $scope.data.age = 20;
    });
}

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.

Solution 2:

Jeremy's answer is really good, though now Angular has changed, and will no longer work, unless you add this line of code:

$scope = $scope.$$childHead;

So, the changed function should look like this

function change() {
    var appElement = document.querySelector('[ng-app=myApp]');
    var $scope = angular.element(appElement).scope();
    $scope = $scope.$$childHead; // add this and it will work
    $scope.$apply(function() {
        $scope.data.age = 20;
    });
}

Solution 3:

http://jsfiddle.net/MaxPRafferty/GS6Qk/

You want set your ng-click attribute to a function in your scope, as follows:

var person = {
    age: 16
};

// Create module
var myApp = angular.module('myApp', []);
myApp.factory('Data', function() {
    return person;
});

function FirstCtrl($scope, Data) {
    $scope.data = Data;
    $scope.update = function(){
        $scope.data.age = 20;
    }
}