Skip to content

Save state directive angular

Description

Exmaple directive to use exportAs property and call internal signals/function.

Directive

typescript
import {
  computed,
  Directive,
  effect,
  inject,
  input,
  signal,
} from '@angular/core';
import { Settings } from '@mathematic-std/core';
import { ListViewComponent } from '@mathematic-std/core/list-view';

@Directive({
  selector: '[collapsedStateDirective]',
  exportAs: 'collapsedState',
})
export class CollapsedStateDirective {
  // localstorage wrapped service
  private _settings = inject(Settings);

  collapsedEntity = signal<string[] | null>(null);
  collapsedKeys = input.required<string[] | null>();
  collapsedSettingKey = input.required<string>();

  #_entityCollapsedChanged = effect(() => {
    // sync to settings
    const keys = this.collapsedKeys();
    if (!this.collapsedEntity() || !keys) {
      return;
    }

    const model = this._getCollapsedModel(this.collapsedSettingKey());
    for (const key of keys) {
      model[key] = this.collapsedEntity();
    }

    this._settings.setValue(this.collapsedSettingKey(), model);
  });

  entityCollapsedValue = computed(() => {
    const keys = this.collapsedKeys();
    if (!keys) {
      return [];
    }

    const model = this._getCollapsedModel(this.collapsedSettingKey());
    const mergedModel = [];
    for (const key of keys) {
      mergedModel.push(...(model[key] || []));
    }

    return mergedModel;
  });

  private _getCollapsedModel = (key: string): any => {
    const _model = this._settings.value(key, {});
    return Array.isArray(_model) ? {} : _model;
  };

  onPersistCollapsed(event: any, ref: ListViewComponent) {
    if (ref.processing()) return;
    this.collapsedEntity.set(event);
  }
}

Usage

html

...
<mat-list-view
  #listViewRef
  collapsedStateDirective
  #collapsedStateRef="collapsedState"
  [collapsedKeys]="['key1', 'key2']"
  [collapsedSettingKey]="'collapsed-state-lvexample'"
  [collapsed]="collapsedStateRef.entityCollapsedValue()"
  (collapsedChange)="collapsedStateRef.onPersistCollapsed(
    $event,
    listViewRef
  )"
></mat-list-view>
...

Note that:

  • the name of the directive is important, you need to end it with Directive to be able to use it in the template.
  • collapsedStateRef is the name of the instance of the directive, we export it as collapsedState.