@WidgetComponent

nm-category-select-control

File

src/app/shared/widgets/search-app-search-widget/category-select-control/category-select-control.component.ts

Implements

OnDestroy

Metadata

changeDetection ChangeDetectionStrategy.OnPush
selector nm-category-select-control
styleUrls category-select-control.component.scss
templateUrl ./category-select-control.component.html

Index

Widget inputs
Widget outputs
Properties
Methods
Inputs
Outputs

Constructor

constructor(widgetframeService: WidgetframeService, store: AppdataStore, cd: ChangeDetectorRef, currentLocaleService: CurrentLocaleService)
Parameters :
Name Type Optional
widgetframeService WidgetframeService no
store AppdataStore no
cd ChangeDetectorRef no
currentLocaleService CurrentLocaleService no

Inputs

autofocus

Type: boolean

Default value: false

categoryPlaceholder

Type: string

categoryUrl
filterChannelTypes

Type: string[]

includeSubCategories

Default value: false

initialCategoryValues

Type: any[]

initPublication
localStorageRecovery

Default value: true

multi

Default value: true

placeholder

Type: string

preferredPosition

Default value: ["combo-bottom", "combo-top"]

readonly

Type: boolean

selectedPublication
showIncludeSubCategories

Default value: false

showPublicationDropdown

Default value: true

value

Outputs

change $event type: EventEmitter
includeSubCategoriesChange $event type: EventEmitter

Methods

Private configureTreeWidget
configureTreeWidget()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
onIncludeSubCategoriesChange
onIncludeSubCategoriesChange()
Returns : void
onPublicationChange
onPublicationChange(fromSelect: )
Parameters :
Name Optional Default value
fromSelect no true
Returns : void
Private recoverPublication
recoverPublication()
Returns : void
resetValue
resetValue(event: )
Parameters :
Name Optional
event no
Returns : boolean

Properties

Private _isRecovering
_isRecovering: boolean
Type : boolean
Default value : false
Public _selectedPublication
_selectedPublication:
Private _value
_value:
Private elementRef
elementRef: ElementRef
Type : ElementRef
Decorators : ViewChild
Public filter
filter: LookupFilter
Type : LookupFilter
Public filterCtrl
filterCtrl: FormControl
Type : FormControl
Default value : new FormControl()
Private initializing
initializing:
Default value : true
Public publications
publications: []
Type : []
Default value : []
Private staticPublication
staticPublication:
Default value : false
treeComponent
treeComponent: SelectTreeWidgetComponent
Type : SelectTreeWidgetComponent
Decorators : ViewChild
Private unsubscribe
unsubscribe:
Default value : NgUnsubscribe.create()

Accessors

value
setvalue(value: )
Parameters :
Name Optional
value no
Returns : void
selectedPublication
setselectedPublication(pub: )
Parameters :
Name Optional
pub no
Returns : void
initPublication
setinitPublication(publication: )
Parameters :
Name Optional
publication no
Returns : void
import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  ElementRef,
  EventEmitter,
  Input,
  OnDestroy,
  Output,
  ViewChild,
} from "@angular/core";
import { FormControl } from "@angular/forms";
import { WidgetframeService } from "../../widgetframe/widgetframe.service";
import { AppdataStore } from "../../../components/appdata/appdata.store";
import { combineLatest, of } from "rxjs";
import { SelectTreeWidgetComponent } from "../../select-tree";
import { WidgetConfig } from "../../../widgets/widget.configuration";
import { NgUnsubscribe } from "../../../ng-unsubscribe";
import { flatMap, map, takeUntil } from "rxjs/operators";
import { CurrentLocaleService } from "../../../components/i18n/currentLocale.service";
import { LookupFilter } from "../../../util/lookup.filter";
import { getOrDefault } from "../../widget.configuration";

@Component({
  selector: "nm-category-select-control",
  templateUrl: "./category-select-control.component.html",
  styleUrls: ["./category-select-control.component.scss"],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CategorySelectControlComponent implements OnDestroy {
  private unsubscribe = NgUnsubscribe.create();
  @Input()
  public placeholder: string;

  @Input()
  public categoryPlaceholder: string;

  @Input()
  public showPublicationDropdown = true;

  @Input()
  public localStorageRecovery = true;

  @Input()
  public showIncludeSubCategories = false;

  @Input()
  public includeSubCategories = false;

  @Input()
  public multi = true;

  @Input()
  public autofocus: boolean = false;

  @Input()
  public filterChannelTypes: string[];

  @Input()
  public categoryUrl;

  @Input()
  public preferredPosition = ["combo-bottom", "combo-top"];

  @Input()
  public readonly: boolean;

  @Input() public set value(value) {
    if (value === this._value) {
      return;
    }
    if (value && this._value) {
      if (
        value.publication === this._value.publication &&
        value.category === this._value.category
      ) {
        return;
      }
    }
    if (this._value && !value) {
      this._selectedPublication = null;
      this.treeComponent.resetChannel.next();
    }

    this._value = value;
    if (value && value.category) {
      this.recoverPublication();
    }
  }

  @Input() public set selectedPublication(pub) {
    this._selectedPublication = pub;
    this.staticPublication = true;
    this.onPublicationChange(true);
  }

  @Input() public set initPublication(publication) {
    if (publication) {
      this._selectedPublication = publication;
      this.staticPublication = true;
      this.treeComponent.rootCategoryLink = publication._links.self.href;
      this.treeComponent.rootSearchCategoryLink =
        publication._links.search.href;
      this.treeComponent.reloadChannel.next();
      this.initializing = false;
    }
  }

  @Input() public initialCategoryValues: any[];

  @Output() public change = new EventEmitter<{
    publication: any;
    category: any;
    paths: string[][];
  }>();

  @Output() public includeSubCategoriesChange = new EventEmitter<any>();

  public publications = [];

  public _selectedPublication;
  private staticPublication = false;

  private initializing = true;

  private _value;

  public filter: LookupFilter;
  public filterCtrl: FormControl = new FormControl();

  @ViewChild("tree", { read: SelectTreeWidgetComponent, static: true })
  treeComponent: SelectTreeWidgetComponent;

  @ViewChild("input") private elementRef: ElementRef;

  private _isRecovering: boolean = false;

  constructor(
    private widgetframeService: WidgetframeService,
    private store: AppdataStore,
    private cd: ChangeDetectorRef,
    private currentLocaleService: CurrentLocaleService
  ) {}

  private recoverPublication() {
    //We are pre ngOnInit so the filter isnt setup yet. We will do this again in the init
    if (!this.filter) {
      return;
    }
    const publication = this.filter
      .getLookups()
      .find((publication) => publication.identifier == this._value.publication);
    if (publication === this._selectedPublication) {
      return;
    }

    this._isRecovering = true;

    if (publication) {
      this._selectedPublication = publication;
      this.onPublicationChange(false);
      this.cd.markForCheck();

      if (this._value.category) {
        this.treeComponent.selectionPath.next(this._value.paths);
      }
    }

    this._isRecovering = false;
  }

  ngOnInit(): void {
    this.filter = new LookupFilter("description");

    this.placeholder = getOrDefault(this.placeholder, "table.head.taxonomy");
    this.categoryPlaceholder = getOrDefault(
      this.categoryPlaceholder,
      "table.head.category"
    );

    const linkObs = this.categoryUrl
      ? of(this.categoryUrl)
      : this.store
          .getAppdata()
          .pipe(
            map((data) => data.ipim._links["category-select-publications"].href)
          );

    combineLatest([linkObs, this.currentLocaleService.getCurrentLocale()])
      .pipe(
        map((data) => data[0]),
        flatMap((link) => this.widgetframeService.getData(link))
      )
      .subscribe((data) => {
        const dataType = data.type;
        this.publications =
          this.filterChannelTypes && this.filterChannelTypes.length > 0
            ? data._embedded[dataType].filter(
                (publication) =>
                  this.filterChannelTypes.indexOf(publication["channel-type"]) >
                  -1
              )
            : data._embedded[dataType];

        this.filter.setLookups(this.publications);

        if (this.staticPublication) {
          return;
        }

        if (this._value) {
          this.recoverPublication();
          this.cd.markForCheck();
        } else {
          if (this._selectedPublication) {
            this._selectedPublication = null;
            this.onPublicationChange(true);
            this.cd.markForCheck();
          }
        }
      });
    this.configureTreeWidget();

    if (this.initialCategoryValues && this.initialCategoryValues.length > 0) {
      const categories = this.initialCategoryValues
        .filter((source) => source.id && source.value)
        .map((source) => {
          return { id: source.id, description: source.value };
        });
      this.treeComponent.initCategoryFromInput(categories);
    }
  }

  private configureTreeWidget() {
    const treeConfig: WidgetConfig = {
      id: "category-select-edit-tree",
      component: "",
      configuration: {
        "localstorage-category": this.localStorageRecovery
          ? "category-select-edit-tree"
          : null,
        "local-storage-key": this.localStorageRecovery
          ? "category-select-edit-tree-key"
          : null,
        dataType: "products",
        placeholder: this.categoryPlaceholder,
        multi: this.multi,
        triggerAsChipList: true,
      },
    };
    this.treeComponent.configuration = treeConfig;
    this.treeComponent.configureWidget(treeConfig);

    this.treeComponent.selectionEmitter
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((selection) => {
        if (this._isRecovering) {
          return;
        }

        const description = selection
          .map((value) => value.description)
          .join(" | ");
        const category = selection.map((value) => value.category);
        const paths = selection.map((value) => value.path);

        const rootNode = selection.length > 0 ? selection[0].root : null;

        if (!this._value) {
          this._value = {};
        }
        this._value.category = category;
        this._value.paths = paths;

        if (this._selectedPublication) {
          const data = {
            publication: this._selectedPublication.identifier,
            publicationDescription: this._selectedPublication.description,
            category,
            categoryDescription: description,
            includeSubCategories: this.includeSubCategories,
            rootNode: rootNode,
            paths,
          };
          this.change.next(data);
        }
      });
  }

  onPublicationChange(fromSelect = true) {
    if (this._selectedPublication) {
      this.treeComponent.rootCategoryLink = this._selectedPublication._links.self.href;
      this.treeComponent.rootSearchCategoryLink = this._selectedPublication._links.search?.href;

      if (!fromSelect && this.initializing) {
        this.treeComponent.reloadChannel.next();
      } else {
        this.treeComponent.resetChannel.next();
      }
    } else {
      // clear selection from tree, if the publication is reset
      this.treeComponent.rootCategoryLink = null;
      this.treeComponent.rootSearchCategoryLink = null;
      this.treeComponent.resetChannel.next();
      this.change.next({ publication: null, category: null, paths: null });
    }
    this.initializing = false;
  }

  resetValue(event) {
    this._selectedPublication = null;
    this.treeComponent.resetChannel.next();
    event.preventDefault();
    event.stopPropagation();
    this.change.next({ publication: null, category: null, paths: null });
    return false;
  }

  onIncludeSubCategoriesChange() {
    this.includeSubCategoriesChange.emit(this.includeSubCategories);
  }

  ngOnDestroy(): void {
    this.unsubscribe.destroy();
  }
}
<div class="nm-categorySelector">
  <div class="nm-categorySelector__publication" *ngIf="showPublicationDropdown">
    <mat-form-field [ngClass]="{ virgin: !_selectedPublication }">
      <mat-select
        class="{{ _selectedPublication ? 'with-clear-button' : '' }}"
        [(value)]="_selectedPublication"
        (selectionChange)="onPublicationChange()"
        [placeholder]="placeholder | translate"
        (keydown.backspace)="resetValue($event)"
        [nmAutofocus]="autofocus"
      >
        <mat-select-trigger *ngIf="_selectedPublication">
          {{ _selectedPublication.description }}
          <div
            class="nm-categorySelector__selectedRowChip"
            *ngIf="_selectedPublication.chips"
          >
            <nm-chip
              *ngFor="let chip of _selectedPublication.chips"
              class="nm-select-chips__chip"
              [modifier]="chip.color"
              [content]="chip.value"
              [toUpperCase]="true"
            >
            </nm-chip>
          </div>
        </mat-select-trigger>
        <mat-option>
          <ngx-mat-select-search
            placeholderLabel="{{ 'placeholder.search' | translate }}"
            [formControl]="filter.getFilterControl()"
            noEntriesFoundLabel="{{ 'select.no.options' | translate }}"
            (keydown.escape)="selectSearch.matSelect.focus()"
            #selectSearch
          >
          </ngx-mat-select-search>
        </mat-option>
        <mat-option></mat-option>
        <mat-option
          *ngFor="let publication of filter.getFilteredLookups() | async"
          [value]="publication"
        >
          {{ publication.description }}
          <div class="nm-categorySelector__chip" *ngIf="publication.chips">
            <nm-chip
              *ngFor="let chip of publication.chips"
              class="nm-select-chips__chip"
              [modifier]="chip.color"
              [content]="chip.value"
              [toUpperCase]="true"
            >
            </nm-chip>
          </div>
        </mat-option>
      </mat-select>
      <button
        mat-icon-button
        matSuffix
        aria-label="Clear"
        color="primary"
        class="clear-button"
        *ngIf="_selectedPublication"
        (click)="resetValue($event)"
        tabIndex="-1"
      >
        <mat-icon color="primary" class="fade-in">close</mat-icon>
      </button>
    </mat-form-field>
  </div>
  <div
    class="nm-categorySelector__tree"
    [class.edit-tree]="showPublicationDropdown"
  >
    <nm-edit-tree
      #tree
      [disabled]="readonly || !_selectedPublication"
      [filterable]="true"
      [preferredPosition]="preferredPosition"
    >
    </nm-edit-tree>
  </div>
  <mat-checkbox
    *ngIf="showIncludeSubCategories"
    [(ngModel)]="includeSubCategories"
    class="nm-categorySelector__checkbox"
    color="primary"
    (ngModelChange)="onIncludeSubCategoriesChange()"
  >
    <span> {{ "label.include-sub-categories" | translate }} </span>
  </mat-checkbox>
</div>
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""