File

projects/common/lib/components/wizard-progress-bar/wizard-progress-bar.component.ts

Description

NPM Dependencies: a) rxjs b) ngx-bootstrap

Implements

OnInit OnDestroy

Metadata

changeDetection ChangeDetectionStrategy.OnPush
selector common-wizard-progress-bar
styleUrls ./wizard-progress-bar.component.scss
templateUrl ./wizard-progress-bar.component.html

Index

Properties
Methods
Inputs

Constructor

constructor(router: Router, cd: ChangeDetectorRef)
Parameters :
Name Type Optional
router Router No
cd ChangeDetectorRef No

Inputs

progressSteps
Type : WizardProgressItem[]
Default value : []

Methods

calculateProgressPercentage
calculateProgressPercentage()
Returns : number
getActiveIndex
getActiveIndex(url)
Parameters :
Name Optional
url No
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

Properties

Public activeIndex
Type : number
Private routerEvents$
Type : Subscription
stepContainer
Type : ElementRef
Decorators :
@ViewChild('stepContainer')
steps
Type : QueryList<ElementRef<HTMLAnchorElement>>
Decorators :
@ViewChildren('steps')

Design Guidelines

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>
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""