How to pass vm to a setTimeout in AngularJs? Changes to scope don't update DOM view

坚强是说给别人听的谎言 提交于 2019-12-07 19:37:28

Try use the script bellow.

(function () {
    'use strict';

     angular
         .module("app")
         .controller("Banana", banana);

     function banana($timeout) {
        var vm = this;
        vm.showStuff = false;

        $timeout(function () {
            console.log("poof!");
            vm.showStuff = true;
        }, 1000);
     }
})();

To be noted - there's additional step required.

  1. Substitute setTimeout(...) for $timeout(...).
  2. Pass $timeout into banana(...).
  3. Provide banana.$inject = ["$timeout",...].

Use the $apply method with setTimeout:

//WORKS
setTimeout(function () {
    $scope.$apply("vm.showStuff = true");
}, 1000);

OR use the AngularJS $timeout service:

//RECOMMENDED
$timeout(function () {
    vm.showStuff = true;
}, 1000);

The window.setTimeout method creates an event outside the AngularJS framework and its digest cycle. The $timeout service wraps window.setTimeout and integrates it with the AngularJS framework and its digest cycle.

Angular modifies the normal JavaScript flow by providing its own event processing loop. This splits the JavaScript into classical and Angular execution context. Only operations which are applied in Angular execution context will benefit from Angular data-binding, exception handling, property watching, etc... You use $apply() to enter Angular execution context from JavaScript.

Keep in mind that in most places (controllers, services) $apply has already been called for you by the directive which is handling the event. An explicit call to $apply is needed only when implementing custom event callbacks, or when working with third-party library callbacks.

AngularJS Developer Guide - Integration with the browser event loop

Hey What Mateus Koppe is showing it's a good answer, I would like to extend, just because this can help someone that needs to apply changes to the view.

The $Timeout service on angular refreshes the data on the view, but with setTimeout you don't have the same effect, so you should use $scope and $apply() to force the refresh on the screen.

On my EXAMPLE I use them, to show you the effect.

    //Timeout angularjs
    $timeout(function () {
        console.log("poof! $timeout");
        vm.showStuff = true;
    }, 1000);

    //Tiemout regular
    setTimeout(function () {
      console.log("poof1! setTimeout");
      vm.showStuff1 = true;
    }, 1000);

    //Timeout + $scope.$apply
    setTimeout(function () {
      console.log("poof2! setTimeout");
      vm.showStuff2 = true;
      $scope.$apply();    //<<<<<<<<<<<<<<<<<<<<<<<<<<<
    }, 3000);

I hope it helps.

As its explained on $apply()

$apply() is used to execute an expression in angular from outside of the angular framework. (For example from browser DOM events, setTimeout, XHR or third party libraries). Because we are calling into the angular framework we need to perform proper scope life-cycle of exception handling, executing watches.

Also you should avoid using on $digest()

Usually, you don't call $digest() directly in controllers or in directives. Instead, you should call $apply() (typically from within a directive), which will force a $digest().

Please check my example here.
https://jsfiddle.net/moplin/x8mnwf5a/

maqduni

As explained in previous answers it has to do with the $digest cycle, native setTimeout() doesn't trigger the digest cycle and therefore the view doesn't get re-rendered with new value of vm.showStuff.

I'd slightly extend Pablo Palacious's answer with the following usage of $scope.$apply(),

//Timeout + $scope.$apply
setTimeout(function () {
  $scope.$apply(function () {
    console.log("poof2! setTimeout");
    vm.showStuff2 = true;
  });
}, 3000);

You could also consider using $scope.$applyAsync() which queues up expressions and functions for execution in the next digest cycle, as described here,

$applyAsync([exp]);

Schedule the invocation of $apply to occur at a later time. The actual time difference varies across browsers, but is typically around ~10 milliseconds.

This can be used to queue up multiple expressions which need to be evaluated in the same digest.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!