@anglr/grid
Version:
Angular module displaying grid
275 lines • 11 kB
JavaScript
import { Component, ChangeDetectionStrategy, ElementRef, Inject, Optional, forwardRef, resolveForwardRef, signal, inject, computed, Injector } from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
import { CommonModule } from '@angular/common';
import { MatDialog } from '@angular/material/dialog';
import { PERMANENT_STORAGE, LocalizePipe } from '@anglr/common';
import { GRID_PLUGIN_INSTANCES, METADATA_SELECTOR_OPTIONS } from '@anglr/grid';
import { extend } from '@jscrpt/common/extend';
import { skip } from 'rxjs';
import { VerticalDragNDropSelectionComponent } from '../../../components';
import * as i0 from "@angular/core";
import * as i1 from "@angular/material/dialog";
import * as i2 from "@angular/common";
/**
* Default options for dialog metadata selector
*/
const defaultOptions = {
storageName: null,
dialogCompnentOptions: {
dragDisabled: false,
},
cssClasses: {
btnElement: 'btn btn-primary',
btnIconElement: 'fas fa-list grid-margin-right-extra-small',
dialogComponentClasses: {
titleElement: 'metadata-columns-title',
resetMetadataIconElement: 'fas fa-rotate-right',
columnsContainer: 'metadata-columns',
columnElement: 'metadata-column',
dragIndicationElement: 'fas fa-bars'
}
},
texts: {
btnShowSelection: 'column selection',
dialogComponentTexts: {
selectionTitle: 'columns'
}
},
showButtonVisible: true,
dialogComponent: forwardRef(() => VerticalDragNDropSelectionComponent),
};
/**
* Component for rendering dialog metadata selector
*/
export class DialogMetadataSelectorComponent {
/**
* @inheritdoc
*/
get options() {
return this.optionsValue();
}
set options(options) {
this.optionsValue.update(opts => extend(true, opts, options));
}
/**
* @inheritdoc
*/
get metadata() {
return this.metadataValue;
}
//######################### constructor #########################
constructor(storage, dialog, options) {
this.storage = storage;
this.dialog = dialog;
/**
* Metadata for dialog component
*/
this.metadataForDialogComponent = computed(() => {
return {
...this.allMetadata(),
columns: this.columnsForSelection(),
};
});
/**
* Instance of injector used for DI
*/
this.injector = inject(Injector);
/**
* Indication whether gahterer has been initialized
*/
this.gathererInitialized = false;
/**
* All metadata that are available
*/
this.allMetadata = signal(null);
/**
* Array of visiblity flags for columns originaly obtained from metadata selector
*/
this.originalColumnsVisibility = [];
/**
* Columns for selection that are currently
*/
this.columnsForSelection = signal([]);
//######################### public properties - implementation of DialogMetadataSelector #########################
/**
* @inheritdoc
*/
this.gridPlugins = inject(GRID_PLUGIN_INSTANCES, { optional: true });
/**
* @inheritdoc
*/
this.pluginElement = inject((ElementRef));
this.optionsValue = signal(extend(true, {}, defaultOptions, options));
this.metadataValue = computed(() => {
return {
...this.allMetadata(),
columns: this.columnsForSelection().filter(itm => itm.visible),
};
});
}
//######################### public methods - implementation of OnDestroy #########################
/**
* Called when component is destroyed
*/
ngOnDestroy() {
this.metadataChangedSubscription?.unsubscribe();
this.metadataChangedSubscription = null;
}
//######################### public methods - implementation of DialogMetadataSelector #########################
/**
* @inheritdoc
*/
show() {
if (!this.dialogComponent) {
return;
}
this.dialog.open(this.dialogComponent, {
data: {
metadata: this.metadataForDialogComponent,
setMetadata: metadata => {
this.saveToStorage();
this.columnsForSelection.set([...metadata.columns]);
},
resetMetadata: () => {
this.resetMetadata();
},
cssClasses: this.options.cssClasses.dialogComponentClasses,
texts: this.options.texts.dialogComponentTexts,
options: this.options.dialogCompnentOptions,
}
});
}
/**
* @inheritdoc
*/
resetMetadata() {
if (this.options.storageName) {
this.storage.remove(this.options.storageName);
}
//reset visiblity of all columns
const allMetadata = this.metadataGatherer?.metadata();
if (!allMetadata) {
this.allMetadata.set(null);
this.initMetadata();
return;
}
for (let x = 0; x < allMetadata.columns.length; x++) {
const col = allMetadata.columns[x];
col.visible = this.originalColumnsVisibility[x] ?? false;
}
this.allMetadata.set({ ...allMetadata });
this.initMetadata();
}
/**
* @inheritdoc
*/
setMetadataGatherer(gatherer) {
if (this.metadataGatherer != gatherer) {
this.gathererInitialized = false;
}
this.metadataGatherer = gatherer;
}
/**
* @inheritdoc
*/
initialize(force) {
this.dialogComponent = resolveForwardRef(this.options.dialogComponent);
if (force || !this.gathererInitialized) {
if (!this.metadataGatherer) {
throw new Error('DialogMetadataSelectorComponent: missing metadata gatherer!');
}
const initMetadataFn = (allMetadata) => {
this.originalColumnsVisibility = allMetadata?.columns.map(itm => itm.visible) ?? [];
this.allMetadata.set(allMetadata);
this.initMetadata();
};
this.metadataChangedSubscription?.unsubscribe();
this.metadataChangedSubscription = toObservable(this.metadataGatherer.metadata, { injector: this.injector })
.pipe(skip(1))
.subscribe(initMetadataFn);
initMetadataFn(this.metadataGatherer.metadata());
this.gathererInitialized = true;
}
}
/**
* @inheritdoc
*/
initOptions() {
}
/**
* @inheritdoc
*/
invalidateVisuals() {
}
//######################### protected methods #########################
/**
* Initialize metadata
*/
initMetadata() {
const storageState = this.loadFromStorage();
const allMetadata = this.allMetadata();
if (storageState) {
allMetadata?.columns.forEach(meta => {
if (!meta.id) {
throw new Error('Missing id for column to be stored in storage!');
}
meta.visible = !!storageState[meta.id]?.visible;
});
this.columnsForSelection.set(Object.keys(storageState)
.map(id => allMetadata?.columns.find(itm => itm.id == id))
.filter(itm => !!itm)
.concat(allMetadata?.columns.filter(meta => !storageState[meta.id ?? 0]) ?? []));
}
else {
this.columnsForSelection.set([...(allMetadata?.columns ?? [])]);
}
}
/**
* Saves current state to storage
*/
saveToStorage() {
if (!this.options.storageName) {
return;
}
const state = {};
this.columnsForSelection().forEach(meta => {
if (!meta.id) {
throw new Error('Missing id for column to be stored in storage!');
}
state[meta.id] =
{
visible: meta.visible,
id: meta.id,
title: meta.title,
};
});
this.storage.set(this.options.storageName, state);
}
/**
* Gets stored storage state
*/
loadFromStorage() {
if (!this.options.storageName) {
return null;
}
return this.storage.get(this.options.storageName);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.0", ngImport: i0, type: DialogMetadataSelectorComponent, deps: [{ token: PERMANENT_STORAGE }, { token: i1.MatDialog }, { token: METADATA_SELECTOR_OPTIONS, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.0", type: DialogMetadataSelectorComponent, isStandalone: true, selector: "ng-dialog-metadata-selector", ngImport: i0, template: "@if(optionsValue().showButtonVisible)\r\n{\r\n <div>\r\n <button type=\"button\" (click)=\"show()\" [ngClass]=\"optionsValue().cssClasses.btnElement\">\r\n <span [ngClass]=\"optionsValue().cssClasses.btnIconElement\"></span>\r\n <span>{{optionsValue().texts.btnShowSelection | localize}}</span>\r\n </button>\r\n </div>\r\n}", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: LocalizePipe, name: "localize" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.0", ngImport: i0, type: DialogMetadataSelectorComponent, decorators: [{
type: Component,
args: [{ selector: 'ng-dialog-metadata-selector', imports: [
CommonModule,
LocalizePipe,
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if(optionsValue().showButtonVisible)\r\n{\r\n <div>\r\n <button type=\"button\" (click)=\"show()\" [ngClass]=\"optionsValue().cssClasses.btnElement\">\r\n <span [ngClass]=\"optionsValue().cssClasses.btnIconElement\"></span>\r\n <span>{{optionsValue().texts.btnShowSelection | localize}}</span>\r\n </button>\r\n </div>\r\n}" }]
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Inject,
args: [PERMANENT_STORAGE]
}] }, { type: i1.MatDialog }, { type: undefined, decorators: [{
type: Inject,
args: [METADATA_SELECTOR_OPTIONS]
}, {
type: Optional
}] }] });
//# sourceMappingURL=dialogMetadataSelector.component.js.map