I try to implement a progress bar and a timer using TimelineLite:
HTML:
<div id="progress"></div>
{{timeline.time()}}
CSS:
#progress {
width: 100%;
height: 30px;
background-color: red;
}
Here's what I want:
When the page loads, the progress bar starts animating from 100% to 0% width (10 sec. duration). Also, I want to show the result of the time
function.
Here's what I did:
public timeline = new TimelineLite();
ngOnInit() {
this.start();
}
start() {
const progress = document.getElementById('progress');
this.timeline.fromTo(progress, 10, {width: '100%'}, {width: 0, ease: Linear.easeNone});
}
So when the page loads, the progress bar works but the timer doesn't. I don't know why. If I try to set a timeout for 3 seconds at ngOnInit
, it works:
ngOnInit() {
setTimeout(() => this.start(), 3000);
}
Also if I create a button than invokes start
function at click, it works:
<button (click)="start()">Start</button>
So the problem is that the timer doesn't work if I try to invoke fromTo
function from ngOnInit
.
Hi you should use @ViewChild
to target your elements and use AfterViewInit
lifeCycleHook when you want to manipulate | access to your DOMElement (current component or child component).
export class AppComponent implements AfterViewInit {
@ViewChild('progress') progressElement: ElementRef;
constructor(private changeRef: ChangeDetectorRef) { }
public timeline = new TimelineLite();
ngAfterViewInit() {
this.start();
}
start() {
this.timeline.eventCallback('onUpdate', () => {
this.time = this.timeline.time();
this.changeRef.detectChanges();
}, [] );
// Here i use the ViewChild Binding instead of pure javascript fetching.
this.timeline.fromTo(this.progressElement.nativeElement, 10, {width: '100%'}, {width: 0, ease: Linear.easeNone});
}
}
To facilitate your testing i have does Github Pull request. Anyone which read your original question can easily see the difference.
Update 1 : on your view, you call a function which return the current timer from TimelineLite. Because is just function call, it will not be called again and again on each internal TimelineLite update.
To do it, you have to use TimelineLite event binding.
Now, by default your view will not be "updated" each time you update your attribute from following code :
this.timeline.eventCallback('onUpdate', () => {
// angular is not inform by default than something happen here.
}, [] );
is why, you should use ChangeDetectorRef
to force angular to detect the freshest updated component attribute.
pull requested updated