Ag-grid is taking a lot of time to display with multiple Cell Renderer and Value Getter - ag-grid

I have to render ag-grid table in dialog box.
My grid has multi cellRenderer, valueGetter and cellRendererParams in columnDefs.
Instead of converting server data to rowData and using field to render, I have used valueGetter to fetch the value from the server data like
valueGetter: 'data.screen1.graph.visible'.
My ag-grid with 13 columns and 150 rows is taking noticeable time to render.
Is it because of valueGetter that my table is taking time to render?
Below is my sample data:
private createColumnDefs() {
this.columnDefs = [{
headerName: 'Header1',
cellRenderer: (params) => {
return params.data.serverObject1.function === 'input' ? 'I' : 'O';
},
minWidth: 50,
width: 70,
}, {
headerName: 'Header2',
field: 'serverObject1.name',
minWidth: 60,
width: 80,
}, {
headerName: 'Header3',
field: 'value',
cellRenderer: 'valueFieldRenderer',
minWidth: 100,
width: 250,
}, {
headerName: 'Header4',
cellRenderer: 'checkBoxRenderer',
valueGetter: 'data.serverObject1.graph.visible',
cellRendererParams(params) {
return {
disabledVal : params.data.localArray.length > 0 || params.data.attribute1 !== null
};
},
minWidth: 70,
width: 70,
}, {
headerName: 'Header5',
cellRenderer: 'checkBoxRenderer',
valueGetter: 'data.serverObject1.archive',
cellRendererParams(params) {
return {
disabledVal : params.data.serverObject1.function === 'input'
};
},
minWidth: 70,
width: 70,
}, {
headerName: 'Header6',
cellRenderer: 'checkBoxRenderer',
valueGetter: 'data.serverObject1.alarm',
cellRendererParams(params) {
return {
disabledVal : !((params.data.serverObject1.function === 'output') && (params.data.serverObject1.type === 'bool'))
};
},
minWidth: 70,
width: 70,
},
{
headerName: 'Header7',
cellRenderer: 'textBoxRenderer',
valueGetter: 'data.serverObject1.active',
minWidth: 150,
width: 150,
},
{
headerName: 'Header8',
cellRenderer: 'textBoxRenderer',
valueGetter: 'data.serverObject1.inactive',
minWidth: 150,
width: 150,
},
{
headerName: 'Header11',
cellRenderer: 'textBoxRenderer',
valueGetter: (params) => params.data.text1,
minWidth: 150,
width: 150,
cellStyle: (params) => {
return (this.diagram === 'XYZ' &&
!(params.data.serverObject1.function === 'output' || params.data.serverObject1.type === 'string'
|| params.data.serverObject1.type === 'int')) ? {display: 'block'} : {display: 'none'};
}}
];
}
cell renderer:
#Component({
selector: 'app-check-box',
template:
`
<input type="checkbox" [(ngModel)]="params.value" [id]="getID(params)" class="primary small"
(change)="onChange($event)">
<label [for]="getID(params)" class="text-hide">hidden</label>
`,
styleUrls: ['./test.component.css']
})
// tslint:disable-next-line:component-class-suffix
export class CheckBoxRenderer implements AfterViewInit, ICellRendererAngularComp {
private params: ICellRendererParams;
constructor(private readonly translateService: TranslateService) { }
agInit(params: ICellRendererParams): void {
this.params = params;
}
public onChange(event) {
}
refresh(params: any): boolean {
return false;
}
public getID(params): string {
return params.column.colId + params.rowIndex;
}
afterGuiAttached(params?: IAfterGuiAttachedParams): void {
}
ngAfterViewInit(): void {
}
translate(key: string, params?: any): string {
return this.translateService.instant(key, params);
}
}
Should I consider converting to rowData to decrease loading time?

Related

how to use multiple custom components in framework in ag-grid-angular?

I have created two custom components, i.e custom tooltip component and custom datepicker component. when im trying to declare in framework it is not working.
Its taking only datepicker custom component not tooltip component. If datepicker component is removed then its taking tooltip component Its considering only one custom component in frameworkComponent.
Please find the below code:
CustomTooltip :
import {Component, ViewEncapsulation} from '#angular/core';
import {ITooltipAngularComp} from "ag-grid-angular";
#Component({
selector: 'tooltip-component',
template: `
<div class="custom-tooltip" [style.background-color]="data.color">
<p>{{tooltipData}}</p>
</div>`,
styles: [
`
:host {
position: absolute;
width: 250px;
height: 60px;
border: 1px solid cornflowerblue;
overflow: hidden;
pointer-events: none;
transition: opacity 1s;
}
:host.ag-tooltip-hiding {
opacity: 0;
}
.custom-tooltip p {
margin: 5px;
white-space: nowrap;
}
`
],
styleUrls: ['./custom-tooltip.component.scss']
})
export class CustomTooltip implements ITooltipAngularComp {
params: any;
data: any;
tooltipData: any;
agInit(params): void {
console.log("params",params.value);
this.params = params;
this.tooltipData=params.value;
this.data = params.api.getRowNode(params.rowIndex).data;
this.data.color = this.params.color || 'white';
}
}
CustomDateComponent:
import {Component, ElementRef, ViewChild} from '#angular/core';
import flatpickr from 'flatpickr'
#Component({
selector: 'app-loading-overlay',
template: `
<div #flatpickrEl class="ag-input-text-wrapper custom-date-filter fa">
<input type='text' data-input />
<a class='input-button' title='clear' data-clear>
<i class='fa fa-times'></i>
</a>
<a class="input-button" title="toggle" data-toggle>
<i class="fa fa-calendar"></i>
</a>
</div>
`,
styles: [
`
.custom-date-filter a {
position: relative;
right: 34px;
color: rgba(0, 0, 0, 0.54);
cursor: pointer;
}
.custom-date-filter:after {
content: '\f073';
display: block;
font-weight: 400;
font-family: 'Font Awesome 5 Free';
position: relative;
right: 25px;
pointer-events: none;
color: rgba(0, 0, 0, 0.54);
}
`
]
})
export class CustomDateComponent {
#ViewChild("flatpickrEl", {read: ElementRef}) flatpickrEl: ElementRef;
private date: Date;
private params: any;
private picker: any;
agInit(params: any): void {
this.params = params;
}
ngAfterViewInit(): void {
// outputs `I am span`
this.picker = flatpickr(this.flatpickrEl.nativeElement, {
onChange: this.onDateChanged.bind(this),
wrap: true
});
this.picker.calendarContainer.classList.add('ag-custom-component-popup');
}
ngOnDestroy() {
console.log(`Destroying DateComponent`);
}
onDateChanged(selectedDates) {
this.date = selectedDates[0] || null;
this.params.onDateChanged();
}
getDate(): Date {
return this.date;
}
setDate(date: Date): void {
this.date = date || null;
this.picker.setDate(date);
}
}
Im trying to use both custom component in one grid i.e:
this.columnDefs = [
{
headerName: 'Request Number', field: 'request_no', sortable: true, filter: 'agNumberColumnFilter'
},
{
headerName: 'Request Date', field: 'created_at', sortable: true, width: 300,
filter: "agDateColumnFilter",
filterParams: {
comparator: function (filterLocalDateAtMidnight, cellValue) {
var dateAsString = cellValue;
var dateParts = dateAsString.split("/");
var cellDate = new Date(Number(dateParts[2]), Number(dateParts[1]) - 1, Number(dateParts[0]));
if (filterLocalDateAtMidnight.getTime() === cellDate.getTime()) {
return 0;
}
if (cellDate < filterLocalDateAtMidnight) {
return -1;
}
if (cellDate > filterLocalDateAtMidnight) {
return 1;
}
}
}
},
{ headerName: 'Requested By', field: 'user_name', sortable: true, filter: 'agTextColumnFilter', tooltipField: 'user_name' },
{
headerName: 'Client', field: 'borrower_name', sortable: true, filter: 'agTextColumnFilter',
tooltipField: 'borrower_name', tooltipComponentParams: { color: "#ececec" }, width: 200
},
{
headerName: 'Debtor', field: 'customer_name', sortable: true, filter: 'agTextColumnFilter',
cellStyle: { color: 'blue', cursor: 'pointer' }, tooltipField: 'customer_name', width: 200
},
{
headerName: 'Current Limit', field: 'current_limit', sortable: true, filter: 'agNumberColumnFilter',
cellStyle: { textAlign: 'right' },
cellRenderer: this.CurrencyCellRenderer
},
{
headerName: 'Requested Limit', field: 'requested_limit', sortable: true, filter: 'agNumberColumnFilter',
cellStyle: { textAlign: 'right' },
cellRenderer: this.CurrencyCellRenderer
},
{
headerName: 'Approved Limit', field: 'approved_limit', sortable: true, filter: 'agNumberColumnFilter',
cellStyle: { textAlign: 'right' },
cellRenderer: this.CurrencyCellRenderer
},
{ headerName: 'Status', field: 'status', sortable: true, filter: 'agTextColumnFilter', width: 120, },
{ headerName: 'Comment', field: 'comment', sortable: true, filter: 'agTextColumnFilter', tooltipField: 'comment', width: 200 },
{
headerName: "",
suppressMenu: true,
suppressSorting: false,
cellClass: 'action-class',
width: 120,
template:
`<i class="fa fa-pencil-square-o" aria-hidden="true" data-action-type="view" pTooltip="Edit Queue" tooltipPosition="top"></i>
<i class="fa fa-info-circle" aria-hidden="true" data-action-type="history" pTooltip="View Comment History" tooltipPosition="top"></i>`
}
];
this.defaultColDef = {
enableValue: true,
sortable: true,
tooltipComponent: "customTooltip",
resizable: true
};
this.frameworkComponents = {
customTooltip: CustomTooltip,
agDateInput: CustomDateComponent };
Seems it's a custom tooltip issue (somewhere inside ag-grid), will try to inform the team and describe the bug.
In your case, you can specify your component (CustomDateComponent) directly via cellEditorFramework rather than cellEditor, without internal declaration in frameworkComponents block.
{
headerName: "Date",
field: "date",
width: 190,
editable:true,
cellEditorFramework:CustomDateComponent
}
Just for info: your CustomDateComponent not yet ready to be used as cellEditor

Accessing state with Ag-grid

Probably not a Ag-Grid problem but I'm stuck on this one for some time.
Having a component in react like this :
export default class Recrutement extends React.Component {
constructor(props) {
super(props);
this.state = {
candidats: [], // We suppose here that values are filled
values: [] // We suppose here that values are filled
};
this.getContacts();
this.getValues();
}
columnDefs = [{
cellRenderer: function(params) {
return '<span><i class="material-icons"></i></span>';
},
suppressMovable: true,
width: 100,
colId: 1,
//width: (self.columnDefinitions.find(function (v) { return v.colId === 1 }) || {}).size || 50,
pinned: 'left',
suppressFilter: true
},
{
width: 100,
headerName: "Formation",
editable: true,
colId: 7,
suppressMovable: true,
//width : (self.columnDefinitions.find(function (v) { return v.colId === 7 }) || {}).size || null,
autoHeight: true,
cellEditor: 'agSelectCellEditor',
valueGetter: function(params) {
if (params.data.candidat.formationId === null)
return "";
return this.state.values.formations.find(function(val) {
return val.id === params.data.candidat.formationId;
}).name;
},
valueSetter: function(params) {
return selectValueSetter(this.state.values.formations, true, 'formationId', params);
},
cellEditorParams: function() {
return {
values: this.state.values.formations
.sort(function(a, b) {
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
})
.map(function(v) {
return v.name;
})
};
},
filter: "anyOfWordsFilter"
},
];
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
What I want is that valueGetter for example have access to this.state. However here, I just get everytime :
Uncaught TypeError: Cannot read property 'state' of undefined
I tried the bind system (or maybe I did it wrong, probably :D), the arrow one however none of them are working.
How can I access the state in this condition ? To use Ag-grid, I need my array to stay like this (function can change)
replace
valueSetter: function(params) {
return selectValueSetter(this.state.values.formations, true, 'formationId', params);
},
by
valueSetter: (params) => {
return selectValueSetter(this.state.values.formations, true, 'formationId', params);
},
and please ready this post and this one

"No Row To Show" message is coming after data binding from Services

The "No Row To Show" message is showing in grid, but the grid one row of data.
I have a demoComponent.ts and html file.
please refer my below code
demoComponent.ts
import { GridOptions } from "ag-grid/main";
import { Service } from '../Services/service';
#Component({
.
templateUrl: 'demoComponent.html',
.
})
#Injectable()
export class demoComponent implements OnInit {
GridOptions: GridOptions;
GridColumnDefs: any[];
GridData: any[];
data1 : any[]
constructor(private Service: Servicee) {
}
ngOnInit() {
this.GridOptions = <GridOptions>{
enableFilter: false,
rowSelection: 'multiple',
enableSorting: true,
enableColResize: true,
singleClickEdit: true,
animateRows: true,
headerHeight: 50,
rowClass: 'rowClass'
};
Observable.forkJoin(
this.Service.methed1(this.id),
this.Service.methed1(this.id),
this.Service.methed1(this.id),
this.Service.methed1()
).subscribe(response => {
this.data1 = <any>response[0];
this.data2 = <any>response[1];
this.data3 = <any>response[2];
this.data4 = <any>response[3];
this.GridBind()
});
}
GridBind()
{
this.GridColumnDefs = [
{ headerName: "", field: "id", hide: true },
{ headerName: "Column1", field: "Column1", width: 70, editable: true, tooltipField: "release", headerTooltip: "Release" },
{ headerName: "Column2", field: "Column2", width: 80, editable: true, tooltipField: "Column2", headerTooltip: "Column2",
//cellEditorFramework: EstimatingSourceComponent
cellEditorFramework: EstimatingSourceComponent,
cellEditorParams: {
dropDownValue: this.data1,
}
},
{ headerName: "Column3", field: "Column3", width: 70, editable: true },
{ headerName: "Column4", field: "Column4", width: 70, editable: true },
];
this.GridData = [
{
id: 1, Column1: this.data1.value1, Column2: this.data1.value2, Column3: this.data1.value3, Column4: this.data1.value4
}
];
}
}
Then the demoComponent.html
<ag-grid-angular style="width: 100%; height: 350px;"
id="grid1"
class="ag-fresh"
[rowData]="GridData"
[columnDefs]="GridColumnDefs"
[gridOptions]="GridOptions">
</ag-grid-angular>
on rendering the one row is binded with the grid. but "No Row To Show" is showing.
Please correct my implementation , if it is wrong.
thanks in advance

how to add conditional template on ag-grid

can I do a conditional template on the first column below?
for example:
If my row has score property and I want to hide the input when my score is above 70?
let columns = [
{ width: 30, suppressSorting: true, suppressMenu: true, template: '<input type="checkbox">' },
{ headerName: "Score", filter: 'number', valueGetter: (params : any) =>
params.data.traces ? (<Alert> params.data.traces[0]).severity : params.data.severity, width:70},
{ headerName: "Behaviour tags" },
{ headerName: "Host", field: "host_name" },
{ headerName: "Group Id", cellRenderer: 'group', width:140 },
{ headerName: "Comments",width:290 }
];
Use cellRenderer property in your column object
let columns = [{ width: 30, suppressSorting: true, suppressMenu: true,
cellRenderer: function (params) {
var display = 'block';
if (params.data.score > 70) {
display = 'none';
}
var html = '<input type="checkbox" style="display: ' + display + '">';
return html;
}
}]
In params.data you have all row data

Extjs4: editable rowbody

in my first ExtJs4 project i use a editable grid with the feature rowbody to have a big textfield displayed under each row.
I want it to be editable on a dblclick. I succeeded in doing so by replacing the innerHTML of the rowbody by a textarea but the special keys don't do what they are supposed to do (move the cursor). If a use the textarea in a normal field i don't have this problem. Same problem in IE7 and FF4
gridInfo = Ext.create('Ext.ux.LiveSearchGridPanel', {
id: 'gridInfo',
height: '100%',
width: '100%',
store: storeInfo,
columnLines: true,
selType: 'cellmodel',
columns: [
{text: "Titel", flex: 1, dataIndex: 'titel', field: {xtype: 'textfield'}},
{text: "Tags", id: "tags", flex: 1, dataIndex: 'tags', field: {xtype: 'textfield'}},
{text: "Hits", dataIndex: 'hits'},
{text: "Last Updated", renderer: Ext.util.Format.dateRenderer('d/m/Y'), dataIndex: 'lastChange'}
],
plugins: [
Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1
})
],
features: [
{
ftype: 'rowbody',
getAdditionalData: function (data, idx, record, orig) {
var headerCt = this.view.headerCt,
colspan = headerCt.getColumnCount();
return {
rowBody: data.desc, //the big textfieldvalue, can't use a textarea here 8<
rowBodyCls: this.rowBodyCls,
rowBodyColspan: colspan
};
}
},
{ftype: 'rowwrap'}
]
});
me.on('rowbodydblclick', function (gridView, el, event, o) {
//...
rb = td.down('.x-grid-rowbody').dom;
var value = rb.innerText ? rb.innerText : rb.textContent;
rb.innerHTML = '';
Ext.create('Ext.form.field.TextArea', {
id: 'textarea1',
value: value,
renderTo: rb,
border: false,
enterIsSpecial: true,
enableKeyEvents: true,
disableKeyFilter: true,
listeners: {
'blur': function (el, o) {
rb.innerHTML = el.value;
},
'specialkey': function (field, e) {
console.log(e.keyCode); //captured but nothing happens
}
}
}).show();
//...
});
damn, can't publish my own solution, looks like somebody else has to answer, anyway, here is the function that works
function editDesc(me, gridView, el, event, o) {
var width = Ext.fly(el).up('table').getWidth();
var rb = event.target;
var value = rb.innerText ? rb.innerText : rb.textContent;
rb.innerHTML = '';
var txt = Ext.create('Ext.form.field.TextArea', {
value: value,
renderTo: rb,
border: false,
width: width,
height: 300,
enterIsSpecial: true,
disableKeyFilter: true,
listeners: {
'blur': function (el, o) {
var value = el.value.replace('\n', '<br>')
rb.innerHTML = value;
},
'specialkey': function (field, e) {
e.stopPropagation();
}
}
});
var txtTextarea = Ext.fly(rb).down('textarea');
txtTextarea.dom.style.color = 'blue';
txtTextarea.dom.style.fontSize = '11px';
}
Hi Molecule Man, as an alternative to the approach above i tried the Ext.Editor.
It works but i want it inline but when i render it to the rowbody, the field blanks and i have no editor, any ideas ?
gridInfo = Ext.create('Ext.grid.Panel', {
id: 'gridInfo',
height: '100%',
width: '100%',
store: storeInfo,
columnLines: true,
selType: 'cellmodel',
viewConfig: {stripeRows: false, trackOver: true},
columns: [
{text: "Titel", flex: 1, dataIndex: 'titel', field: {xtype: 'textfield'}},
//...
{
text: "Last Updated", renderer: Ext.util.Format.dateRenderer('d/m/Y'), dataIndex: 'lastChange'
}
],
plugins: [
Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1
})
],
features: [
{
ftype: 'rowbody',
getAdditionalData: function (data, idx, record, orig) {
var headerCt = this.view.headerCt,
colspan = headerCt.getColumnCount();
return {
rowBody: data.desc,
rowBodyCls: this.rowBodyCls,
rowBodyColspan: colspan
};
}
}
],
listeners: {
rowbodyclick: function (gridView, el, event) { //werkt
editDesc(this, gridView, el, event);
}
}
})
;
function editDesc(me, gridView, el, event, o) {
var rb = event.target;
me.txt = new Ext.Editor({
field: {xtype: 'textarea'},
updateEl: true,
cancelOnEsc: true,
floating: true,
renderTo: rb //when i do this, the field becomes empty and i don't get the editor
});
me.txt.startEdit(el);
}
This is just to set the question answered, see solution above