projects/common/lib/components/wizard-progress-bar/wizard-progress-bar.component.ts
NPM Dependencies: a) rxjs b) ngx-bootstrap
changeDetection | ChangeDetectionStrategy.OnPush |
selector | common-wizard-progress-bar |
styleUrls | ./wizard-progress-bar.component.scss |
templateUrl | ./wizard-progress-bar.component.html |
Properties |
|
Methods |
Inputs |
constructor(router: Router, cd: ChangeDetectorRef)
|
|||||||||
Parameters :
|
progressSteps | |
Type : WizardProgressItem[]
|
|
Default value : []
|
|
calculateProgressPercentage |
calculateProgressPercentage()
|
Returns :
number
|
getActiveIndex | ||||
getActiveIndex(url)
|
||||
Parameters :
Returns :
number
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
Private scrollStepIntoView |
scrollStepIntoView()
|
Primarily for mobile, this horizontally scrolls the step into view. Note - be very careful with any changes to this function because it steps outside of Angular to call native browser functions.
Returns :
void
|
Public activeIndex |
Type : number
|
Private routerEvents$ |
Type : Subscription
|
stepContainer |
Type : ElementRef
|
Decorators :
@ViewChild('stepContainer')
|
steps |
Type : QueryList<ElementRef<HTMLAnchorElement>>
|
Decorators :
@ViewChildren('steps')
|
Lorem ipsum dolor sit amet consectetur adipisicing elit. Sapiente, magnam ipsam. Sit quasi natus architecto rerum unde non provident! Quia nisi facere amet iste mollitia voluptatem non molestias esse optio?
Aperiam fugiat consectetur temporibus, iste repellat, quisquam sapiente nisi distinctio optio, autem nemo tenetur error eum voluptatibus ab accusamus quis voluptatum blanditiis. Quam et ut reprehenderit vitae nobis, at ipsum!
Exercitationem pariatur animi repudiandae corporis obcaecati ratione ducimus beatae quam, nostrum magnam unde numquam quidem cupiditate odit id. Beatae alias molestiae, optio incidunt harum quia voluptates deserunt sequi. Nesciunt, optio.
import { Component, OnInit, Input, ViewChild, ElementRef,
ViewChildren, QueryList, ChangeDetectionStrategy,
ChangeDetectorRef, OnDestroy } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { filter, map } from 'rxjs/operators';
import { Subscription } from 'rxjs';
import { WizardProgressItem } from '../../models/container';
/**
* NPM Dependencies:
* a) rxjs
* b) ngx-bootstrap
*/
@Component({
selector: 'common-wizard-progress-bar',
templateUrl: './wizard-progress-bar.component.html',
styleUrls: ['./wizard-progress-bar.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class WizardProgressBarComponent implements OnInit, OnDestroy {
@Input() progressSteps: WizardProgressItem[] = [];
@ViewChild('stepContainer') stepContainer: ElementRef;
@ViewChildren('steps') steps: QueryList<ElementRef<HTMLAnchorElement>>;
public activeIndex: number;
private routerEvents$: Subscription;
constructor(private router: Router, private cd: ChangeDetectorRef) {
}
ngOnInit() {
// Update the progress bar view on route change and _only_ route chaange.
// Skip most of Angular's ChangeDetection in favour of manually optimizing.
this.routerEvents$ = this.router.events.pipe(
filter(ev => ev instanceof NavigationEnd),
map((ev: NavigationEnd) => ev.url)
).subscribe(url => {
this.activeIndex = this.getActiveIndex(url);
this.cd.detectChanges();
this.scrollStepIntoView();
});
// Must schedule first run manually, or bar won't be set.
this.activeIndex = this.getActiveIndex(this.router.url);
}
ngOnDestroy() {
this.cd.detach();
this.routerEvents$.unsubscribe();
}
calculateProgressPercentage(): number {
const denominator = this.progressSteps.length;
const numerator = this.activeIndex + 1;
if (denominator === 0 || numerator > denominator) {
return 100;
}
// Because we've switched from space-evenly to space-around (for IE), we
// have to handle the half-space that space-around adds to the start/end of
// the container
const halfSpace = 1 / (denominator * 2);
return Math.round(((numerator / denominator) - halfSpace) * 100);
}
getActiveIndex(url): number {
return this.progressSteps.findIndex(x => url.endsWith(x.route));
}
/**
* Primarily for mobile, this horizontally scrolls the step into view.
*
* Note - be very careful with any changes to this function because it steps
* outside of Angular to call native browser functions.
*/
private scrollStepIntoView() {
const target = this.steps.toArray()[this.activeIndex];
const container = document.getElementsByClassName('horizontal-scroll');
if (container.length === 1) {
// Since we're already breaking out of Angular, we try and be safe by using a try/catch.
// Otherwise an error here could halt execution,
try {
container[0].scrollLeft = Math.abs(target.nativeElement.offsetLeft - (window.outerWidth / 2));
} catch (error) {}
}
}
}
<progressbar
[value]="calculateProgressPercentage()"
[max]="100"
[animate]="true">
</progressbar>
<div class="step-container" #stepContainer>
<a #steps *ngFor="let step of progressSteps; let i = index;" [routerLink]="step.route">
<div class="step" [ngClass]="{active: i === activeIndex}">
<span class="step-text">{{step.title}}</span>
</div>
</a>
</div>