I'm learning angular 4 and would like to implement a directive that causes the host element's background colors to cycle through the 7 listed in an array. Ideally I would want it to be continuous. I don't know which life-cycle hooks I need to hook into.
Here's what I have at the moment. Presently, it's not even visibly cycling through the 7 one time, with one-second intervals, as expected through the use of the SetTimeOut
. I've commented out the While
block as that just hangs the browser.
import {
Directive,
OnInit,
HostBinding,
Input
} from '@angular/core';
@Directive({
selector: '[rainbowize]'
})
export class RainbowizeDirective {
colors: Array<string>;
@HostBinding('style.backgroundColor') bgColor: string;
constructor() {
this.colors = ['violet', 'indigo', 'blue', 'green', 'yellow', 'orange', 'red'];
}
ngOnInit(){
let that = this;
//while (true) {
for (let i = 0; i < 7; i++) {
console.log(that.colors[i]);
setTimeout(function () {
that.bgColor = that.colors[i];
}, 1000)
}
//}
}
}
html:
<h2 rainbowize >This is a raibowized paragraph</h2>
Here is how you can do it:
ngOnInit() {
let that = this;
let counter = 0;
let length = this.colors.length;
upd();
function upd() {
that.bgColor = that.colors[counter % length];
counter++;
// some stopping condition here
if (counter < 20) {
setTimeout(upd, 1000);
}
}
}
The most important thing here is this line:
that.colors[counter % length];
I use modulo operator %
, which returns remainder after the integer division. So it will return:
0%7 = 0
1%7 = 1
2%7 = 2
...
6%7 = 6
7%7 = 0 <---- here the sequence starts from the beginning
8%7 = 1
This will run until the counter
variable reaches Number.MAX_SAFE_INTEGER
, which is 9007199254740991
.
Another simpler approach could be to just do the following:
that.bgColor = that.colors[counter % length];
counter++;
if (counter === length) {
counter = 0;
}
Or use a circular linked list.
But I'm still not clear as to where my error lies? Is it because I have my code in the ngOnInit's main body as opposed to having it a function there?
The problem with your code has nothing to do with Angular. It is that you're adding all callbacks to be executed within a second. And since they are all executed very fast, you only see the latest change to red. You could fix it like this:
for (let i = 0; i < 7; i++) {
console.log(that.colors[i]);
setTimeout(function () {
that.bgColor = that.colors[i];
}, 1000*i+1)
^^^^^^ --------------
}
But the problem now remains that your loop executes only once, so each callback is scheduled only once.