File

src/lib/data-source-error/data-source-error.component.ts

Implements

OnChanges OnInit OnDestroy

Metadata

Index

Properties
Methods
Inputs
Accessors

Constructor

constructor(environment: Environment)
Parameters :
Name Type Optional
environment Environment No

Inputs

dataSourceLike
Type : DataSourceLikeForErrorHandling
error
Type : | null | Observable<>
loading
Type : Observable<boolean> | boolean
refresh
Type : function
reset
Type : function
retry
Type : function

Methods

triggerReset
triggerReset()
Returns : void
triggerRetry
triggerRetry()
Returns : void

Properties

Public errorMessage
Default value : signal('Unknown Error')
Public isNotRelease
Default value : false
Public resetInProgress
Default value : signal(false)
Public retryInProgress
Default value : signal(false)

Accessors

dataSourceLike
setdataSourceLike(value: DataSourceLikeForErrorHandling)
Parameters :
Name Type Optional
value DataSourceLikeForErrorHandling No
Returns : void
import {
  JsonPipe,
  NgIf,
} from '@angular/common';
import {
  ChangeDetectionStrategy,
  Component,
  Inject,
  Input,
  OnChanges,
  OnDestroy,
  OnInit,
  signal,
  SimpleChanges,
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import {
  Environment,
  IsNotReleaseVersion,
  RXAP_ENVIRONMENT,
} from '@rxap/environment';
import {
  Observable,
  Subscription,
} from 'rxjs';

export interface DataSourceLikeForErrorHandling {
  refresh?: () => void;
  retry?: () => void;
  reset?: () => void;
  loading?: Observable<boolean> | boolean;
  loading$?: Observable<boolean>;
  error$?: Observable<unknown>;
  error?: Observable<unknown> | unknown | null;
}

@Component({
    selector: 'rxap-data-source-error',
    templateUrl: './data-source-error.component.html',
    styleUrls: ['./data-source-error.component.scss'],
    changeDetection: ChangeDetectionStrategy.OnPush,
    imports: [
        MatButtonModule,
        NgIf,
        MatProgressSpinnerModule,
        JsonPipe,
    ]
})
export class DataSourceErrorComponent implements OnChanges, OnInit, OnDestroy {

  @Input()
  public error?: unknown | null | Observable<unknown>;

  @Input()
  public refresh?: () => void;

  @Input()
  public retry?: () => void;

  @Input()
  public reset?: () => void;

  @Input()
  public set dataSourceLike(value: DataSourceLikeForErrorHandling) {
    this.refresh ??= value.refresh;
    this.retry ??= value.retry;
    this.reset ??= value.reset;
    this.loading ??= value.loading ?? value.loading$;
    this.error ??= value.error ?? value.error$;
  }

  @Input()
  public loading?: Observable<boolean> | boolean;

  public isNotRelease = false;

  public errorMessage = signal('Unknown Error');

  public retryInProgress = signal(false);
  public resetInProgress = signal(false);

  private _subscription?: Subscription;

  constructor(
    @Inject(RXAP_ENVIRONMENT)
    private readonly environment: Environment,
  ) {
    this.isNotRelease = IsNotReleaseVersion(environment);
  }

  ngOnChanges(changes: SimpleChanges) {
    if (changes['error']) {
      this.retryInProgress.set(false);
      this.resetInProgress.set(false);
    }
    if (changes['loading']) {
      if (!changes['loading'].currentValue && typeof changes['loading'].currentValue === 'boolean') {
        this.retryInProgress.set(false);
        this.resetInProgress.set(false);
      }
    }
  }

  ngOnDestroy() {
    this._subscription?.unsubscribe();
  }

  ngOnInit() {
    this._subscription = new Subscription();
    if (this.loading instanceof Observable) {
      this._subscription.add(this.loading.subscribe((loading) => {
        if (!loading) {
          if (this.retryInProgress()) {
            this.retryInProgress.set(false);
          }
          if (this.resetInProgress()) {
            this.resetInProgress.set(false);
          }
        }
      }));
    }
    if (this.error instanceof Observable) {
      this._subscription.add(this.error.subscribe((error) => {
        if (error) {
          this.errorMessage.set(error.message);
        }
      }));
    }
  }

  triggerRetry() {
    if (this.retry) {
      this.retryInProgress.set(true);
      this.retry();
    } else if (this.refresh) {
      this.retryInProgress.set(true);
      this.refresh();
    }
  }

  triggerReset() {
    if (this.reset) {
      this.resetInProgress.set(true);
      this.reset();
    }
  }

}
<div class="p-10 w-full">
  <div class="flex flex-col justify-center items-center gap-8">
    <span i18n>Something has gone wrong!</span>
    <div class="flex flex-row justify-center items-center gap-4">
      <button *ngIf="refresh || retry" type="button" (click)="triggerRetry()" [disabled]="retryInProgress() || resetInProgress()" mat-stroked-button>
        <span class="flex flex-row items-center gap-4">
          <span i18n>Retry</span>
          <mat-spinner *ngIf="retryInProgress()" [diameter]="15"></mat-spinner>
        </span>
      </button>
      <button *ngIf="reset" type="button" (click)="triggerReset()" [disabled]="resetInProgress() || retryInProgress()" mat-stroked-button>
        <span class="flex flex-row items-center gap-4">
          <span i18n>Reset</span>
          <mat-spinner *ngIf="resetInProgress()" [diameter]="15"></mat-spinner>
        </span>
      </button>
    </div>
    <span *ngIf="isNotRelease" class="text-red-700">{{errorMessage()}}</span>
  </div>
</div>

./data-source-error.component.scss

.container {
  padding: 64px;
  width: 100%;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""