In basic words $timeout refers to angularjs when setTimeout - to JavaScript.
If you still think to use setTimeout therefore you need invoke $scope.$apply() after
As a side note
I suggest you to read How do I “think in AngularJS” if I have a jQuery background? post
and AngularJS: use $timeout, not setTimeout
Example 1: $timeout
   $scope.timeInMs = 0;
  
    var countUp = function() {
        $scope.timeInMs+= 500;
        $timeout(countUp, 500);
    }    
    $timeout(countUp, 500); 
Example 2: setTimeout (same logic)
 $scope.timeInMs_old = 0;
  
    var countUp_old = function() {
        $scope.timeInMs_old+= 500;        
        setTimeout(function () {
        $scope.$apply(countUp_old);
    }, 500);
    }
        
    setTimeout(function () {
        $scope.$apply(countUp_old);
    }, 500);
Demo Fiddle
$timeout also returns a promise
JS
function promiseCtrl($scope, $timeout) { 
 $scope.result = $timeout(function({ 
 return "Ready!"; 
 }, 1000); 
}
HTML
<div ng-controller="promiseCtrl"> 
 {{result || "Preparing…"}}
</div> 
$timeout also trigger digest cycle
Consider we have some 3d party code (not AngularJS) like Cloudinary plugin that uploads some file and returns us 'progress' percentage rate callback.
     // .....
     .on("cloudinaryprogress",
           function (e, data) {
               var name = data.files[0].name;
               var file_ = $scope.file || {};
               file_.progress = Math.round((data.loaded * 100.0) / data.total);
                               
                                
                $timeout(function(){
                     $scope.file = file_;
                }, 0);         
            })
We want to update our UI aka  $scope.file = file_;
So empty $timeout does the job for us, it will trigger digest cycle and $scope.file updated by 3d party will be re-rendered in GUI