File

services/app.service.ts

Description

Entrypoint to store for data mapping application.

Index

Properties
Methods
Accessors

Constructor

constructor()

Methods

addValidators
addValidators()
Returns : void
Private callHazardTilesUsage
callHazardTilesUsage()
Returns : Observable<void>
callService
callService()
Returns : void
Private callTreesUsage
callTreesUsage()
Returns : Observable<void>
createHazardLayer
createHazardLayer(layer?: Layer)

Create the hazard layer from hazard tile info.

Parameters :
Name Type Optional
layer Layer Yes
Returns : void
defaultFormValues
defaultFormValues()

Default control panel form field values.

Returns : ControlForm
filterTilesByImt
filterTilesByImt(tiles: HazardTile[], form: ControlForm)

Returns the hazard tiles for a specific region, year, and IMT.

Parameters :
Name Type Optional Description
tiles HazardTile[] No

The hazard tiles

form ControlForm No

Control panel form values

Returns : HazardTile[]
filterTilesByRegion
filterTilesByRegion(tiles: HazardTile[], form: ControlForm)

Returns the hazard tiles for a specific region.

Parameters :
Name Type Optional Description
tiles HazardTile[] No

The hazard tiles

form ControlForm No

Control panel form values

Returns : HazardTile[]
filterTilesByYear
filterTilesByYear(tiles: HazardTile[], form: ControlForm)

Returns the hazard tiles for a specific region and year.

Parameters :
Name Type Optional Description
tiles HazardTile[] No

The hazard tiles

form ControlForm No

Control panel form values

Returns : HazardTile[]
findTile
findTile(tiles: HazardTile[], form: ControlForm)

Returns the hazard tile for a specific region, year, IMT, and return period.

Parameters :
Name Type Optional Description
tiles HazardTile[] No

The hazard tiles

form ControlForm No

Control panel form values

Returns : HazardTile
init
init()

Initialize the application.

Returns : void
Private initialControlSet
initialControlSet(control: FormControl, defaultValue: boolean, queryValue?: string)
Parameters :
Name Type Optional
control FormControl<boolean> No
defaultValue boolean No
queryValue string Yes
Returns : void
Private initialFormSet
initialFormSet()
Returns : void
initialState
initialState()

Application initial state.

Returns : AppState
Private nshmIdFromString
nshmIdFromString(nshm: string)

Returns the NshmId from a string.

Parameters :
Name Type Optional Description
nshm string No

The NSHM string

Returns : NshmId
resetLayers
resetLayers()

Reset the style of all layers.

Returns : void
resetState
resetState()
Returns : void
sourceFeatureControl
sourceFeatureControl(featureType: FeatureType, featureTypes: string[], control: AbstractControl)

Check to see if feature type is included in the list of supported feature type to enable or disable the control form field.

Parameters :
Name Type Optional Description
featureType FeatureType No

The feature type

featureTypes string[] No

List of all feature types

control AbstractControl<boolean> No

Feature type form state

Returns : void
toggleLayer
toggleLayer(layer: Layer, checked: boolean, spinnerText: string)
Parameters :
Name Type Optional Default value
layer Layer No
checked boolean No
spinnerText string No 'Adding layer ...'
Returns : void
Private toHazardTiles
toHazardTiles(response: ArcServiceResponse)

Convert ArcGIS service response to HazardTiles.

Example JSON response:

Example :
{
"currentVersion": 10.61,
 "services": [
 {
   "name": "haz/AK1hz050_1999",
   "type": "MapServer"
 }
}
Parameters :
Name Type Optional Description
response ArcServiceResponse No

The ArcGIS service response

Returns : HazardTile[]
Private toImt
toImt(imt: string)

Returns the Imt corresponding to the IMT string in the map name.

Parameters :
Name Type Optional Description
imt string No

The IMT string

Returns : Imt
Private toNshmId
toNshmId(region: string, year: number)

Convert the region and year from the map name into a corresponding NshmId.

Parameters :
Name Type Optional Description
region string No

The region from map name

year number No

The year from map name

Returns : NshmId
Private toReturnPeriod
toReturnPeriod(returnPeriod: string)

Returns the ReturnPeriod from the corresponding string.

Parameters :
Name Type Optional Description
returnPeriod string No

The return period string from ArcGIS map name

Returns : ReturnPeriod
updateState
updateState(state: Partial<AppState>)
Parameters :
Name Type Optional
state Partial<AppState> No
Returns : void
Private updateUrl
updateUrl()
Returns : void

Properties

Private arcgisService
Default value : inject(ArcgisService)
Private destroyRef
Default value : inject(DestroyRef)
Private formBuilder
Default value : inject(NonNullableFormBuilder)
Readonly formGroup
Default value : this.formBuilder.group<ControlForm>(this.defaultFormValues())
Private hazardService
Default value : inject(HazardService)
Private http
Default value : inject(HttpClient)
Private location
Default value : inject(LocationService)
map
Default value : new ArcGisMap()
Private nshmpHazWs
Default value : environment.webServices.nshmpHazWs

nshmp-haz-ws web config

Private nshmpService
Default value : inject(NshmpService)
Private nshmsEndpoint
Default value : this.nshmpHazWs.services.nshms

Endpoint to NSHMs

Private route
Default value : inject(ActivatedRoute)
Private spinnerService
Default value : inject(SpinnerService)
Readonly state
Default value : signal<AppState>(this.initialState())

Application state

Accessors

availableModels
getavailableModels()

Returns the avialable models, as Parameters, observable.

Returns : Signal<Parameter[]>
hazardTiles
gethazardTiles()

Returns the hazard tiles.

layers
getlayers()

Returns the layers observable.

Returns : Signal<Layers>
nshmService
getnshmService()
sourceFeaturesUsage
getsourceFeaturesUsage()
treesUsageResponse
gettreesUsageResponse()

Returns the trees usage.

Returns : Signal<SourceLogicTreesUsage>
import {Location as LocationService} from '@angular/common';
import {HttpClient, HttpParams} from '@angular/common/http';
import {computed, DestroyRef, inject, Injectable, Signal, signal} from '@angular/core';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {AbstractControl, FormControl, NonNullableFormBuilder, Validators} from '@angular/forms';
import {ActivatedRoute} from '@angular/router';
import Layer from '@arcgis/core/layers/Layer';
import TileLayer from '@arcgis/core/layers/TileLayer';
import ArcGisMap from '@arcgis/core/Map';
import {HazardService} from '@ghsc/nshmp-lib-ng/hazard';
import {ArcgisService, LatestEarthquakeTime} from '@ghsc/nshmp-lib-ng/map';
import {NshmpService, nshmpUtils, ReturnPeriod} from '@ghsc/nshmp-lib-ng/nshmp';
import {SpinnerService} from '@ghsc/nshmp-template';
import {
  FeaturesUsageResponse,
  FeatureType,
} from '@ghsc/nshmp-utils-ts/libs/nshmp-haz/www/features-service';
import {NshmMetadata} from '@ghsc/nshmp-utils-ts/libs/nshmp-haz/www/nshm-service';
import {
  SourceLogicTreesMetadata,
  SourceLogicTreesUsage,
} from '@ghsc/nshmp-utils-ts/libs/nshmp-haz/www/source-logic-trees-service';
import {Imt} from '@ghsc/nshmp-utils-ts/libs/nshmp-lib/gmm';
import {NshmId, nshmRegion, nshmYear} from '@ghsc/nshmp-utils-ts/libs/nshmp-lib/nshm';
import {Parameter} from '@ghsc/nshmp-utils-ts/libs/nshmp-ws-utils/metadata';
import {environment} from 'projects/nshmp-apps/src/environments/environment';
import {AppServiceModel} from 'projects/nshmp-apps/src/shared/models/app-service.model';
import {apps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
import {catchError, forkJoin, map, mergeMap, Observable, of} from 'rxjs';

import {ControlForm} from '../models/control-form.model';
import {HazardTile} from '../models/hazard-tile.model';
import {ArcLayerId, Layers} from '../models/layers.model';
import {AppState} from '../models/state.model';

/**
 * ArcGIS hazard service info.
 */
interface ArcService {
  /** Name hazard map */
  name: string;
  /** Map type */
  type: string;
}

/**
 * ArcGIS hazard service response.
 */
interface ArcServiceResponse {
  /** Hazard maps */
  services: ArcService[];
}

interface Query {
  /** Whether zone source toggle is on */
  hasHazardTiles: string;
  /** IMT for hazard map tile */
  hazardTileImt: string;
  /** Return period for hazard map tile */
  hazardTileReturnPeriod: ReturnPeriod;
  /** Year for hazard map tile */
  hazardTileYear: string;
  /** Latest earthquake feed time frame */
  latestEarthquakeTime: LatestEarthquakeTime;
  /** The NSHM */
  model: NshmId;
  /** ArcGIS overlay opactiy */
  overlayOpacity: string;
  /** Whether devollement toggle is on */
  showDecollementLayer: string;
  /** Whether latest earthquake toggle is on */
  showEarthquakesLayer: string;
  /** Whether fault sections toggle is on */
  showFaultSectionLayer: string;
  /** Whether interface sections toggle is on */
  showInterfaceSectionsLayer: string;
  /** Whether NSHM boundary toggle is on*/
  showNshmBoundaryLayer: string;
  /** Whether test sites toggle is on */
  showTestSitesLayer: string;
  /** Whether zone sources is toggled on */
  showZoneSourcesLayer: string;
}

/**
 * Entrypoint to store for data mapping application.
 */
@Injectable({
  providedIn: 'root',
})
export class AppService implements AppServiceModel<AppState, ControlForm> {
  private formBuilder = inject(NonNullableFormBuilder);
  private spinnerService = inject(SpinnerService);
  private nshmpService = inject(NshmpService);
  private hazardService = inject(HazardService);
  private http = inject(HttpClient);
  private route = inject(ActivatedRoute);
  private location = inject(LocationService);
  private arcgisService = inject(ArcgisService);
  private destroyRef = inject(DestroyRef);

  readonly formGroup = this.formBuilder.group<ControlForm>(this.defaultFormValues());

  /** Application state */
  readonly state = signal<AppState>(this.initialState());

  map = new ArcGisMap();

  /** nshmp-haz-ws web config */
  private nshmpHazWs = environment.webServices.nshmpHazWs;

  /** Endpoint to NSHMs */
  private nshmsEndpoint = this.nshmpHazWs.services.nshms;

  constructor() {
    this.addValidators();
  }

  /**
   * Returns the avialable models, as `Parameter`s, observable.
   */
  get availableModels(): Signal<Parameter[]> {
    return computed(() => this.state().availableModels);
  }

  /**
   * Returns the hazard tiles.
   */
  get hazardTiles(): Signal<HazardTile[]> {
    return computed(() => this.state().hazardTiles);
  }

  /**
   * Returns the layers observable.
   */
  get layers(): Signal<Layers> {
    return computed(() => this.state().layers);
  }

  get nshmService(): Signal<NshmMetadata> {
    return computed(() =>
      this.state().nshmServices.find(nshm => nshm.model === this.formGroup.getRawValue().model),
    );
  }

  get sourceFeaturesUsage(): Signal<FeaturesUsageResponse> {
    return computed(() =>
      this.state().sourceFeaturesUsages.get(this.formGroup.getRawValue().model),
    );
  }

  /**
   * Returns the trees usage.
   */
  get treesUsageResponse(): Signal<SourceLogicTreesUsage> {
    return computed(() =>
      this.state().treesUsageResponses?.get(this.formGroup.getRawValue().model),
    );
  }

  addValidators(): void {
    this.formGroup.controls.model.addValidators(control => Validators.required(control));
  }

  callService(): void {}

  /**
   * Create the hazard layer from hazard tile info.
   *
   * @param hazardTile The hazard tile
   */
  createHazardLayer(layer?: Layer): void {
    const checked = this.formGroup.getRawValue().hasHazardTiles;

    if (layer) {
      this.toggleLayer(layer, checked, 'Adding hazard layer ...');
    } else if (checked) {
      const hazardTile = this.findTile(this.hazardTiles(), this.formGroup.getRawValue());
      const opacity = this.formGroup.getRawValue().overlayOpacity;

      if (hazardTile === undefined) {
        return null;
      }

      const spinnerRef = this.spinnerService.show('Adding hazard ...');

      this.arcgisService.filterLayer(this.map, ArcLayerId.HAZARD);

      const url = `${environment.webServices.hazardTiles}/${hazardTile.mapName}/MapServer`;

      const hazardLayer = new TileLayer({
        id: ArcLayerId.HAZARD,
        legendEnabled: false,
        opacity: opacity / 100,
        url,
      });

      this.updateState({
        layers: {
          ...this.layers(),
          hazardLayer,
        },
      });

      this.map.add(hazardLayer);
      spinnerRef.close();
    }
  }

  /**
   * Default control panel form field values.
   */
  defaultFormValues(): ControlForm {
    return {
      hasHazardTiles: null,
      hazardTileImt: null,
      hazardTileReturnPeriod: null,
      hazardTileYear: null,
      latestEarthquakeTime: LatestEarthquakeTime.WEEK,
      model: NshmId.CONUS_2018,
      overlayOpacity: 60,
      showDecollementLayer: false,
      showEarthquakesLayer: false,
      showFaultSectionLayer: false,
      showInterfaceSectionsLayer: false,
      showNshmBoundaryLayer: false,
      showTestSitesLayer: false,
      showTracesOnlyFaultSections: false,
      showTracesOnlyInterfaceSections: false,
      showZoneSourcesLayer: false,
    };
  }

  /**
   * Returns the hazard tiles for a specific region, year, and IMT.
   *
   * @param tiles The hazard tiles
   * @param form Control panel form values
   */
  filterTilesByImt(tiles: HazardTile[], form: ControlForm): HazardTile[] {
    if (form.model === null) {
      return [];
    }
    return this.filterTilesByYear(tiles, form)
      ?.filter(tile => tile.imt === form.hazardTileImt)
      .sort((a, b) => a.returnPeriod - b.returnPeriod);
  }

  /**
   * Returns the hazard tiles for a specific region.
   *
   * @param tiles The hazard tiles
   * @param form Control panel form values
   */
  filterTilesByRegion(tiles: HazardTile[], form: ControlForm): HazardTile[] {
    if (form.model === null) {
      return [];
    }

    return tiles
      ?.filter(tile => nshmRegion(tile.nshm) === nshmRegion(form.model))
      .sort((a, b) => nshmYear(a.nshm) - nshmYear(b.nshm));
  }

  /**
   * Returns the hazard tiles for a specific region and year.
   *
   * @param tiles The hazard tiles
   * @param form Control panel form values
   */
  filterTilesByYear(tiles: HazardTile[], form: ControlForm): HazardTile[] {
    if (form.model === null) {
      return [];
    }
    return this.filterTilesByRegion(tiles, form)
      .filter(tile => nshmYear(tile.nshm) === form.hazardTileYear)
      .sort((a, b) => (a.imt.toLowerCase() > b.imt.toLowerCase() ? 1 : -1));
  }

  /**
   * Returns the hazard tile for a specific region, year, IMT, and return period.
   *
   * @param tiles The hazard tiles
   * @param form Control panel form values
   */
  findTile(tiles: HazardTile[], form: ControlForm): HazardTile {
    return this.filterTilesByImt(tiles, form)?.find(
      tile => tile.returnPeriod === form.hazardTileReturnPeriod,
    );
  }

  /**
   * Initialize the application.
   */
  init(): void {
    const spinnerRef = this.spinnerService.show(SpinnerService.MESSAGE_METADATA);

    this.callTreesUsage()
      .pipe(takeUntilDestroyed(this.destroyRef))
      .pipe(
        mergeMap(() => forkJoin([this.callHazardTilesUsage()])),
        catchError(error => {
          this.initialFormSet();
          spinnerRef.close();
          console.error(error);
          return of();
        }),
      )
      .subscribe(() => {
        this.initialFormSet();
        spinnerRef.close();
      });
  }

  /**
   * Application initial state.
   */
  initialState(): AppState {
    const treesUsageResponses: Map<string, SourceLogicTreesUsage> = new Map();
    treesUsageResponses.set(NshmId.CONUS_2018, null);

    return {
      availableModels: [],
      hazardTiles: [],
      layers: {
        hazardLayer: null,
      },
      nshmServices: [],
      sourceFeaturesUsages: new Map(),
      treesUsageResponses,
      view: null,
    };
  }

  /**
   * Reset the style of all layers.
   */
  resetLayers(): void {
    Object.values(ArcLayerId).forEach(id => this.arcgisService.filterLayer(this.map, id));
  }

  resetState(): void {
    const values = this.formGroup.getRawValue();
    const hazardTiles = this.filterTilesByRegion(this.hazardTiles(), values);
    const defaultTile = [...hazardTiles].pop();
    this.resetLayers();

    this.updateState({
      layers: {
        hazardLayer: null,
      },
    });

    if (hazardTiles.length > 0) {
      this.formGroup.controls.hasHazardTiles.enable();
    } else {
      this.formGroup.controls.hasHazardTiles.disable();
    }

    this.formGroup.patchValue({
      hasHazardTiles: false,
      hazardTileImt: defaultTile?.imt,
      hazardTileReturnPeriod: defaultTile?.returnPeriod,
      hazardTileYear: defaultTile ? nshmYear(defaultTile?.nshm) : undefined,
    });

    // this.callService();
  }

  /**
   * Check to see if feature type is included in the list of supported feature type to
   * enable or disable the control form field.
   *
   * @param featureType The feature type
   * @param featureTypes List of all feature types
   * @param control Feature type form state
   */
  sourceFeatureControl(
    featureType: FeatureType,
    featureTypes: string[],
    control: AbstractControl<boolean>,
  ): void {
    control.setValue(false);

    if (featureTypes.includes(featureType)) {
      control.enable();
    } else {
      control.disable();
    }
  }

  toggleLayer(layer: Layer, checked: boolean, spinnerText = 'Adding layer ...'): void {
    if (checked) {
      const spinnerRef = this.spinnerService.show(spinnerText);
      this.map.add(layer);
      spinnerRef.close();
    } else {
      this.arcgisService.filterLayer(this.map, layer.id);
    }
  }

  updateState(state: Partial<AppState>): void {
    this.state.set({
      ...this.state(),
      ...state,
    });
  }

  private callHazardTilesUsage(): Observable<void> {
    return this.http.get<ArcServiceResponse>(`${environment.webServices.hazardTiles}?f=pjson`).pipe(
      map(response => {
        const hazardTiles = this.toHazardTiles(response);
        const controls = this.formGroup.controls;

        const hazardTilesForRegion = this.filterTilesByRegion(
          hazardTiles,
          this.formGroup.getRawValue(),
        );

        if (hazardTilesForRegion.length > 0) {
          controls.hasHazardTiles.enable();
        } else {
          controls.hasHazardTiles.disable();
        }

        const defaultTile = [...hazardTilesForRegion].pop();

        if (defaultTile) {
          this.formGroup.patchValue({
            hasHazardTiles: false,
            hazardTileImt: defaultTile?.imt,
            hazardTileReturnPeriod: defaultTile?.returnPeriod,
            hazardTileYear: nshmYear(defaultTile?.nshm),
          });
        }

        this.updateState({
          hazardTiles,
        });
      }),
    );
  }

  private callTreesUsage(): Observable<void> {
    return this.hazardService
      .dynamicNshms$<SourceLogicTreesMetadata>(
        `${this.nshmpHazWs.url}${this.nshmsEndpoint}`,
        environment.webServices.nshmpHazWs.services.curveServices.trees,
      )
      .pipe(
        map(({models, nshmServices, usageResponses}) => {
          this.updateState({
            availableModels: models,
            nshmServices,
            treesUsageResponses: usageResponses,
          });
        }),
        catchError((error: Error) => {
          return this.nshmpService.throwError$(error);
        }),
      );
  }

  private initialControlSet(
    control: FormControl<boolean>,
    defaultValue: boolean,
    queryValue?: string,
  ): void {
    if (control.enabled) {
      control.patchValue(nshmpUtils.queryParseBoolean(defaultValue, queryValue));
    }
  }

  private initialFormSet(): void {
    const query = this.route.snapshot.queryParams as Query;
    const defaultValues = this.defaultFormValues();
    const controls = this.formGroup.controls;

    this.formGroup.patchValue({
      model: query?.model ?? NshmId.CONUS_2018,
    });

    this.initialControlSet(
      controls.showTestSitesLayer,
      defaultValues.showTestSitesLayer,
      query?.showTestSitesLayer,
    );
    this.initialControlSet(
      controls.showDecollementLayer,
      defaultValues.showDecollementLayer,
      query?.showDecollementLayer,
    );
    this.initialControlSet(
      controls.showEarthquakesLayer,
      defaultValues.showEarthquakesLayer,
      query?.showEarthquakesLayer,
    );
    this.initialControlSet(
      controls.showFaultSectionLayer,
      defaultValues.showFaultSectionLayer,
      query?.showFaultSectionLayer,
    );
    this.initialControlSet(
      controls.hasHazardTiles,
      defaultValues.hasHazardTiles,
      query?.hasHazardTiles,
    );
    this.initialControlSet(
      controls.showInterfaceSectionsLayer,
      defaultValues.showInterfaceSectionsLayer,
      query?.showInterfaceSectionsLayer,
    );
    this.initialControlSet(controls.showNshmBoundaryLayer, true, query?.showNshmBoundaryLayer);
    this.initialControlSet(
      controls.showZoneSourcesLayer,
      defaultValues.showZoneSourcesLayer,
      query?.showZoneSourcesLayer,
    );

    this.formGroup.valueChanges
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe(() => this.updateUrl());
  }

  /**
   * Returns the `NshmId` from a string.
   *
   * @param nshm The NSHM string
   */
  private nshmIdFromString(nshm: string): NshmId {
    const nshmId = Object.values(NshmId).find(id => id.toString() === nshm);

    if (nshmId === undefined) {
      throw new Error(`NSHM ${nshm} not found`);
    }

    return nshmId;
  }

  /**
   * Convert ArcGIS service response to `HazardTile`s.
   *
   * Example JSON response:
   *  ```
   * {
   *  "currentVersion": 10.61,
   *   "services": [
   *   {
   *     "name": "haz/AK1hz050_1999",
   *     "type": "MapServer"
   *   }
   * }
   *  ```
   *
   * @param response The ArcGIS service response
   */
  private toHazardTiles(response: ArcServiceResponse): HazardTile[] {
    const services = response.services.filter(
      service => service.name.includes('hz') || service.name.includes('pga'),
    );

    const hazardTiles: HazardTile[] = [];

    // Example name: haz/USpga050_2008
    services.forEach(service => {
      const mapName = service.name.split('haz/').pop();
      const region = mapName.substring(0, 2);
      const imt = this.toImt(mapName.substring(2, 5));
      const returnPeriod = this.toReturnPeriod(mapName.substring(5, 8));
      const year = Number.parseInt(mapName.split('_').pop());
      const nshm = this.toNshmId(region, year);

      const hazardTile: HazardTile = {
        imt,
        mapName,
        nshm,
        returnPeriod,
      };

      hazardTiles.push(hazardTile);
    });

    return hazardTiles;
  }

  /**
   * Returns the `Imt` corresponding to the IMT string in the map name.
   *
   * @param imt The IMT string
   */
  private toImt(imt: string): Imt {
    switch (imt) {
      case 'pga':
        return Imt.PGA;
      case '5hz':
        return Imt.SA0P2;
      case '1hz':
        return Imt.SA1P0;
      default:
        throw new Error(`IMT [${imt}] not supported`);
    }
  }

  /**
   * Convert the region and year from the map name into a corresponding `NshmId`.
   * @param region The region from map name
   * @param year The year from map name
   * @returns
   */
  private toNshmId(region: string, year: number): NshmId {
    switch (region) {
      case 'AK':
        return this.nshmIdFromString(`${nshmRegion(NshmId.ALASKA_2023)}_${year}`);
      case 'HI':
        return this.nshmIdFromString(`${nshmRegion(NshmId.HAWAII_2021)}_${year}`);
      case 'US':
        return this.nshmIdFromString(`${nshmRegion(NshmId.CONUS_2023)}_${year}`);
      default:
        throw new Error(`Region [${region}] year [${year}] not supported`);
    }
  }

  /**
   * Returns the `ReturnPeriod` from the corresponding string.
   *
   * @param returnPeriod The return period string from ArcGIS map name
   */
  private toReturnPeriod(returnPeriod: string): ReturnPeriod {
    switch (returnPeriod) {
      // 10% in 50
      case '050':
        return ReturnPeriod.RP_475;
      // 2% in 50
      case '250':
        return ReturnPeriod.RP_2475;
      default:
        throw new Error(`Return period [${returnPeriod}] not supported`);
    }
  }

  private updateUrl(): void {
    this.location.replaceState(
      apps().source.modelMaps.routerLink,
      new HttpParams().appendAll(this.formGroup.getRawValue()).toString(),
    );
  }
}

results matching ""

    No results matching ""