File

packages/ui/src/lib/loader/loader.component.ts

Description

The ec-loader can be plugged into various components to be triggered when they load stuff. https://components.entrecode.de/ui/loader?e=1

Metadata

changeDetection ChangeDetectionStrategy.OnPush
selector ec-loader
templateUrl ./loader.component.html

Index

Properties
Methods

Constructor

constructor(host: ElementRef)

Injects the host element.

Parameters :
Name Type Optional
host ElementRef No

Methods

Private hide
hide()

Hide the loader by removing .visible from the host. This method is NOT meant to be used from outside,

Returns : void
Private show
show()

Shows the loader by setting .visible to the host. This method is NOT meant to be used from outside,

Returns : void
wait
wait(promise: Promise)

Tells loader to show until the given promise resolves. (includes all other promises that are waited upon) Make sure the given promise is catched (so the loader will stop loading on error)!

Parameters :
Name Type Optional
promise Promise<any> No
Returns : any

Properties

Private stack
Type : Collection<Promise<any>>
Default value : new Collection([])

The current stack of loading promises.

Private timestamp

The timestamp of the last time a promise has been added to the stack.

Private visible
Default value : false

The loader's visibility status.

Loader

The loader can be used to indicate any kind of loading activity

Template

<ec-loader #globalLoader class="ec-loader loader is-global"></ec-loader>
<ec-loader #localLoader class="ec-loader loader is-local"></ec-loader>
<button (click)="globalLoader()">Global Loader</button>
<button (click)="localLoader()">Local Loader</button>

The default classes can be found here.

Usage

You can use a global loader that handles every action or use multiple local loaders:

import { LoaderComponent, LoaderService } from '@ec.components/ui';
export class MyApp {
  @ViewChild('globalLoader') globalLoader: LoaderComponent;
  @ViewChild('localLoader') localLoader: LoaderComponent;
  constructor(private loaderService: LoaderService) {
      this.loaderService.use(this.globalLoader); // set global loader
  }
  globalLoader() { // When not passing a loader to .wait, the global loader (set by .use) is used.
    this.loaderService.wait(new Promise((resolve) => setTimeout(resolve, 2000)));
  }
  localLoader() {
    this.loaderService.wait(new Promise((resolve) => setTimeout(resolve, 2000)), this.localLoader);
    // this.localLoader.wait(new Promise((resolve) => setTimeout(resolve, 2000))); // alternative way
  }
}

The advantage of local loaders is that you can place them in specific places of your template to only "disable" a part of your site while loading and not the whole page. See the commented out line in localLoader for a direct way to trigger a loader without the service.

How it works

Each time .wait is called on the LoaderService, the target loader throws the given promise on a stack. When all promises on the stack have been resolved, the loader is hidden. This is better than just a boolean switch because multiple loading activies do not interfere with each other.

import { Component, ElementRef, ChangeDetectionStrategy } from '@angular/core';
import { Collection } from '@ec.components/core';

/** The ec-loader can be plugged into various components to be triggered when they load stuff.
 * <example-url>https://components.entrecode.de/ui/loader?e=1</example-url>
 */
@Component({
  selector: 'ec-loader',
  templateUrl: './loader.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class LoaderComponent {
  /** The current stack of loading promises.*/
  private stack: Collection<Promise<any>> = new Collection([]);
  /** The loader's visibility status. */
  private visible = false;
  /** The timestamp of the last time a promise has been added to the stack. */
  private timestamp;

  /** Injects the host element. */
  constructor(private host: ElementRef) { }

  /** Shows the loader by setting .visible to the host. This method is NOT meant to be used from outside, */
  private show() {
    this.visible = true; // show loader
    this.host.nativeElement.classList.add('is-active');
  }

  /** Hide the loader by removing .visible from the host. This method is NOT meant to be used from outside, */
  private hide() {
    this.visible = false; // hide loader
    this.host.nativeElement.classList.remove('is-active');
  }

  /** Tells loader to show until the given promise resolves. (includes all other promises that are waited upon)
   * Make sure the given promise is catched (so the loader will stop loading on error)! */
  wait(promise: Promise<any>) {
    this.stack.add(promise); // add promise to stack
    this.show();
    const timestamp = Date.now();
    this.timestamp = timestamp; // get timestamp
    Promise.all(this.stack.items).catch(error => {
    }).then(() => {
      if (timestamp === this.timestamp) {
        this.hide();
        this.stack.removeAll();
      }
    });
    return promise;
  }
}
<ng-content></ng-content>
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""