Matoy Matoy - 4 months ago 24
AngularJS Question

can't use 2 js functions with sleep between them

I am trying to create an angular form where the user types text and while he does it the text lable below say "user is typing...".

Then it waits for 200 mili seconds and the text lable goes blank (the "user is typing" disappear).

I am doing it with angular ng-change directive.
my code is below.

the problem is that for some reason there is a problem with the help method I wrote for running 2 methods with sleep in between them.
for some reason the text "user is typing..." does not disappear after a short sleep.

why is that?

thanks

<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="myCtrl">
<p>Write something in the input field:</p>
<input type="text" ng-change="myFunc()" ng-model="myValue" />
<p>{{text}}</p>
</div>

<script>
angular.module('myApp', [])
.controller('myCtrl', ['$scope', function($scope) {
$scope.count = 0;
$scope.myFunc = function() {
runTwoFunctionWithSleepBetweenThem(function (){$scope.text='user is typing...';},function (){$scope.text='';},200);
};

var runTwoFunctionWithSleepBetweenThem=function(foo1,foo2, time) {
var sleep =function (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
foo1();
sleep(time).then(() => {
foo2();
});
}
}]);


</script>
</body>
</html>

Answer

As André Vale and Titus mentioned in the comments, you're outside your scope application cycle, so Angular doesn't know to do a "dirty check" after you've updated scope.

var runTwoFunctionWithSleepBetweenThem=function(foo1,foo2, time) {
  var sleep = function (time) {
    return new Promise((resolve) => setTimeout(resolve, time));
  }
  foo1();
  sleep(time).then(() => {
    foo2();
    $scope.$apply();
  });
}

Your sleep function approximates $timeout, which is Promise-based; you could easily switch to it, and also take advantage of the fact that it will invoke the function within an $apply block by default:

// Inject the $timeout service in your controller.
var runTwoFunctionWithSleepBetweenThem=function(foo1, foo2, time) {
  foo1();
  $timeout(foo2, time);
}

If you wanted to make this fully Promise-compatible, delaying foo1 if it returns a promise, and aborting if it rejects, then you could rephrase it like this:

// Inject $timeout and $q.
var runTwoFunctionWithSleepBetweenThem=function(foo1, foo2, time) {
  $q.when(foo1()).then(() => $timeout(foo2, time));
}
Comments