0

I m trying to chain a promise to my 'timeout/typewriter effect' function, so once he function is finished another function should be called which is a simple $state.go. Ive been researching and looking at so many posts but whatever I try doesnt work-the first function is never being executed /or probably being executed but so fast that you cant see anything-instead just the second (the $state.go) function is being executed right away. Any ideas would be very much appreciated. Thank you!

app.controller('homeCtrl', function($scope, $state, $q, $interval, $timeout) {
     function beginn() {
        var content = "helloo"
        $scope.typewriter = "";
        var i = 0;
        var timer = $interval(function() {
            if (i < content.length)
                $scope.typewriter += content[i];
            else {
                $interval.cancel(timer);
            }
            i++;

        }, 300)
    }

    function change() {
        $state.go('profile')
    }

    $q.when(beginn()).then(change);

});

html:

<p>{{typewriter}}</p>
web2016
  • 47
  • 9

3 Answers3

1

But why do you need to chain the two promises? All you need to do is just do a $state.go when the characters are done pushing.

.controller('demoCtrl', ['$scope', '$state', '$interval', function($scope, $state, $interval) {
  var content = "helloo"
  $scope.typewriter = "";
  var i = 0;
  var timer = $interval(function() {
    if (i < content.length) {
      $scope.typewriter += content[i];
    } else {
      $state.go('home') // just go to the state directly
    }
    i++;
  }, 300)
}])

Working plnkr here

Edit

If you wanna do it your (functional) way, you will need to create a deferred promise, and then either resolve/reject it when you are done with pushing the letters.

  function begin() {
    var deferred=  $q.defer();//create a deferred object using $q

    var content = "helloo";
    $scope.typewriter = "";
    var i = 0;
    var timer = $interval(function() {
      if (i < content.length) {
        $scope.typewriter += content[i];
      } else {
        deferred.resolve(); //resolve this when done
      }
      i++;
    }, 300);
    return deferred.promise; // return the promise of the deferred object
  }

  begin().then(()=>$state.go('home')) // call it as usual, but using .then

Working plnkr here

CozyAzure
  • 8,280
  • 7
  • 34
  • 52
  • Thank you- that def. makes sense :) Can you still tell me what was wrong with my promise- not for this case anymore, but I just wanna know where the mistake was. Thank you! – web2016 Jan 17 '17 at 18:30
  • @web2016 You need to return a promise in your `begin` function, and you need to resolve it when it's done pushing the letters. I have added an edit and also a working plnkr. – CozyAzure Jan 18 '17 at 01:51
0

It is very simple why your code does not work, the beginn function when it is called in when returns undefined immediately when it is called (before $interval callback gets a chance to be executed. Since you are providing a sync value to $q.when (the undefined returned by beginn()) the promise will be immediately resolved and hence the change function in then block will be immediately called before the callback you provided to $interval.

If you still think you want to use the promise api this is how you should write your code:

app.controller('homeCtrl', function($scope, $state, $q, $interval, $timeout) {
 function beginn() {
    var content = "helloo"
    $scope.typewriter = "";
    var i = 0;
    return $q(function(resolve, reject) {

        var timer = $interval(function() {
            if (i < content.length)
                $scope.typewriter += content[i];
            else {
                $interval.cancel(timer);
                resolve();
            }
            i++;

        }, 300);          
    });
}

function change() {
    $state.go('profile')
}

beginn().then(change);

});

Look how beginn() now returns a promise immediately but only RESOLVEs it when the job is done and we want to cancel the timer. Also notice that you no longer need to use $q.when.

Ali Motevallian
  • 1,250
  • 10
  • 15
-1

I think you're not seeing anything because the scope loose track of your variable inside the interval, you need to let the scope know that you have made a change using $scope.$apply.

so your code should look like this.

       var timer = $interval(function() {
            if (i < content.length){
                $scope.typewriter += content[i];
                $scope.$apply();
            else {
                $interval.cancel(timer);
            }
            i++;

        }, 300)
  • it doesnt work..I added the $scope.$apply and also tried to take out the $scope.typewriter="" out of the function but that didnt help either.. – web2016 Jan 17 '17 at 01:24
  • no, you don't need the `$scope.$apply`. The typewriter is already a $scope variable, and $interval is an angular native service. – CozyAzure Jan 17 '17 at 02:22