File

libs/ngx-pfe/services/pfe-business-service/business.service.ts

Description

The PfeBusinessService provides functionality, that can be used in the pages to retrieve and store data in the state and to access other parts of the application.

Index

Properties
Methods
Accessors

Constructor

constructor(pfeConfigService: PfeConfigurationService, pfeStateService: PfeStateService, pfeNavService: PfeNavigationService, pfeServiceActivatorService: PfeServiceActivatorService, pfeTranslateService: PFETranslateService, logger: NgxLoggerService)
Parameters :
Name Type Optional
pfeConfigService PfeConfigurationService No
pfeStateService PfeStateService No
pfeNavService PfeNavigationService No
pfeServiceActivatorService PfeServiceActivatorService No
pfeTranslateService PFETranslateService No
logger NgxLoggerService No

Methods

Async getErrorPage
getErrorPage(errorResponse?: HttpErrorResponse)
Parameters :
Name Type Optional
errorResponse HttpErrorResponse Yes
Returns : unknown
Async getFirstPage
getFirstPage()
getFullState
getFullState()
Returns : PfeUserInputState
Async getNextPage
getNextPage(pageNavConfig: PageNavigationConfiguration)
Parameters :
Name Type Optional
pageNavConfig PageNavigationConfiguration No
Returns : unknown
getObservableForExpressionKey
getObservableForExpressionKey(expression: JsonPathExpression, triggerForUndefined?: boolean, disableDeepEqual?: boolean)
Parameters :
Name Type Optional
expression JsonPathExpression No
triggerForUndefined boolean Yes
disableDeepEqual boolean Yes
Returns : Observable<any>
getObservableForKey
getObservableForKey(key: string, triggerForUndefined?: boolean, disableDeepEqual?: boolean)
Parameters :
Name Type Optional
key string No
triggerForUndefined boolean Yes
disableDeepEqual boolean Yes
Returns : Observable<any>
Public getPageConfigFromRoute
getPageConfigFromRoute(activatedRoute: ActivatedRoute)
Parameters :
Name Type Optional
activatedRoute ActivatedRoute No
Returns : PAGE_CONFIG_TYPE
Async getPageConfiguration
getPageConfiguration(pageID: string)
Parameters :
Name Type Optional
pageID string No
Async getPreviousPage
getPreviousPage(pageNavConfig: PageNavigationConfiguration)
Parameters :
Name Type Optional
pageNavConfig PageNavigationConfiguration No
Returns : unknown
getValue
getValue(key: string)

Returns previously stored data by its key.

Parameters :
Name Type Optional
key string No
Returns : any
getValueByExpression
getValueByExpression(jsonPathExpression: string)
Parameters :
Name Type Optional
jsonPathExpression string No
Returns : any
Public Async hasConfig
hasConfig()
Returns : unknown
Async navigateBack
navigateBack()
Async navigateNext
navigateNext(ignorePageStatus?: boolean)
Parameters :
Name Type Optional
ignorePageStatus boolean Yes
Async navigateToErrorPage
navigateToErrorPage(errorResponse?: HttpErrorResponse)
Parameters :
Name Type Optional
errorResponse HttpErrorResponse Yes
Returns : unknown
Async navigateToPage
navigateToPage(pageId: string, triggerLeaveActions?: boolean)
Parameters :
Name Type Optional
pageId string No
triggerLeaveActions boolean Yes
Returns : unknown
Public ngOnDestroy
ngOnDestroy()
Returns : void
restoreState
restoreState()
Returns : Promise<any>
Public setPageFormIdsToStaleState
setPageFormIdsToStaleState(formIds: string[])

setPageFormIds to stale state

Parameters :
Name Type Optional
formIds string[] No
Returns : void
setPageStatus
setPageStatus(pageStatus: boolean)

Sets the validity status of the current page. When a page is opened it is considered invalid. This will prevent the navigation. Once the page is valid, navigation will be allowed.

Parameters :
Name Type Optional
pageStatus boolean No
Returns : void
storeValue
storeValue(key: string, value: any)
Parameters :
Name Type Optional
key string No
value any No
Returns : void
storeValueByExpression
storeValueByExpression(expression: JsonPathExpression, value: any)
Parameters :
Name Type Optional
expression JsonPathExpression No
value any No
Returns : void
Async triggerServiceActivators
triggerServiceActivators(pageId: string, hook?: ServiceActivatorHook)

Triggers the service activators for a given page and action.

{string} pageId the pageId whose service activators will be triggered {ServiceActivatorHook} hook triggers onEnter or onLeave service activators, default is onEnter.

Parameters :
Name Type Optional
pageId string No
hook ServiceActivatorHook Yes
Returns : any
Async triggerSingleServiceActivator
triggerSingleServiceActivator(serviceCallInput: string | NavServiceActivatorConfig, httpErrorHandler?: HttpErrorHandler)

Triggers a specific service activator. Either a service activator configuration or just its id is given as input. If the service activator id is provided, the service activator configuration is extracted from the current page configuration or the global config.

It returns the HttpResponse in a Promise for service activators that are NOT marked as async (flow async) Error responses are also returned by rejecting the Promise.

It is advisable to use the disableErrorPageNavigation flag for service activators that are called via code. Otherwise the currently active page will be left and a navigation to the error page is done.

Parameters :
Name Type Optional Description
serviceCallInput string | NavServiceActivatorConfig No

the id of the service activator to be triggered or a service activator configuration

httpErrorHandler HttpErrorHandler Yes

an optional custom callback function to receive an information in case any error

a Promise with the HttpResponse or HTTPError

Properties

Public busy$
Type : Observable<boolean>
Default value : combineLatest([ this.pfeServiceActivatorService.serviceActivatorCallInProgress$, this.pfeNavService.navigationInProgress$, ]).pipe(map(([serviceActivator, navigation]) => serviceActivator || navigation))

Signals if the pfe is busy with:

  • A service activator call
  • An action that is tied to a navigation
  • A navigation itself

For example, this can be used to show a loading animation in an app for those events.

Public currentPageId$
Type : BehaviorSubject<string | undefined>
Default value : this.pfeNavService.currentPageId$
Public pageStatus$
Type : BehaviorSubject<boolean>
Default value : this.pfeNavService.pageStatus$
Public serviceActivatorCallInProgressDetails$
Type : Observable<NavServiceActivatorConfig[]>
Default value : this.pfeServiceActivatorService.serviceActivatorCallInProgressDetails$

Accessors

serviceActivatorCallInProgress$
getserviceActivatorCallInProgress$()

Set to true, when a navigation or network call (service activator call) is currently running.

Returns : BehaviorSubject<boolean>
errorMessage$
geterrorMessage$()
import { NgxLoggerService } from '@allianz/ngx-logger';
import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { Injectable, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { BehaviorSubject, Observable, Subject, combineLatest } from 'rxjs';
import { first, map, takeUntil } from 'rxjs/operators';
import { PFETranslateService } from '../../i18n/pfe-translate.service';
import { JsonPathExpression } from '../../models/jsonpath-expression-type.model';
import { PageNavigationConfiguration, ServiceActivatorHook } from '../../models/navigation-config.model';
import { PageConfig } from '../../models/ngx-pfe-page-config.model';
import { PfeUserInputState } from '../../models/pfe-state/user-input-state.model';
import { NavServiceActivatorConfig } from '../../pfe-service-activator/service/service-activator.model';
import { HttpErrorHandler, PfeServiceActivatorService } from '../../pfe-service-activator/service/service-activator.service';
import { PfeConfigurationService } from '../pfe-config-service/config-service.service';
import { PfeNavigationService } from '../pfe-navigation-service/navigation.service';
import { PfeStateService } from '../pfe-state-service/state.service';

export const PAGE_CONFIG_ROUTE_ATTRIBUTE_NAME = 'pageConfig';

/**
 * The PfeBusinessService provides functionality, that can be used in the pages to retrieve and store data
 * in the state and to access other parts of the application.
 *
 * @export
 */
@Injectable()
// eslint-disable-next-line @typescript-eslint/naming-convention
export class PfeBusinessService<PAGE_CONFIG_TYPE extends PageConfig = PageConfig> implements OnDestroy {
  public currentPageId$: BehaviorSubject<string | undefined> = this.pfeNavService.currentPageId$;
  public pageStatus$: BehaviorSubject<boolean> = this.pfeNavService.pageStatus$;

  /**
   * Signals if the pfe is busy with:
   *
   * - A service activator call
   * - An action that is tied to a navigation
   * - A navigation itself
   *
   * For example, this can be used to show a loading animation in an app for those events.
   */
  public busy$: Observable<boolean> = combineLatest([
    this.pfeServiceActivatorService.serviceActivatorCallInProgress$,
    this.pfeNavService.navigationInProgress$,
  ]).pipe(map(([serviceActivator, navigation]) => serviceActivator || navigation));

  public serviceActivatorCallInProgressDetails$: Observable<NavServiceActivatorConfig[]> =
    this.pfeServiceActivatorService.serviceActivatorCallInProgressDetails$;

  private componentDestroyed$ = new Subject<void>();
  private _errorMessageSubject$ = new BehaviorSubject<string | undefined>(undefined);
  private _errorMessage$: Observable<string | undefined> = this._errorMessageSubject$.asObservable();
  private errorMessageDisplayInitialized = false;

  constructor(
    private pfeConfigService: PfeConfigurationService,
    private pfeStateService: PfeStateService,
    private pfeNavService: PfeNavigationService,
    private pfeServiceActivatorService: PfeServiceActivatorService,
    private pfeTranslateService: PFETranslateService,
    private logger: NgxLoggerService
  ) {}
  /**
   * Set to true, when a navigation or network call (service activator call) is currently running.
   */
  get serviceActivatorCallInProgress$(): BehaviorSubject<boolean> {
    return this.pfeServiceActivatorService.serviceActivatorCallInProgress$;
  }

  /**
   * @deprecated This will be moved to a separate optional service
   */
  public get errorMessage$(): Observable<string | undefined> {
    if (!this.errorMessageDisplayInitialized) {
      this.initializeValidationDisplay();
      this.errorMessageDisplayInitialized = true;
    }
    return this._errorMessage$;
  }

  public async hasConfig() {
    return (await this.pfeConfigService.getConfig()) !== undefined;
  }

  async getErrorPage(errorResponse?: HttpErrorResponse) {
    return await this.pfeNavService.getErrorPage(errorResponse);
  }

  async getFirstPage(): Promise<string | undefined> {
    return await this.pfeNavService.getFirstPage();
  }

  async navigateNext(ignorePageStatus?: boolean): Promise<PageConfig | undefined> {
    if (!ignorePageStatus && !this.pfeNavService.pageStatus$.value) {
      return;
    }
    return this.pfeNavService.navigateNext();
  }

  async navigateBack(): Promise<PageConfig | undefined> {
    return this.pfeNavService.navigateBack();
  }

  async navigateToPage(pageId: string, triggerLeaveActions?: boolean) {
    return await this.pfeNavService.navigateToPageId(pageId, triggerLeaveActions);
  }

  async navigateToErrorPage(errorResponse?: HttpErrorResponse) {
    return await this.pfeNavService.navigate(await this.pfeNavService.getErrorPage(errorResponse));
  }

  async getNextPage(pageNavConfig: PageNavigationConfiguration) {
    const pageID = await this.pfeNavService.getNextPage(pageNavConfig);
    return pageID;
  }

  async getPreviousPage(pageNavConfig: PageNavigationConfiguration) {
    const pageID = await this.pfeNavService.getPreviousPage(pageNavConfig);
    return pageID;
  }

  async getPageConfiguration(pageID: string): Promise<PageConfig | undefined> {
    return await this.pfeConfigService.getPageConfiguration(pageID);
  }

  /**
   * Sets the validity status of the current page.
   * When a page is opened it is considered invalid.
   * This will prevent the navigation.
   * Once the page is valid, navigation will be allowed.
   */
  setPageStatus(pageStatus: boolean): void {
    this.pfeNavService.pageStatus$.next(pageStatus);
  }

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  storeValue(key: string, value: any) {
    this.pfeStateService.storeValue(key, value);
  }

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  storeValueByExpression(expression: JsonPathExpression, value: any) {
    this.pfeStateService.storeValueByExpression(expression, value);
  }

  /**
   * Returns previously stored data by its key.
   *
   * @param key
   */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  getValue(key: string): any {
    return this.pfeStateService.getValue(key);
  }

  /**
   * {@link PfeStateService.getObservableForKey}
   *
   * @param key
   */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  getObservableForKey(key: string, triggerForUndefined?: boolean, disableDeepEqual?: boolean): Observable<any> {
    return this.pfeStateService.getObservableForKey(key, triggerForUndefined, disableDeepEqual);
  }

  /**
   * {@link PfeStateService.getObservableForExpressionKey}
   *
   * @param key
   */
  getObservableForExpressionKey(
    expression: JsonPathExpression,
    triggerForUndefined?: boolean,
    disableDeepEqual?: boolean
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
  ): Observable<any> {
    return this.pfeStateService.getObservableForExpressionKey(expression, triggerForUndefined, disableDeepEqual);
  }

  getValueByExpression(jsonPathExpression: string) {
    return this.pfeStateService.getStateValueByExpression(jsonPathExpression);
  }

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  restoreState(): Promise<any> {
    return this.pfeStateService.automaticallyRestoreState();
  }

  getFullState(): PfeUserInputState {
    return this.pfeStateService.getFullState();
  }

  /**
   * Triggers the service activators for a given page and action.
   *
   * {string} pageId the pageId whose service activators will be triggered
   * {ServiceActivatorHook} hook triggers onEnter or onLeave service activators, default is onEnter.
   */
  async triggerServiceActivators(pageId: string, hook?: ServiceActivatorHook) {
    const pageConfig: PageNavigationConfiguration | undefined = await this.pfeConfigService.getPageNavigationConfiguration(pageId);
    if (!pageConfig) {
      return;
    }

    try {
      const serviceActivators =
        hook === ServiceActivatorHook.LEAVE ? pageConfig.onPageLeaveServiceActivators : pageConfig.onPageEnterServiceActivators;
      if (serviceActivators) {
        await this.pfeServiceActivatorService.spreadWithGlobalServiceActivatorConfig(serviceActivators);
        await this.pfeServiceActivatorService.handleServiceActivators(serviceActivators, pageConfig.executeServiceActivatorsSync);
        await this.pfeServiceActivatorService.waitForAsyncServiceActivators(pageConfig.pageId);
      } else {
        throw new Error('Could not determine service activators to be triggered.');
      }
    } catch (error) {
      // Error handling is done in showErrorPage
    }
  }

  /**
   * Triggers a specific service activator. Either a service activator configuration or just its id is given as input.
   * If the service activator id is provided, the service activator configuration is extracted from
   * the current page configuration or the global config.
   *
   * It returns the HttpResponse in a Promise for service activators that are NOT marked as async (flow async)
   * Error responses are also returned by rejecting the Promise.
   *
   * It is advisable to use the disableErrorPageNavigation flag for service activators that are called via code.
   * Otherwise the currently active page will be left and a navigation to the error page is done.
   *
   * @param serviceCallInput the id of the service activator to be triggered or a service activator configuration
   * @param httpErrorHandler an optional custom callback function to receive an information in case any error
   * @returns a Promise with the HttpResponse or HTTPError
   */
  async triggerSingleServiceActivator(
    serviceCallInput: string | NavServiceActivatorConfig,
    httpErrorHandler?: HttpErrorHandler
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
  ): Promise<HttpResponse<any> | undefined> {
    const pageConfig: PageNavigationConfiguration | undefined = await this.pfeConfigService.getPageNavigationConfiguration(
      this.pfeNavService.currentPageId$.value
    );
    let serviceActivator: NavServiceActivatorConfig | undefined;

    if (typeof serviceCallInput === 'string') {
      if (!pageConfig) {
        return;
      }

      const globalConfig = await this.pfeConfigService.getConfig();

      // So we are inside a page, fine!
      if (pageConfig.serviceActivators && pageConfig.serviceActivators[serviceCallInput]) {
        serviceActivator = pageConfig.serviceActivators[serviceCallInput];
      } else if (globalConfig.navConfiguration.serviceActivators) {
        // Ok, so the page has no service activator, lets check in global cfg
        serviceActivator = globalConfig.navConfiguration.serviceActivators[serviceCallInput];
      }

      if (!serviceActivator) {
        // eslint-disable-next-line max-len
        this.logger.error(
          `This serviceCallId "${serviceCallInput}" does not exist. Available option that you have from the configuration: `,
          pageConfig.serviceActivators,
          globalConfig.navConfiguration.serviceActivators
        );
        return;
      }
    } else {
      serviceActivator = serviceCallInput;
    }

    const serviceActivators = [serviceActivator];
    await this.pfeServiceActivatorService.spreadWithGlobalServiceActivatorConfig(serviceActivators);
    const response = await this.pfeServiceActivatorService.handleServiceActivators(
      serviceActivators,
      pageConfig?.executeServiceActivatorsSync,
      httpErrorHandler
    );
    if (pageConfig) {
      await this.pfeServiceActivatorService.waitForAsyncServiceActivators(pageConfig.pageId);
    }

    if (Array.isArray(response)) {
      // As only one service activator is triggered, there is only 1 response:
      return response[0];
    } else {
      // This will happen if a sequential execution is active
      return response;
    }
  }

  public getPageConfigFromRoute(activatedRoute: ActivatedRoute): PAGE_CONFIG_TYPE {
    return activatedRoute.snapshot.data[PAGE_CONFIG_ROUTE_ATTRIBUTE_NAME];
  }

  /**
   * setPageFormIds to stale state
   * @param formIds
   */
  public setPageFormIdsToStaleState(formIds: string[]) {
    this.pfeStateService.setStateIds(formIds);
  }

  public ngOnDestroy() {
    this.componentDestroyed$.next();
    this.componentDestroyed$.complete();
  }

  private async initializeValidationDisplay() {
    const errorMessageKey = await this.pfeConfigService.getErrorMessageKey();

    // set initial state of the error key to undefined
    this.storeValue(errorMessageKey, undefined);

    this.getObservableForKey(errorMessageKey, true)
      .pipe(takeUntil(this.componentDestroyed$))
      .subscribe((message) => {
        if (message) {
          this.pfeTranslateService
            .get(message as string)
            .pipe(first())
            .subscribe((translatedMessage: string) => {
              this._errorMessageSubject$.next(translatedMessage);
            });
        } else {
          this._errorMessageSubject$.next(undefined);
        }
      });
  }

  // TODO: Add getAppConfiguration
}

results matching ""

    No results matching ""