File

projects/i-components/src/lib/components/container/container.component.ts

Description

Angular Component for the container Control.

Implements

DoCheck

Metadata

selector wm-container
styleUrls ./container.component.scss

Index

Properties
Methods
Inputs
Accessors

Constructor

constructor(componentFactoryResolver: ComponentFactoryResolver, changeDetectorNotifier: ChangeDectionNotifierService, cd: ChangeDetectorRef, differs: IterableDiffers, viewContainerRef: ViewContainerRef, injectorBase: Injector)

Creates an instance of ContainerComponent.

Parameters :
Name Type Optional
componentFactoryResolver ComponentFactoryResolver No
changeDetectorNotifier ChangeDectionNotifierService No
cd ChangeDetectorRef No
differs IterableDiffers No
viewContainerRef ViewContainerRef No
injectorBase Injector No

Inputs

controls
Type : any

Set the controls to render.

Methods

addControl
addControl(record: any)

Add a new control to the current Angular view

Parameters :
Name Type Optional
record any No
Returns : void
applyChanges
applyChanges(changes: any)

This method apply changes when any of the following actions in the model is triggered: forEachRemovedItem: Something has been removed. forEachAddedItem: Something has been added.

Parameters :
Name Type Optional
changes any No
Returns : void
detectChangesAction
detectChangesAction()

Handle subscription to the notifyDetectChanges action Refresh the component whenever a model modification was performed

Returns : void
intermediateControl
intermediateControl(record: any)

Add an intermediate control if needed.

Parameters :
Name Type Optional
record any No
Returns : ViewContainerRef

{ViewContainerRef}

Private markForCheckComp
markForCheckComp()

Marks current component

Returns : void
ngDoCheck
ngDoCheck()

This is part of Angular lifecycle hook. Review the changes in the control's collection and perform the instantiation of the new control's

Returns : void
removeControl
removeControl(id: string)

Removes the dynamically opened control

Parameters :
Name Type Optional
id string No
Returns : void

Properties

controlsCollection
Type : any
Default value : {}

An array of components to render corresponding to the control's that are displayed dynamically

Private differences
Type : any

The differences that the collection has.

Protected ngZone
Type : NgZone

Angular´s NgZone accessor

openedComponents
Type : any
Default value : {}

Keeps a reference to the dynamically opened components.

timeoutChangeDetection
Type : null
Default value : null

The timeour change detection

Public viewContainerRef
Type : ViewContainerRef

Reference to the view containerRef for the component that contains the directive

Accessors

controls
getcontrols()

Get the controls to render

Returns : any
setcontrols(value: any)

Set the controls to render.

Parameters :
Name Type Optional
value any No
Returns : void
import {
  Component,
  ComponentFactoryResolver,
  ComponentRef,
  DoCheck,
  IterableChangeRecord,
  IterableDiffers,
  Input,
  ViewContainerRef,
  ChangeDetectorRef,
  Optional,
  Injector,
  NgZone,
} from '@angular/core';
import { UIElement, Guid } from '@mobilize/wms-framework';
import { ChangeDectionNotifierService } from '../../services';
import { Utils } from '../../utils/utilities';
import { CanvasItemComponent } from '../canvas-item/canvas-item.component';

/**
 * Angular Component for the container Control.
 *
 * @export
 * @class ContainerComponent
 */
@Component({
  selector: 'wm-container',
  template: ``,
  styleUrls: ['./container.component.scss'],
})
export class ContainerComponent implements DoCheck {
  /**
   * Reference to the view containerRef for the component that contains the directive
   *
   * @type {ViewContainerRef}
   * @memberof ContainerComponent
   */
  public viewContainerRef: ViewContainerRef;

  /**
   * Keeps a reference to the dynamically
   * opened components.
   *
   * @type {*}
   * @memberof ContainerComponent
   */
  openedComponents: any = {};

  /**
   * The timeour change detection
   *
   * @memberof ContainerComponent
   */
  timeoutChangeDetection = null;

  /**
   * An array of components to render corresponding to the
   * control's that are displayed dynamically
   *
   * @type {any[]}
   * @memberof ContainerComponent
   */
  controlsCollection: any = {};

  /**
   * Set the controls to render.
   *
   * @memberof ContainerComponent
   */
  @Input()
  set controls(value: any) {
    this.controlsCollection = value ?? {};
    /* istanbul ignore else */
    if (!this.differences && this.differs && value && value.dynamics) {
      this.differences = this.differs
        .find(this.controlsCollection.dynamics)
        .create();
    }
  }

  /**
   * Get the controls to render
   *
   * @readonly
   * @type {any[]}
   * @memberof ContainerComponent
   */
  get controls(): any {
    return this.controlsCollection;
  }

  /**
   * The differences that the collection has.
   *
   * @private
   * @type {*}
   * @memberof ContainerComponent
   */
  private differences: any;

  /**
   * Angular´s NgZone accessor
   *
   * @protected
   * @type {NgZone}
   * @memberof ContainerComponent
   */
  protected ngZone: NgZone;

  /**
   * Creates an instance of ContainerComponent.
   *
   * @param {ComponentFactoryResolver} componentFactoryResolver
   * @memberof ContainerComponent
   */
  constructor(
    private componentFactoryResolver: ComponentFactoryResolver,
    private changeDetectorNotifier: ChangeDectionNotifierService,
    private cd: ChangeDetectorRef,
    protected differs: IterableDiffers,
    viewContainerRef: ViewContainerRef,
    @Optional() protected injectorBase: Injector = null
  ) {
    if (this.injectorBase != null) {
      this.ngZone = injectorBase.get(NgZone);
    }
    this.viewContainerRef = viewContainerRef;
  }

  /**
   * This is part of Angular lifecycle hook.
   * Review the changes in the control's collection and perform the
   * instantiation of the new control's
   *
   * @memberof ContainerComponent
   */
  ngDoCheck(): void {
    /* istanbul ignore else */
    if (this.differences) {
      const changes = this.differences.diff(this.controlsCollection.dynamics);
      /* istanbul ignore else */
      if (changes) {
        this.applyChanges(changes);
      }
    }
  }

  /**
   * This method apply changes when any of the following actions in the model is triggered:
   * forEachRemovedItem: Something has been removed.
   * forEachAddedItem: Something has been added.
   *
   * @param {*} changes
   * @memberof ContainerComponent
   */
  applyChanges(changes: any): void {
    changes.forEachRemovedItem((record: IterableChangeRecord<any>) =>
      this.removeControl(record.item['_wmuid'])
    );
    changes.forEachAddedItem((record: IterableChangeRecord<any>) =>
      this.addControl(record)
    );
  }

  /**
   * Add a new control to the current Angular view
   *
   * @param {string} id - id to track the component
   * @param {*} componentToLoad - Angular Component to update
   * @param {Injector} inject - Angular injector to create the new component
   * @memberof ContainerComponent
   */
  addControl(record: any): void {
    const uid = Guid.newGuid().toString();
    record.item['_wmuid'] = uid;
    const dynamic = Utils.getUIControls(
      [record.item],
      this.controlsCollection.injector
    )[0];
    const viewContainerRef = this.intermediateControl(record);
    const componentRef = viewContainerRef.createComponent(dynamic.component, {
      index: null,
      injector: dynamic.customInjector,
    }) as ComponentRef<any>;
    if (
      ['stackpanel', 'tabcontrol', 'wrappanel', 'xamTileMngr'].indexOf(
        this.controlsCollection.container
      ) > -1
    ) {
      this.openedComponents[uid] = componentRef;
    }

    this.detectChangesAction();
  }

  /**
   * Add an intermediate control if needed.
   *
   * @param {*} record
   * @return {*}  {ViewContainerRef}
   * @memberof ContainerComponent
   */
  intermediateControl(record: any): ViewContainerRef {
    let viewContainerRef = this.viewContainerRef;
    switch (this.controlsCollection.container) {
      case 'canvas': {
        let itemIndex: number = undefined;
        if (this.controlsCollection.dynamics?.indexOf && record.item) {
          itemIndex = this.controlsCollection.dynamics.indexOf(record.item);
          itemIndex = itemIndex >= 0 ? itemIndex : undefined;
        }
        const componentRef = viewContainerRef.createComponent(
          CanvasItemComponent,
          { index: itemIndex }
        ) as ComponentRef<any>;
        if (record.item instanceof UIElement) {
          componentRef.instance.itemInfo = record.item;
        } else {
          componentRef.instance.itemInfo = record.item.model;
        }
        this.openedComponents[record.item['_wmuid']] = componentRef;
        viewContainerRef =
          componentRef.instance.componentContainer.viewContainerRef;
        break;
      }

      case 'grid': {
        break;
      }
    }

    return viewContainerRef;
  }

  /**
   * Removes the dynamically opened control
   *
   * @param model The control's id unique identifier.
   * @memberof ContainerComponent
   */
  removeControl(id: string): void {
    /* istanbul ignore else */
    if (this.openedComponents[id]) {
      this.openedComponents[id].destroy();
      delete this.openedComponents[id];
    }
    this.detectChangesAction();
  }

  /**
   * Handle subscription to the notifyDetectChanges action
   * Refresh the component whenever a model modification was performed
   *
   * @memberof ContainerComponent
   */
  detectChangesAction(): void {
    if (this.ngZone) {
      // if ngZone is defined then make sure it executes markforCheck inside Angular´s Zone
      this.ngZone?.run(() => {
        this.markForCheckComp();
      });
    } else {
      this.markForCheckComp();
    }
  }

  /**
   * Marks current component
   *
   * @private
   * @memberof ContainerComponent
   */
  private markForCheckComp(): void {
    this.cd?.markForCheck();
    if (this.changeDetectorNotifier?.timeout) {
      clearTimeout(this.changeDetectorNotifier.timeout);
    }
    if (this.changeDetectorNotifier) {
      this.changeDetectorNotifier.timeout = setTimeout(() => {
        this.changeDetectorNotifier?.notifyDetectChanges(null);
      }, this.changeDetectorNotifier.timer);
    }
  }
}

./container.component.scss

Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""