0

I have a div in my view, I want to execute a function on ng-click() which turns the background for the div to 'color a' for 30 seconds if there's no action taken then for 60 seconds then change to 'color b' and if no action is taken beyond 120 seconds just hide the div.(this can be done via adding/removing classes as well )

In essence I'm looking to execute a sequence of $timeouts in angular where one timeout leads into another.

Any help on that would be hugely appreciated. Thanks.

2
  • 1
    what's holding you back?
    – adrichman
    Commented Apr 17, 2014 at 5:49
  • How I should approach it, should I create one $timeout of 120 seconds and nest the subsequent $timeouts in the root $timeout. I think I might have solved it myself. :P
    – SinSync
    Commented Apr 17, 2014 at 6:28

1 Answer 1

3

I would approach it by using a variable in the scope to hold the state, and chaining $timeouts to move between the states. So on the element that will be clicked:

<span ng-click="startChange()">Click me to start</span>

and in the controller:

$scope.state = 'a';
$scope.startChange = function() {
  $scope.state = 'b';
  return $timeout(angular.noop, 30 * 1000).then(function() {
    $scope.state = 'c';
    return $timeout(angular.noop, 60 * 1000);
  }).then(function() {
    $scope.state = 'd';
    return $timeout(angular.noop, 120 * 1000);
  }).then(function() {
    $scope.state = 'e'
  });
}

The angular.noop is just a function that does nothing. It's a slightly personal preference, but I find it a bit easier to see the flow of activity where the callback passed to $timeout does nothing, and all action on the scope are always in the then success callback of the promise.

In the template for the background div:

<div class="background-state-{{state}}">....</div>

and then in CSS set the colours:

.background-state-a {background-color: red}
.background-state-b {background-color: green}
.background-state-c {background-color: blue}
...

However, I'm not sure what else you have in the controller or your exact use-case. You might want to separate some logic out into a directive, as it might be mixing business logic with view logic.

9
  • That's a more structured approach with promises and definitely better than my approach. Thanks @Michal!
    – SinSync
    Commented Apr 17, 2014 at 7:29
  • Any idea why the {{ state }} won't output in the div? I can see that when I log the $scope the .state is set to 'a'; but on the template it's just <div "background-state-"></div>
    – SinSync
    Commented Apr 19, 2014 at 7:30
  • Yes: I made a mistake in my answer. I wrote $state instead of $scope.state. I've now edited it. Commented Apr 19, 2014 at 7:50
  • It actually works on {{ state }} as well but not when I want to output it in the class attr on the custom directive that I have and also it doesn't update it on the $timeout sequence. I can see it when I console.log that it's changing state, but it's not updating the value of state as it executes.
    – SinSync
    Commented Apr 19, 2014 at 8:00
  • 1
    There were a number of issues in the plunkr. Fixed at plnkr.co/edit/JjqIJSEHFrCL9bJfvtyK?p=preview . 1) Typo: you were using $scoe instead of $scope. 2) $timeout wasn't being injected into the controller. 3) You were using just $state in the controller, instead of $scope.state (as I was in my original answer) 4) The function element.on seems to cause issues sometimes. I've changed to element.bind Not sure why this is necessary, admittedly. Commented Apr 19, 2014 at 8:35

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.