Articles in this section
Category / Section

Render Syncfusion Angular components as Dynamic content in Dashboard Layout

8 mins read

This article explains how to render multiple components dynamically on the Angular Dashboard Layout component.


Get Started with Angular Dashboard Layout

Refer to this getting started to create an Angular Dashboard Layout component- https://ej2.syncfusion.com/angular/documentation/dashboard-layout/getting-started/


Render Dashboard Layout component

Render a dashboard Layout component using `ng-template`.

[app.component.html]

 
<div class="control-section">
  <div style="padding:5px;text-align: right;">
    <button id="add" class="e-btn e-info" (click)="addPanel()">
      Add Panel
    </button>
  </div>
  <ejs-dashboardlayout
    id="default_dashboard"
    #default_dashboard
    columns="2"
    [allowResizing]="true"
    [cellSpacing]="cellSpacing"
  >
    <e-panels>
      <e-panel
        *ngFor="let panel of panelsData"
        [id]="panel.id"
        [sizeX]="panel.sizeX"
        [sizeY]="panel.sizeY"
        [row]="panel.row"
        [col]="panel.col"
      >
        <ng-template #content>
          <span
            style="float:right; margin-right:40px;padding-top:10px;font-weight: bold;"
            (click)="addWidget($event)"
            >ⓘ</span
          >
          <span
            id="close"
            class="e-template-icon e-close-icon"
            (click)="onCloseIconHandler($event)"
          ></span>
          <div class="e-panel-container">
            <div class="text-align" [id]="panel.index">
              <ng-template #template> </ng-template>
            </div></div
        ></ng-template>
      </e-panel>
    </e-panels>
  </ejs-dashboardlayout>
 
  <div id="template"></div>
  <div id="modalDialog"></div>
  <div id="dialogcontent">
    <div>
      <div id="line_template">
        <p class="dialog-text">Line Chart (1x1)</p>
      </div>
      <div id="bar_template">
        <p class="dialog-text">Bar Chart (1x1)</p>
      </div>
      <div id="grid_template">
        <p class="dialog-text">Grid (2x1)</p>
      </div>
    </div>
  </div>
</div>
 

[app.component.ts]

 
import { Component, ViewChild, ViewEncapsulation } from '@angular/core';
import { ListBoxComponent } from '@syncfusion/ej2-angular-dropdowns';
import { DragAndDropEventArgs, NodeClickEventArgs, TreeViewComponent } from '@syncfusion/ej2-angular-navigations';
import { closest } from '@syncfusion/ej2-base';
import { AnalytesDragAndDrop } from './analytes-drag-and-drop';
import {
  Inject,
  ViewChildren,
  ViewContainerRef,
  QueryList,
  ComponentFactoryResolver,
  ComponentRef,
} from '@angular/core';
import { Component, ViewChild, ViewEncapsulation } from '@angular/core';
import { ListBoxComponent } from '@syncfusion/ej2-angular-dropdowns';
import { DragAndDropEventArgs, NodeClickEventArgs, TreeViewComponent } from '@syncfusion/ej2-angular-navigations';
import { closest } from '@syncfusion/ej2-base';
import { AnalytesDragAndDrop } from './analytes-drag-and-drop';
import {
  Inject,
  ViewChildren,
  ViewContainerRef,
  QueryList,
  ComponentFactoryResolver,
  ComponentRef,
} from '@angular/core';
import {
  DashboardLayoutComponent,
  PanelModel,
} from '@syncfusion/ej2-angular-layouts';
import { Dialog } from '@syncfusion/ej2-popups';
import { Chart, LineSeries, Category } from '@syncfusion/ej2-charts';
import { Button } from '@syncfusion/ej2-buttons';
import { ChartComponent } from './chart.component';
import { BarComponent } from './bar.component';
import { GridComponent } from './grid.component';
Chart.Inject(LineSeries, Category);
 
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  encapsulation: ViewEncapsulation.None,
})
 
export class AppComponent {
 
  @ViewChild('default_dashboard')
  public dashboard: DashboardLayoutComponent;
  componentRef: ComponentRef<ChartComponent>;
  componentRefOne: ComponentRef<BarComponent>;
  componentRefTwo: ComponentRef<GridComponent>;
  // @ViewChild('template', { read: ViewContainerRef })
  // viewTemplate: ViewContainerRef;
  @ViewChildren('template', { read: ViewContainerRef })
  viewTemplate: QueryList<ViewContainerRef>;
  constructor(private cfr: ComponentFactoryResolver) {}
  public count: number = 8;
  public dialogObj: Dialog;
  public target: any;
  public cellSpacing: number[] = [10, 10];
  public data: Object[] = [
    { month: 'Jan', sales: 35 },
    { month: 'Feb', sales: 28 },
    { month: 'Mar', sales: 34 },
    { month: 'Apr', sales: 32 },
    { month: 'May', sales: 40 },
    { month: 'Jun', sales: 32 },
    { month: 'Jul', sales: 35 },
    { month: 'Aug', sales: 55 },
    { month: 'Sep', sales: 38 },
    { month: 'Oct', sales: 30 },
    { month: 'Nov', sales: 25 },
    { month: 'Dec', sales: 32 }
  ];
  public axis: Object = {
    valueType: 'Category',
  };
 
  public panelsData: any = [
    {
      index: 0,
      id: 'one',
      sizeX: 1,
      sizeY: 1,
      row: 0,
      col: 0
    },
    {
      index: 1,
      id: 'two',
      sizeX: 3,
      sizeY: 1,
      row: 0,
      col: 1
    },
 
    {
      index: 2,
      id: 'three',
      sizeX: 2,
      sizeY: 1,
      row: 1,
      col: 0
    }
  ];
  addPanel(): void {
    let panel: PanelModel[] = [
      {
        id: this.count.toString(),
        sizeX: 1,
        sizeY: 1,
        row: 0,
        col: 0,
        content:
          '<span id="close" class="e-template-icon e-close-icon"></span><div class="text-align">' +
          this.count.toString() +
          '</div>'
      },
    ];
    this.dashboard.addPanel(panel[0]);
    let closeIcon: any = document
      .getElementById(this.count.toString())
      .querySelector('.e-close-icon');
    closeIcon.addEventListener('click', this.onCloseIconHandler.bind(this));
    this.count = this.count + 1;
  }
  onCloseIconHandler(event: any): void {
    if ((<HTMLElement>event.target).offsetParent) {
      this.dashboard.removePanel((<HTMLElement>event.target).offsetParent.id);
    }
  }
...

Render Angular Grid and Chart components


Render Data GridLine Chart, and Bar Chart components inside the app folder using Angular `template`.

[grid.component.ts]

import {
  Component,
  ViewEncapsulation,
  Input,
  Inject,
  ViewChild,
} from '@angular/core';
 
@Component({
  selector: 'grid-root',
  template: `<ejs-grid [dataSource]='gridData'>
  <e-columns>
      <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=90></e-column>
      <e-column field='CustomerID' headerText='Customer ID' width=120></e-column>
      <e-column field='Freight' headerText='Freight' textAlign='Right' format='C2' width=90></e-column>
      <e-column field='OrderDate' headerText='Order Date' textAlign='Right' format='yMd' width=120></e-column>
  </e-columns>
  </ejs-grid>`,
  encapsulation: ViewEncapsulation.None,
})
export class GridComponent {
  @Input() gridData: Object[];
  ngOnInit(): void {}
}
 
 

[chart.component.ts]

import {
  Component,
  ViewEncapsulation,
  Input,
  Inject,
  ViewChild,
} from '@angular/core';
 
@Component({
  selector: 'chart-root',
  template: `<ejs-chart
  [primaryXAxis]="primaryXAxis"
  width="100%"
  height="100%"
>
  <e-series-collection>
    <e-series
      [dataSource]="chartData"
      type="Line"
      xName="month"
      yName="sales"
      name="Sales"
    ></e-series>
  </e-series-collection>
</ejs-chart>`,
  encapsulation: ViewEncapsulation.None,
})
export class ChartComponent {
  @Input() primaryXAxis: Object;
  @Input() chartData: Object[];
  ngOnInit(): void {
    // Data for chart series
  }
}
 
 

[bar.component.ts]

import {
  Component,
  ViewEncapsulation,
  Input,
  Inject,
  ViewChild,
} from '@angular/core';
 
@Component({
  selector: 'bar-root',
  template: `<ejs-chart
  style="display:block;"
  [chartArea]="chartArea"
  width="100%"
  height="100%"
  [primaryXAxis]="primaryXAxis"
  [primaryYAxis]="primaryYAxis"
  [title]="title"
  [tooltip]="tooltip"
>
  <e-series-collection>
    <e-series
      [dataSource]="data"
      type="Bar"
      xName="x"
      yName="y"
      name="Imports"
      [marker]="marker"
    >
    </e-series>
    <e-series
      [dataSource]="data1"
      type="Bar"
      xName="x"
      yName="y"
      name="Exports"
      [marker]="marker"
    >
    </e-series>
  </e-series-collection>
</ejs-chart>`,
  encapsulation: ViewEncapsulation.None,
})
export class BarComponent {
  public chartArea: Object = {
    border: {
      width: 0,
    }
  };
  //Initializing Chart Width
  @Input() data: Object[];
  @Input() data1: Object[];
  //Initializing Marker
  public marker: Object = {
    dataLabel: {
      visible: true,
      position: 'Top',
      font: {
        fontWeight: '600',
        color: '#ffffff',
      },
    },
  };
  //Initializing Primary X Axis
  public primaryXAxis: Object = {
    valueType: 'Category',
    title: 'Food',
    interval: 1,
    majorGridLines: { width: 0 },
  };
  //Initializing Primary Y Axis
  public primaryYAxis: Object = {
    labelFormat: '{value}B',
    edgeLabelPlacement: 'Shift',
    majorGridLines: { width: 0 },
    majorTickLines: { width: 0 },
    lineStyle: { width: 0 },
    labelStyle: {
      color: 'transparent',
    },
  };
  public tooltip: Object = {
    enable: true,
  };
 
  // custom code end
  public title: string = 'UK Trade in Food Groups - 2015';
  constructor() {
    //code
  }
}
 

 

Render dynamic components as content of the Dashboard Layout

Render Angular component as panel content of the Dashboard Layout based on the selection using Angular’s `ComponentFactoryResolver’.

[app.component.ts]

export class AppComponent {
 
  ...
  addWidget(event) {
    this.target = event.target.closest('.e-panel').querySelector('.text-align');
    if (this.dialogObj == undefined) {
      this.dialogObj = new Dialog({
        width: '500px',
        header: 'Add a widget',
        showCloseIcon: true,
        animationSettings: { effect: 'Zoom' },
        content: document.getElementById('dialogcontent'),
        target: document.getElementById('target'),
        isModal: true,
        height: '260px',
        visible: false,
      });
      this.dialogObj.appendTo('#modalDialog');
    }
    this.dialogObj.show();
    document.getElementById('line_template').onclick = () => {
      this.dialogObj.hide();
      //Get the panel index.
      var count = this.target.id;
      this.viewTemplate.map((vcr: ViewContainerRef, index: number) => {
        //Check whether the panel index matches reference index.
        if (index == count && this.target.innerText == '') {
          const componentFactory =
            this.cfr.resolveComponentFactory(ChartComponent);
          this.componentRef = vcr.createComponent(componentFactory);
          this.componentRef.instance.chartData = this.data;
          this.componentRef.instance.primaryXAxis = this.axis;
        }
      });
    };
    document.getElementById('bar_template').onclick = () => {
      this.dialogObj.hide();
      var count = this.target.id;
      this.viewTemplate.map((vcr: ViewContainerRef, index: number) => {
        if (index == count && this.target.innerText == '') {
          const componentFactory =
            this.cfr.resolveComponentFactory(BarComponent);
          this.componentRefOne = vcr.createComponent(componentFactory);
          this.componentRefOne.instance.data = [
            { x: 'Egg', y: 2.2 },
            { x: 'Fish', y: 2.4 },
            { x: 'Misc', y: 3 },
            { x: 'Tea', y: 3.1 },
          ];
          this.componentRefOne.instance.data1 = [
            { x: 'Egg', y: 1.2 },
            { x: 'Fish', y: 1.3 },
            { x: 'Misc', y: 1.5 },
            { x: 'Tea', y: 2.2 },
          ];
        }
      });
    };
    document.getElementById('grid_template').onclick = () => {
      this.dialogObj.hide();
      var count = this.target.id;
      this.viewTemplate.map((vcr: ViewContainerRef, index: number) => {
        if (index == count && this.target.innerText == '') {
          const componentFactory =
            this.cfr.resolveComponentFactory(GridComponent);
          this.componentRefTwo = vcr.createComponent(componentFactory);
          this.componentRefTwo.instance.gridData = [
            {
              OrderID: 10248,
              CustomerID: 'VINET',
              EmployeeID: 5,
              OrderDate: new Date(8364186e5),
              ShipName: 'Vins et alcools Chevalier',
              ShipCity: 'Reims',
              ShipAddress: '59 rue de l Abbaye',
              ShipRegion: 'CJ',
              ShipPostalCode: '51100',
              ShipCountry: 'France',
              Freight: 32.38,
              Verified: !0,
            },
            {
              OrderID: 10249,
              CustomerID: 'TOMSP',
              EmployeeID: 6,
              OrderDate: new Date(836505e6),
              ShipName: 'Toms Spezialitäten',
              ShipCity: 'Münster',
              ShipAddress: 'Luisenstr. 48',
              ShipRegion: 'CJ',
              ShipPostalCode: '44087',
              ShipCountry: 'Germany',
              Freight: 11.61,
              Verified: !1,
            },
            {
              OrderID: 10250,
              CustomerID: 'HANAR',
              EmployeeID: 4,
              OrderDate: new Date(8367642e5),
              ShipName: 'Hanari Carnes',
              ShipCity: 'Rio de Janeiro',
              ShipAddress: 'Rua do Paço, 67',
              ShipRegion: 'RJ',
              ShipPostalCode: '05454-876',
              ShipCountry: 'Brazil',
              Freight: 65.83,
              Verified: !0,
            },
          ];
        }
      });
    };
  }
 
}
 
 

Screenshot:

 

Angular Dashboard Layout component with Grid and Chart as Dynamic component

 

GitHub sample - https://github.com/SyncfusionExamples/angular-dashboard-layout-dynamic-components


Conclusion


We hope you enjoyed learning about how to render Syncfusion Angular components as Dynamic content in Dashboard Layout.

You can refer to our Angular feature tour page to learn about its other groundbreaking feature representations and documentation, and how to quickly get started with configuration specifications. You can also explore our Angular dashboard-layout example to understand how to create and manipulate data.

For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to explore our other controls.

If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forums, BoldDesk Support, or feedback portal. We are always happy to assist you!

Did you find this information helpful?
Yes
No
Help us improve this page
Please provide feedback or comments
Comments (0)
Please  to leave a comment
Access denied
Access denied