Edit in JSFiddle

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

myApp.controller('MyCtrl', function ($scope, $timeout) {

    document.getElementById('btn').onclick = function (e) {
        $timeout(function () {
            $scope.name = "Button clicked";
        });
    }
});


//Recommendations:
/*
Try to avoid to use this:
    if(!$scope.$$phase) {
   //$digest or $apply
}
$$phase is indeed private to the framework and there are good reasons for that

$timeout(callback) will wait until the current digest cycle (if any) is done, then execute your code, then run at the end a full $apply.

$timeout(callback, delay, false)will do the same (with an optional delay before executing your code), but won’t fire an $apply which saves performances if you didn’t modify your model.

$apply invokes, among other things, $root.$digest, which means it will redigest the root scope and all of its children, even if you’re within an isolated scope.

$digest will simply sync its scope model to view, but won’t tell its parents scope, which can save a lot of performances when working on an isolated part of your HTML with an isolated scope (from a directive).

$evalAsync has been introduced with angularjs 1.2, that will probably solve most of your troubles.

if you get the “$digest already in progress” error, then your architecture is wrong: either you don’t need to re-digest your scope, or you should not be in charge of that.


*/
<div ng-controller="MyCtrl">
    <button id="btn" type="button">Click me</button>
    <div>{{name}}</div>
</div>
<br/>


              

External resources loaded into this fiddle: