src/app/shared/widgets/container/container.component.ts
import {
AfterContentInit,
AfterViewChecked,
ChangeDetectorRef,
Component,
ComponentFactoryResolver,
ComponentRef,
EventEmitter,
HostBinding,
Input,
NgModule,
OnChanges,
OnDestroy,
OnInit,
Optional,
Output,
SimpleChanges,
ViewChild,
ViewContainerRef,
} from "@angular/core";
import { NmWidgetMetadataRegistry } from "../widget.metadata.registry";
import { WidgetRegistry } from "../widget.registry";
import { AppService, WidgetData } from "../configuration/app.service";
import { WidgetConfig } from "../widget.configuration";
import { UtilService } from "../../components/util";
import { CommonModule } from "@angular/common";
import { CoreComponentsModule } from "../../components/core-components.module";
import { WidgetForPipe } from "./widget-for.pipe";
import { MatDrawer, MatSidenavModule } from "@angular/material/sidenav";
import { MatFormFieldModule } from "@angular/material/form-field";
import { MatOptionModule } from "@angular/material/core";
import { MatSelectModule } from "@angular/material/select";
import { AppContext } from "../../components/app-context";
import { Subject } from "rxjs";
import { NmDrawerContainerComponent } from "./drawer-container.component";
import { MatCardModule } from "@angular/material/card";
import { MatIconModule } from "@angular/material/icon";
import { MatButtonModule } from "@angular/material/button";
@Component({
selector: "nm-container",
templateUrl: "container.component.html",
styleUrls: ["container.component.scss"],
host: { "[id]": "id", "[attr.data-layout]": "layout" },
// TODO: Check if following line is still valid
// can't be activated, until PIMWEB-1219 is completed
//changeDetection: ChangeDetectionStrategy.OnPush
})
export class NmContainerComponent
implements OnInit, OnChanges, AfterContentInit, AfterViewChecked, OnDestroy {
@ViewChild("target", { read: ViewContainerRef, static: true })
viewContainerRef: ViewContainerRef;
@HostBinding("class") hostClass = null;
public elementClass = null;
@Input()
public configuration: WidgetConfig;
@Input()
private parent: string;
@Input()
public id: string;
public layoutContainer: boolean;
public layout: string;
private cmpRef: ComponentRef<any>;
private isViewInitialized: boolean = false;
private widgetId: string;
private widgetData: WidgetData;
private componentChanged = false;
public dockMode = new Subject();
public sideMode: boolean = false;
@ViewChild("drawer", { static: false }) public drawer: MatDrawer;
@Output("component-initialized")
public componentInitialized = new EventEmitter<string>();
selectedMode: any;
constructor(
private appContext: AppContext,
private _resolver: ComponentFactoryResolver,
private changeDetectorRef: ChangeDetectorRef,
@Optional() private widgetRegistry: WidgetRegistry,
@Optional() private appService: AppService
) {}
updateComponent() {
if (!this.isViewInitialized) {
return;
}
if (this.cmpRef) {
if (this.appService && this.widgetId) {
this.appService.destroyComponent(this.widgetId);
}
this.cmpRef.destroy();
this.cmpRef = null;
}
if (!this.configuration) {
return;
}
this.layout = this.getOrientation();
this.layoutContainer = this.isLayoutContainer();
this.hostClass = UtilService.buildCssClass(
this.configuration.hostClass,
this.configuration.hostClassModifiers
);
this.elementClass = UtilService.buildCssClass(
this.configuration.elementClass,
this.configuration.elementClassModifiers
);
if (this.layoutContainer) {
//Still set that the component changed here so we will fire that the container is initialized later on
this.componentChanged = true;
return;
}
let { descriptor, widget } = this.createComponent();
if (this.appService) {
this.widgetData = this.appService.configure(
this.id,
widget,
descriptor,
this.configuration
);
this.widgetId = this.widgetData.widgetId;
} else if (this.widgetRegistry) {
this.widgetRegistry.configureWidget(
this.parent,
this.id,
this.configuration,
widget,
descriptor
);
}
this.componentChanged = true;
this.changeDetectorRef.markForCheck();
}
private createComponent() {
let component = this.configuration.component;
let descriptor = NmWidgetMetadataRegistry.getWidgetDescriptor(component);
if (!descriptor) {
throw new Error('no descriptor found for widget "' + component + '"');
}
let componentFactory = this._resolver.resolveComponentFactory(
descriptor.component
);
this.cmpRef = this.viewContainerRef.createComponent(componentFactory, 0);
if (this.elementClass) {
this.cmpRef.location.nativeElement.className = this.elementClass;
}
let widget = this.cmpRef.instance;
return { descriptor, widget };
}
private isLayoutContainer(): boolean {
if (!this.configuration) {
return false;
}
return (
this.configuration.component === "nm-horizontal-layout" ||
this.configuration.component === "nm-vertical-layout" ||
this.configuration.component === "nm-drawer-layout"
);
}
ngOnInit() {}
ngAfterViewChecked() {
if (this.componentChanged) {
this.componentChanged = false;
if (this.widgetData) {
this.widgetData.initializeChannels();
}
if (this.appService) {
this.appService.componentInitialized(this.id);
}
this.componentInitialized.emit(this.id);
}
}
ngOnChanges(changes: SimpleChanges) {
this.updateComponent();
}
ngAfterContentInit() {
this.isViewInitialized = true;
this.updateComponent();
}
ngOnDestroy() {
if (this.cmpRef) {
this.cmpRef.destroy();
}
}
private getOrientation(): string {
if (this.configuration.component === "nm-horizontal-layout") {
return "horizontal";
}
if (this.configuration.component === "nm-vertical-layout") {
return "vertical";
}
if (this.configuration.component === "nm-drawer-layout") {
return "drawer";
}
return "inherited";
}
onModeChange(value) {
console.log("onModeChange", value);
this.dockMode.next(value);
}
}
@NgModule({
imports: [
CommonModule,
CoreComponentsModule,
MatSidenavModule,
MatFormFieldModule,
MatOptionModule,
MatSelectModule,
MatCardModule,
MatIconModule,
MatButtonModule,
],
declarations: [
NmContainerComponent,
WidgetForPipe,
NmDrawerContainerComponent,
],
exports: [NmContainerComponent, WidgetForPipe, NmDrawerContainerComponent],
})
export class ContainerModule {}