Templates and dynamic columns

hi,
is it possible to use templates in conjunction with the dynamic-columns?
i am trying to adapt this sample https://www.syncfusion.com/forums/131923/dynamic-grid-with-dynamic-headertemplate

something like this:

<ejs-grid #grid width='100%' [dataSource]="data" [query]="query">
    <e-columns>
        <ng-template ngFor let-column [ngForOf]="columns">
            <e-column [field]="column.field"
                      [headerText]="column.headerText"
                      [allowEditing]="column.allowEditing"
                      [isPrimaryKey]="column.isPrimaryKey != null ? column.isPrimaryKey : null"
                      [template]="column.template"
                      [width]="column.width">
            </e-column>
        </ng-template>
    </e-columns>
</ejs-grid>

but i can't find the way to access the data(context) within the template.

<div id="myTemplate">
    <ng-template let-data #template>
        <div>
            <span style="background: red">{{data.id}}</span>
        </div>
    </ng-template>
</div>

the "data" is null!(:

am i doing something really wrong or is this scenario not supported?

regards
viktor

15 Replies

HJ Hariharan J V Syncfusion Team September 3, 2018 11:55 AM UTC

Hi Viktor, 

Thanks for contacting Syncfusion support. 


Based on your requirement we have created a sample ‘Grid columns and headerTemplate render dynamically’. Please find the code example and sample for your reference. 
 
Code example: 


[app.component.html] 

<ejs-grid #grid [dataSource]='data' [allowPaging]='true'> 
 
    <e-columns> 
        <ng-template #template ngFor let-column [ngForOf]="columns"> 
            <e-column [field]="column.field" 
                      [headerText]="column.headerText" 
                      [allowEditing]="column.allowEditing" 
                      [isPrimaryKey]="column.isPrimaryKey != null ? column.isPrimaryKey : null" 
                      [width]="column.width"> 
            </e-column> 
        </ng-template> 
    </e-columns> 
</ejs-grid> 
 
 
<ng-template #header> 
    <span class="e-icon-userlogin e-icons employee"></span> 
    Emp ID 
</ng-template> 
 
[app.component.ts] 
 

  export class DefaultComponent implements OnInit { 
. . . 
  public template: any; 
  @ViewChild('header') 
  public headerTemp: NgModel; 
  @ViewChild('grid') 
  public grid: Grid; 
  public columns: any; 
  ngOnInit(): void { 
 
    this.data = employeeData; 
    this.columns = [{ field: "EmployeeID", isPrimaryKey: "true", headerText: "Employee ID", width: "90" }, 
    { field: "FirstName", headerText: "First Name", width: "90" }, 
    { field: "LastName", headerText: "Last Name", width: "90", allowEditing: false }, 
    { field: "Country", headerText: "Country", width: "90" }] 
  } 
 
  ngAfterViewInit(): void { 
 
    (this.grid.getColumns()[3].headerTemplate as any) = this.headerTemp; 
  } 




Regards, 
Hariharan 



VI Viktor September 3, 2018 03:52 PM UTC

Hi Hariharan,
thank you for your prompt support!
that is highly appreciated.
but it is not exactly my requirement.
what i need is a something like this :

[app.component.ts]
this.columns = [
    { field: "EmployeeID", isPrimaryKey: "true", headerText: "Employee ID", width: "90" },
    { field: "FirstName", headerText: "First Name", width: "90" , template:"#template1"},
    { field: "LastName", headerText: "Last Name", width: "90", allowEditing: false , template:"#template2"},
    { field: "Country", headerText: "Country", width: "90", template:"#template3" }]
   
[app.component.html]


<ejs-grid #grid width='100%' [dataSource]="data" [query]="query">
    <e-columns>
        <ng-template ngFor let-column [ngForOf]="columns">
            <e-column [field]="column.field"
                      [headerText]="column.headerText"
                      [allowEditing]="column.allowEditing"                     
                      [template]="column.template"
                      [width]="column.width">
            </e-column>
        </ng-template>
    </e-columns>
</ejs-grid>

<ng-template let-data #template1>
    <div>
        <span style="background: red">{{data.id}}</span>
    </div>
</ng-template>

<ng-template let-data #template2>
    <div *ngFor:item of data.items>
        <span style="background: red">{{item.name}}</span>
    </div>
</ng-template>

<ng-template let-data #template2>
    <image [src]="data.src" />
</ng-template>

do you know what i mean?
Regards
Viktor


HJ Hariharan J V Syncfusion Team September 4, 2018 10:00 AM UTC

Hi Viktor, 
 
Thanks for your update. 
 
As per your requirement we have created a sample ‘Grid with multiple column-template render dynamically’.  Please find the code example and sample for your reference. 
 
Code example: 
 
 
<ejs-grid #grid [dataSource]='data' [allowPaging]='true'> 
 
    <e-columns> 
        <ng-template #template ngFor let-column [ngForOf]="columns"> 
            <e-column [field]="column.field" 
                      [headerText]="column.headerText" 
                      [allowEditing]="column.allowEditing" 
                      [isPrimaryKey]="column.isPrimaryKey != null ? column.isPrimaryKey : null" 
                      [width]="column.width"> 
            </e-column> 
        </ng-template> 
    </e-columns> 
</ejs-grid> 
 
<ng-template let-data #template1> 
    <div> 
        <span style="background: red">a</span> 
    </div> 
</ng-template> 
 
<ng-template let-data #template2> 
 
    <span style="background: blue">{{data.FirstName}}</span> 
 
</ng-template> 
 
<ng-template let-data #template3> 
    <span style="background:green">template-Data</span> 
</ng-template> 
</div> 
 
[app.component.ts] 
 
public data: Object[] = []; 
  public gridData: any; 
  public template: any; 
  @ViewChild('header') 
  public headerTemp: NgModel; 
  @ViewChild('template1') 
  public temp1: NgModel; 
    @ViewChild('template2') 
  public temp2: NgModel; 
    @ViewChild('template3') 
  public temp3: NgModel; 
  @ViewChild('grid') 
  public grid: Grid; 
  public columns: any; 
  ngOnInit(): void { 
 
    this.data = employeeData; 
    this.columns = [{ field: "EmployeeID", isPrimaryKey: "true", headerText: "Employee ID", width: "90" }, 
    { field: "FirstName", headerText: "First Name", width: "90" }, 
    { field: "LastName", headerText: "Last Name", width: "90", allowEditing: false }, 
    { field: "Country", headerText: "Country", width: "90" }] 
  } 
 
ngAfterViewInit(): void { 
 
    (this.grid.getColumns()[1].template as any) = this.temp1; 
    (this.grid.getColumns()[2].template as any) = this.temp2; 
    (this.grid.getColumns()[3].template as any) = this.temp3; 
  } 
 
} 
 
 
We need to initialize the template when initialize process completed (due to avoid time delay to initialize the  template) 
 
 
Regards 
Hariharan 



VI Viktor September 4, 2018 11:29 AM UTC

Hi Hariharan,
thank you again for your premium support!:)
i have slightly modified you code (see below) and  it works!
i think it is exactly what i need!!
you are the best!:)
consider this issue as closed!
thanks!
regards
Viktor

ngOnInit(): void {
    this.data = employeeData;
    this.columns = [
      { field: "EmployeeID", isPrimaryKey: "true", headerText: "Employee ID", width: "90",uid:"grid_column0" },
      { field: "FirstName", headerText: "First Name", width: "90", uid:"grid_column1", template:'#template1' },
      { field: "LastName", headerText: "Last Name", width: "90", allowEditing: false ,uid:"grid_column2", template:'#template2'},
      { field: "Country", headerText: "Country", width: "90", uid:"grid_column3", template:'#template2' }]
  }

  ngAfterViewInit(): void {
    this.columns.forEach((item : any)=>{
      if(item.template!=null){
              var column = this.grid.getColumnByUid(item.uid);
                if (column != null) {
                    switch (item.template) {
                        case "#template1":
                            column.template = this.temp1 as any;
                            break;
                        case "#template2":
                            column.template = this.temp2 as any;
                            break;
                        case "#template3":
                            column.template = this.temp3 as any;
                            break;
                    default:
                    }
                   
                }        
      }
    })  
  }

Sample: https://stackblitz.com/edit/angular-ninkrn-3ekqnu?file=default.component.ts



HJ Hariharan J V Syncfusion Team September 5, 2018 04:31 AM UTC

Hi Viktor 

Thanks for your update. We are happy to hear that your problem has been resolved.
  
  
Regards,   
Hariharan  



CR Casey Redis December 4, 2018 05:55 PM UTC

Hello,

I'm trying to do something similar.  I'm putting my column definitions in an array in my component ts file and then assign them to my grid.columns in ngAfterViewInit.  For one of the columns, I'm trying to setup a template with a button using the template below.  

#editButtonTemplate let-currentRow> (click)='testClick(currentRow)' type="button" class="btn btn-primary btn-sm">Edit

When I do it this way, the ng-template is rendered as html (i.e., it's not being processed).  If I define the template in the component html and use template: '#editButtonTemplate' in the column definition, I get no rows displayed at all (and no errors).  

The technique used earlier in the thread with looping through the definitions and getting the column and assigning the template there works but it's kind of clunky for my implementation and I'm wondering if there's something I'm missing due to my being new to the whole Angular world...


Thanks!


TS Thavasianand Sankaranarayanan Syncfusion Team December 5, 2018 12:48 PM UTC

Hi Casey, 

You can achieve your requirement by setting the template ViewChild instance to the column.template property. Please refer to the below code example. Please refer to the below code example and sample link. 

[component.ts] 
@Component({ 
        selector: 'control-content', 
  template: '<div class="control-section"> 
            <ejs-grid #grid [dataSource]='data' [allowPaging] = 'true' [columns]="gridColumns"> 
            </ejs-grid> 
 
          <ng-template let-data #template1> 
           <button ejs-button> Button </button>  
           </ng-template > 
         </div> ', 
  styleUrls: ['default.component.css'] 
}) 
export class DefaultComponent implements OnInit { 
  .  .  . 
 
  @ViewChild('template1') 
  public temp1: NgModel; 
    
  ngAfterViewInit(): void { 
this.gridColumns = [{ field: "EmployeeID", isPrimaryKey: "true", headerText: "Employee ID", width: "90" }, 
    { headerText: "Button", width: "90", template: this.temp1 }]; 
  } 
 
} 


Regards, 
Thavasianand S. 



SH Shannon Hill February 28, 2019 11:52 AM UTC

Hello,

I have also run into an issue with using dynamic columns and data loaded asynchronously in combination with frozen columns.  I am trying to freeze the first column in a grid and have been following this example: https://ej2.syncfusion.com/angular/demos/#/material/grid/async-pipe

Everything seems to work fine with loading the data and columns async.  However, the first column will only be displayed and remain frozen if I make all of the columns static, which is not possible since the data and columns are dynamic.  My grid setup looks like this:


            <ejs-grid  (dataStateChange)='dataStateChange($event)'  [dataSource]='data | async' height='400' [frozenRows]='0' [frozenColumns]='1' [allowSelection]='false' [enableHover]='false' [allowResizing]='true' [allowSorting]='true' [allowMultiSorting]='false' allowPaging='true'>
<ng-template ngFor let-column [ngForOf]="data.columns$ | async">
            <e-column [field]="column.field"
                      [headerText]="column.headerText"
                      [allowEditing]="column.allowEditing"
                      [template]="column.template" 
                      [width]="column.width">
            </e-column>
        </ng-template>
            </ejs-grid>   

Again, all of the data is displayed, but the first column is display with a 0px width and I cannot see it.  If I take off the [frozenColumns]='1' attribute, everything displays fine.

Please let me know if dynamic data and columns and a frozen column/header can be used together.

Thanks,

-Shannon


TS Thavasianand Sankaranarayanan Syncfusion Team March 6, 2019 09:18 AM UTC

Hi Shannon, 
 
Query: I have also run into an issue with using dynamic columns and data loaded asynchronously in combination with frozen columns.  all of the data is displayed, but the first column is display with a 0px width and I cannot see it.  If I take off the [frozenColumns]='1' attribute, everything displays fine. 
 
We have validated your query and checked the reported problem at our end. It works fine. Here, we have load grid data asynchronously with frozen columns and rows. We have prepared a sample based on your requirement. Please find the below code example and sample for your reference. 
 
[code example] 
... 
 
@Component({ 
  selector: 'app-root', 
  template: `<ejs-grid [dataSource]='data | async' [frozenRows]='2' [frozenColumns]='1' [allowPaging]='true' [pageSettings]='pageOptions' [allowSorting]='true' [allowGrouping]='true' (dataStateChange)= 'dataStateChange($event)' 
  <e-columns> 
<ng-template ngFor let-column [ngForOf]="columns"> 
        <e-column [field]="column.field"  
                  [headerText]="column.headerText" 
                  [allowEditing]="column.allowEditing" 
                  [isPrimaryKey]="column.isPrimaryKey != null ? column.isPrimaryKey : null" 
                  [width] = "column.width"  
                 > 
       </e-column> 
  </ng-template> 
</e-columns> 
</ejs-grid>`, 
providers: [OrdersService, PageService, FreezeService, SortService, GroupService] 
}) 
export class AppComponent implements OnInit { 
  public data: Observable<DataStateChangeEventArgs>; 
  public pageOptions: Object; 
  public state: DataStateChangeEventArgs; 
  constructor(public service: OrdersService) { 
    this.data = service; 
  } 
  public columns: any; 
   
  public dataStateChange(state: DataStateChangeEventArgs): void { 
    this.service.execute(state); 
  } 
 
  public ngOnInit(): void { 
    this.pageOptions = { pageSize: 5, pageCount: 4 }; 
    let state = { skip: 0, take: 20 }; 
    this.service.execute(state); 
    this.columns = ...] 
 } 
} 
 
 
 
Please get back to us if you need further assistance. 
 
Regards, 
Thavasianand S. 



DJ Deepak Jain April 13, 2020 07:38 AM UTC

How to get column definition like column.fieldname inside column template defined outside of ejsgrid


BS Balaji Sekar Syncfusion Team April 14, 2020 04:22 AM UTC

Hi Shannon, 
 
We have validated your query and we suspect that you want define column template in outside of grid wrapper. Since we have achieved your requirement using column.template property. In below code example, we have defined the dropdown component in ng-template and column template property refer that ng-template id and you can access the column properties in the outside of the template definition. Please refer below code example and sample for more information. 
[app.component.html] 
 
  <ejs-grid #grid [dataSource]='data' allowPaging='true' [pageSettings]='pageSettings' [editSettings]='editSettings' 
    [toolbar]='toolbar'> 
    <e-columns> 
      <e-column field='ShipCountry' headerText='Ship Country' width='150'    [template]="languageEditTemplate"> 
      </e-column> 
      <e-column field='OrderID' headerText='Order ID' width='120' textAlign='Right' isPrimaryKey='true' 
        [validationRules]='orderidrules'></e-column> 
      <e-column field='CustomerName' headerText='Customer Name' width='120' [validationRules]='customeridrules'> 
      </e-column> 
      <e-column field='Freight' headerText='Freight' width='120' format='C2' textAlign='Right' 
        editType='numericedit' [validationRules]='freightrules'></e-column> 
    </e-columns> 
  </ejs-grid> 
 
<ng-template #languageEditTemplate let-column> 
  <ejs-dropdownlist [width]='column.width' [dataSource]='languages' (change)='change($event)'  [value]='column.ShipCountry' 
    [fields]="{text:'ShipCountry', value: 'ShipCountry'}" [placeholder]='column.headerText'></ejs-dropdownlist> 
</ng-template>  
 
 

Please get back to us, if you need further assistance. 

Regards, 
Balaji Sekar 



KA Karthik January 10, 2024 02:09 PM UTC

Hello, 

here the languageEditTemplate  is valid only for one column as you are mentioning column specific data in the template 

if i want to use a single template for more than one columns how can it be done??



JC Joseph Christ Nithin Issack Syncfusion Team January 15, 2024 08:16 PM UTC

Hi Karthik,


   Based on your query, you want to use single template for the entire row, your requirement can be achieved by using the ‘rowTemplate’. We have already discussed the same in the below documentation and sample demo. Please refer the below for more details.


Documentation: https://ej2.syncfusion.com/angular/documentation/grid/row/row-template


Sample: https://ej2.syncfusion.com/angular/demos/#/bootstrap5/grid/row-template



KA Karthik replied to Joseph Christ Nithin Issack January 16, 2024 02:39 PM UTC

Hello Joseph,


Thank you for the response, 

is it possible to reuse templates only for some columns instead of entire row.

i want to utilize batch editing experience for other columns and i have multilevel stacked header generated by columns attribute in e-columnand these columns are  built dynamically in typescript.


I would be helpful if you can prepare a sammple for the above scenarios






JC Joseph Christ Nithin Issack Syncfusion Team January 22, 2024 05:57 AM UTC

Hi Karthik,


   Before proceeding to the solution, we would like you to share the below details.


  • Explain your requirement in detail, are you trying to show a template for some of the columns?
  • Complete grid rendering code.
  • Simple sample you are using.
  • Video demo of your requirement.
  • Syncfusion package version.

Loader.
Up arrow icon