Ag Grid Why cell renderer component updates after running 'onRowHeightChanged()' - ag-grid-angular

I use Ag Grid Angular to display the user list.
One of the cells is an email with a custom component. When the value is invalid it shows an error message. To display it properly I should expend the row. When I expend the row, an error despaired.
It looks like the cell renderer component updates every time after calling the onRowHeightChanged() method.
How to fix this issue?
<div class="app-users-list__action-bar">
<button
class="btn btn-primary ml-1"
(click)="changeGridMode()"
>{{gridModeBtnTitle}}</button>
</div>
<ng-container *ngIf="users$ | async"></ng-container>
<div
class="app-users-list__table"
infiniteScroll
[infiniteScrollContainer]="'.ag-body-viewport'"
[infiniteScrollDistance]="2"
[infiniteScrollThrottle]="0"
(scrolled)="onScroll()"
[scrollWindow]="false">
<ag-grid-angular
class="ag-theme-bootstrap user-list"
[suppressRowClickSelection]="true"
[gridOptions]="gridOptions"
[frameworkComponents]="frameworkComponents"
>
</ag-grid-angular>
</div>
<ngx-loading [show]="isLoading$ | async"></ngx-loading>
</section>
import { Component, OnInit } from '#angular/core';
import { NgModel } from '#angular/forms';
import { select, Store } from '#ngrx/store';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import * as fromShared from '../../../shared/models';
import * as userList from '../../actions/user-list.action';
import * as fromUserListSelectors from '../../selectors/user-list.selectors';
import * as gridComponents from '../../../shared/grid-components';
import { Organization } from '../../../organizations';
import { DEFAULT_INTERACTION_LIST_FILTER, SORT_DIRECTION } from '../../../shared/constants/filter.constant';
import { GridApi, GridOptions, GridReadyEvent, RowNode } from 'ag-grid-community';
import { Evaluator } from '../../../evaluators';
#Component({
selector: 'app-user-list',
templateUrl: './user-list.component.html',
styleUrls: ['./user-list.component.scss'],
})
export class UserListComponent implements OnInit {
public users$: Observable<fromShared.User[]>;
public isLoading$: Observable<boolean>;
public isEditMode = false;
public frameworkComponents = {...gridComponents};
public gridModeBtnTitle = this.setButtonTitle(this.isEditMode);
public columnDefs = [
{
headerName: 'First Name',
field: 'firstName',
minWidth: 200,
unSortIcon: true,
suppressMovable: true,
resizable: true,
autoHeight: true,
cellRenderer: 'GridTextCellComponent',
cellRendererParams: (params) => {
return {
value: params.data.firstName,
name: 'firstName',
aqaId: 'user-firstName',
};
}
},
{
headerName: 'Last Name',
field: 'lastName',
minWidth: 200,
unSortIcon: true,
suppressMovable: true,
autoHeight: true,
cellRenderer: 'GridTextCellComponent',
cellRendererParams: (params) => {
return {
value: params.data.lastName,
name: 'lastName',
aqaId: 'user-lastName',
};
}
},
{
headerName: 'Email',
field: 'email',
minWidth: 200,
unSortIcon: true,
suppressMovable: true,
autoHeight: true,
cellRenderer: 'GridEmailCellComponent',
cellRendererParams: (params) => {
return {
value: params.data.email,
name: 'email',
aqaId: 'user-email',
};
}
},
{
headerName: 'Sso Email Id',
field: 'SsoEmail',
minWidth: 300,
unSortIcon: true,
suppressMovable: true,
autoHeight: true,
cellRenderer: 'GridEmailCellComponent',
cellRendererParams: (params) => {
return {
editable: true,
editMode: this.isEditMode,
value: params.data.ssoEmail,
name: 'ssoEmail',
placeholder: 'Enter a SSO email',
aqaId: 'user-ssoEmail',
callback: this.updateHandler.bind(this, params.data, 'ssoEmail'),
statusChange: this.statusFieldChange.bind(this, params.node)
};
}
},
{
headerName: 'Org.Admin',
field: 'orgAdmin',
maxWidth: 200,
unSortIcon: false,
suppressMovable: true,
autoHeight: true,
cellRenderer: 'GridTextCellComponent',
cellRendererParams: (params) => {
return {
value: this.setUserRoleStatus(params.data.roles, fromShared.ERole.ORG_ADMIN),
name: 'orgAdmin',
aqaId: 'user-orgAdmin',
};
}
},
{
headerName: 'Eval.Admin',
field: 'evalAdmin',
maxWidth: 200,
unSortIcon: false,
suppressMovable: true,
autoHeight: true,
cellRenderer: 'GridTextCellComponent',
cellRendererParams: (params) => {
return {
value: this.setUserRoleStatus(params.data.roles, fromShared.ERole.EVALUATION_ADMIN),
name: 'evalAdmin',
aqaId: 'user-evalAdmin',
};
}
},
{
headerName: 'Evaluator',
field: 'evaluator',
maxWidth: 200,
unSortIcon: false,
suppressMovable: true,
autoHeight: true,
cellRenderer: 'GridTextCellComponent',
cellRendererParams: (params) => {
return {
value: this.setUserRoleStatus(params.data.roles, fromShared.ERole.CAN_VOTE),
name: 'evaluator',
aqaId: 'user-evaluator',
};
}
}
];
public gridOptions = <GridOptions>{
context: {componentParent: this},
columnDefs: this.columnDefs,
rowData: [],
enableColResize: true,
enableSorting: true,
headerHeight: 40,
rowHeight: 40,
animateRows: true,
suppressLoadingOverlay: false,
onSortChanged: () => {
let sortModel = this.gridOptions.api.getSortModel();
if (sortModel.length > 0) {
this.usersFilter.direction = SORT_DIRECTION[sortModel[0].sort.toUpperCase()];
this.usersFilter.orderBy = sortModel[0].colId;
} else {
this.usersFilter.orderBy = null;
this.usersFilter.direction = DEFAULT_INTERACTION_LIST_FILTER.direction;
}
this.usersFilter.page = 0;
this.gridOptions.api.setRowData([]);
this.store.dispatch(new userList.LoadUsersByFilterAction(this.usersFilter));
},
onRowDataChanged: (params) => {
},
getRowNodeId: (data: Evaluator) => {
return data.id;
},
noRowsOverlayComponent: 'NoRowsOverlayComponent',
noRowsOverlayComponentParams: {
noRowsMessageFunc: () => {
this.isLoading$.pipe(
map(loading => loading ? '' : 'You have no Users.')
);
}
},
rowClassRules: {
'text-transparent': (params) => params.data.unused,
},
defaultColDef: {
headerName: '',
field: '',
minWidth: 100,
unSortIcon: true,
suppressMovable: true,
resizable: true,
autoHeight: true,
},
onGridReady(event: GridReadyEvent) {
event.api.sizeColumnsToFit();
},
};
private usersFilter: fromShared.UserFilterList = {
limit: 20,
page: 0,
orderBy: 'firstName',
direction: SORT_DIRECTION.ASC
};
constructor(private store: Store<Organization>) {}
public ngOnInit(): void {
this.store.dispatch(new userList.LoadUsersByFilterAction(this.usersFilter));
this.isLoading$ = this.store.pipe(select(fromUserListSelectors.selectLoading));
this.users$ = this.store.pipe(select(fromUserListSelectors.selectUsers))
.pipe(
map(users => {
const api: GridApi = this.gridOptions.api;
if (api) {
api.setRowData(users);
}
return users;
})
);
}
public onScroll() {
this.usersFilter.page++;
this.store.dispatch(new userList.LoadUsersByFilterAction(this.usersFilter));
}
public changeGridMode(): void {
this.isEditMode = !this.isEditMode;
this.gridModeBtnTitle = this.setButtonTitle(this.isEditMode);
this.gridOptions.enableSorting = !this.isEditMode;
this.gridOptions.api.refreshCells({force: true});
}
private updateHandler(item: fromShared.User, field: string, newValue: any, controller: NgModel) {
if (controller && controller.invalid) {
return;
}
item[field] = newValue;
this.store.dispatch(new userList.UpdateUserAction(item));
}
private statusFieldChange(node: RowNode, status: string, isTouched: boolean) {
if (!isTouched) {
return;
}
if (status === 'INVALID') {
if (node.rowHeight < 60) {
this.updateRowSize(node, 60);
}
} else {
setTimeout(() => this.updateRowSize(node, null));
}
}
private updateRowSize(node: RowNode, height: number) {
node.setRowHeight(height);
this.gridOptions.api.onRowHeightChanged();
}
private setButtonTitle(isEditMode: boolean): string {
return isEditMode ? 'Done' : 'Edit';
}
private setUserRoleStatus(roles: fromShared.ERole[], type: fromShared.ERole): boolean {
return roles.includes(type);
}
}

Related

Angular: Cannot read property 'dataRows' of undefined

Can anyone help me with this issue.
Seems to be caused by the fact that the datatable is being build before the data is returned.
The data does load but and the table works as required but its annoying me that it still shows in the console.
Any help would be great, code below.
userlist.component.ts
export class UserslistComponent implements OnInit {
public dataTable: DataTable;
public dataTableData: any;
constructor( private usersService: UsersService) {}
ngOnInit() {
this.usersService.getUsers().subscribe(data => { this.buildDtOptions(data); });
}
buildDtOptions(tableData: any): void {
this.dataTable = {
headerRow: [ 'Firstname', 'Lastname', 'Email', 'Permission', 'Account Status' ],
footerRow: [ 'Firstname', 'Lastname', 'Email', 'Permission', 'Account Status' ],
dataRows: tableData
};
}
ngAfterViewInit() {
$('#datatable').DataTable({
'pagingType': 'full_numbers',
'lengthMenu': [
[10, 25, 50, -1],
[10, 25, 50, 'All']
],
responsive: true,
language: {
search: '_INPUT_',
searchPlaceholder: 'Search records',
},
});
const table = $('#datatable').DataTable();
}
users.service.html
export class UsersService {
localUrl = './assets/data/users.json';
usersUrl = 'https://my.api.mockaroo.com/users.json?key=58f30fc0';
constructor(private http: HttpClient) { }
getUsers() {
return this.http.get(this.localUrl)
.catch(this.errorHandler);
}
errorHandler(error: HttpErrorResponse) {
return Observable.throw(error.message || 'Server Error');
}

Sending data to API and retrieving them in to a grid

In my project I am using extjs in front-end. yii2 in backend. I created a form to retrieve selected data from database.
As you can see I have two date fields and a dropdown list. And I have a group of checkboxes. This is a screenshot of my database table.
I should select the data I want using checkboxes and get them from database between 'from' to 'to' dates. When I click RUN button those selected data should be loaded to the grid in the below. When I click download button, those selected data should be downloaded to a csv file. But when I click RUN button it sends same API call twice. And one API gets data correctly and other one sends and error saying 'Undefined index: from'. This is the code in my view.
recordData: {
date: null,
from: null,
to: null,
rb1: null,
rb1: null,
rb2: null,
rb3: null,
rb4: null,
time: null,
rb5: null,
rb6: null,
rb7: null,
weight: 0,
status: 1
}
},
initComponent: function () {
var me = this;
me.title = 'Reports',
me.store = Ext.create('store.Reports');
Ext.apply(me, {
items: [{
xtype: 'form',
border: false,
padding: 10,
bodyStyle: { "background-color": "#e4e4e4" },
width: '100%',
store: me.store,
defaults: {
selectOnFocus: true,
labelWidth: 125
},
items: [{
xtype: 'datefield',
fieldLabel: 'From',
padding: '10 0 0 40',
name: 'from',
format: 'Y-m-d',
labelWidth: 150,
value: me.recordData.from,
displayField: 'from',
typeAhead: true,
queryMode: 'local',
emptyText: 'Select...'
}, {
xtype: 'datefield',
fieldLabel: 'To',
padding: '20 0 0 40',
name: 'to',
format: 'Y-m-d',
labelWidth: 150,
value: me.recordData.to,
displayField: 'to',
typeAhead: true,
queryMode: 'local',
emptyText: 'Select...'
}, {
xtype: 'combobox',
fieldLabel: 'Report Type',
padding: '20 0 0 40',
name: 'type',
labelWidth: 150,
store: [
['Order Report', 'Order Report']
],
value: me.recordData.type,
displayField: 'type',
typeAhead: true,
queryMode: 'local',
emptyText: 'Select...'
}, {
width: '100%',
bodyStyle: { "background-color": "#e4e4e4" },
padding: '20 0 0 40',
bodyPadding: 10,
renderTo: Ext.getBody(),
items: [{
xtype: 'checkboxgroup',
fieldLabel: 'Customize Report',
width: 700,
labelWidth: 150,
columns: 3,
vertical: false,
items: [
{ boxLabel: 'Order ID', name: 'rb1', inputValue: '1', itemId: 'check1' },
{ boxLabel: 'Connection Number', name: 'rb2', inputValue: '2', itemId: 'check2' },
{ boxLabel: 'Status', name: 'rb3', inputValue: '3', itemId: 'check3' },
{ boxLabel: 'Action', name: 'rb4', inputValue: '4', itemId: 'check4' },
{ boxLabel: 'LOB', name: 'rb5', inputValue: '5', itemId: 'check5' },
{ boxLabel: 'Channel', name: 'rb6', inputValue: '6', itemId: 'check6' },
{ boxLabel: 'Company Name', name: 'rb7', inputValue: '7', itemId: 'check7' }
]
}]
}, {
buttons: [{
xtype: 'button',
text: 'RUN',
itemId: 'btnRun',
handler: function (button, event) {
//console.log("Working!", form);
var form = button.up('form');
//targetGridpanel = button.up();
//console.log("Working!", targetGridpanel);
//console.log("Working!", form);
if (form.isDirty()) {
var _vals = form.getValues();
if (!form.isValid()) {
console.log("Not Working!");
Ext.Msg.show({
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK,
title: me.action + ' Report',
msg: 'Fill mandatory fields'
});
} else {
//console.log(_vals);
me.store.saveRecord(_vals, function () {
});
//me.store.load();
if (me.down('#check1').isDirty()) {
me.down('#rb1').show(true);
}
if (me.down('#check2').isDirty()) {
me.down('#rb2').show(true);
}
if (me.down('#check3').isDirty()) {
me.down('#rb3').show(true);
}
if (me.down('#check4').isDirty()) {
me.down('#rb4').show(true);
}
if (me.down('#check5').isDirty()) {
me.down('#rb5').show(true);
me.down('#time').show(true);
}
if (me.down('#check6').isDirty()) {
me.down('#rb6').show(true);
}
if (me.down('#check7').isDirty()) {
me.down('#rb7').show(true);
}
}
} else {
console.log("Close!");
}
}
}]
}, {
xtype: 'gridpanel',
store: me.store,
flex: 1,
margin: '20 0 0 0',
//minHeight: 300,
height: 240,
viewConfig: {
stripeRows: true
},
bbar: {
xtype: 'pagingtoolbar',
store: me.store,
displayInfo: true,
plugins: Ext.create('Ext.ux.ProgressBarPager')
},
columns: [{
dataIndex: 'date',
//itemId:'date',
text: 'DATE',
flex: 1,
menuDisabled: false,
}, {
dataIndex: 'rb1',
itemId: 'rb1',
text: 'ORDER ID',
flex: 1,
menuDisabled: false,
hidden: true,
}, {
dataIndex: 'rb2',
itemId: 'rb2',
text: 'CONNECTION NUMBER',
menuDisabled: false,
hidden: true,
flex: 2
}, {
dataIndex: 'rb3',
itemId: 'rb3',
text: 'STATUS',
menuDisabled: false,
hidden: true,
flex: 1
}, {
dataIndex: 'rb5',
itemId: 'rb5',
text: 'LOB',
menuDisabled: false,
hidden: true,
flex: 1
}, {
dataIndex: 'rb4',
itemId: 'rb4',
text: 'ACTION',
menuDisabled: false,
hidden: true,
flex: 1
}, {
dataIndex: 'time',
itemId: 'time',
text: 'ACTION TIME',
menuDisabled: false,
hidden: true,
flex: 1
}, {
dataIndex: 'rb6',
itemId: 'rb6',
text: 'CHANNEL',
menuDisabled: false,
hidden: true,
flex: 1
}, {
dataIndex: 'rb7',
itemId: 'rb7',
text: 'COMPANY NAME',
menuDisabled: false,
hidden: true,
flex: 1.5
}]
}
, {
buttons: [{
xtype: 'button',
text: 'DOWNLOAD',
itemId: 'download',
//actionMethods: {'read': 'POST'},
handler: function (button, event) {
var self = button.up();
var form = self.up('form');
var vals = form.getValues();
//console.log('Download', vals);
if (vals.from && vals.to && vals.type && (vals.rb1 || vals.rb2 || vals.rb3 || vals.rb4 || vals.rb5 || vals.rb6 || vals.rb7)) {
if (button) {
Ext.Msg.show({
icon: Ext.MessageBox.QUESTION,
buttons: Ext.Msg.YESNO,
title: 'Download Report',
msg: 'Do you want to download the <strong>selected</strong> report file?',
fn: function (buttonId, text, opt) {
if ('yes' == buttonId) {
//console.log(buttonId);
var dummyFormId = 'py-form-' + (new Date()).getTime();
//console.log(dummyFormId);
var frm = document.createElement('form');
frm.id = dummyFormId;
frm.name = dummyFormId;
//console.log(frm);
frm.className = 'x-hidden';
document.body.appendChild(frm);
Ext.Ajax.request({
url: utils.createUrl('api', 'report-download'),
form: Ext.fly(dummyFormId),
isUpload: true,
params: {
from: vals.from,
to: vals.to,
type: vals.type,
rb1: vals.rb1,
rb2: vals.rb2,
rb3: vals.rb3,
rb4: vals.rb4,
rb5: vals.rb5,
rb6: vals.rb6,
rb7: vals.rb7
},
callback: function (opts, success, res) {
console.log('Hello');
//Ext.getBody().unmask();
//console.log(params);
try {
if (success) {
var response = Ext.decode(res.responseText);
if (!response.success) {
throw response.data;
}
} else {
throw response.data;
}
} catch (ex) {
Ext.Msg.show({
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK,
title: 'Download Report',
msg: 'No Data Found'
});
}
},
// fn: function () {
// console.log(arguments);
// }
});
}
}
});
}
} else {
Ext.Msg.show({
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK,
title: 'Download Report',
msg: 'Please fill the form first'
});
}
}
}
]
}
]
}],
});
me.callParent(arguments);
I send these data to a store file. This is store file code.
extend: 'Ext.data.Store',
model: 'model.Report',
storeId: 'reportStore',
autoLoad: false,
pageSize: Configs.grid.pageSize,
saveRecord: function(data,fnCallBack) {
var me = this;
//var data = this.data;
//autoLoad: true,
//console.log(data);
Ext.getBody().mask('Please wait...');
Ext.Ajax.request({
url: utils.createUrl('api', 'report-read'),
params: data,
callback: function(opts, success, res) {
Ext.getBody().unmask();
try {
if(success) {
var response = App.decodeHttpResp(res.responseText);
if(response.success) {
Ext.Msg.show({
icon: Ext.MessageBox.INFO,
buttons: Ext.Msg.OK,
title: 'Reports',
msg: 'Report saved successfully'
});
} else {
throw response.error;
}
me.load();
} else {
throw 'Unknown Reason';
}
} catch (ex) {
Ext.Msg.show({
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK,
title: 'Report',
msg: 'Failed to save data<br />' +
'Reason: ' + ex
});
}
}
});
}
This is my front-end model.
extend: 'Ext.data.Model',
fields: [
{ name: 'from', type: 'auto' },
{ name: 'to', type: 'auto' },
{ name: 'rb1', type: 'auto' },
{ name: 'rb2', type: 'auto' },
{ name: 'rb3', type: 'auto' },
{ name: 'rb4', type: 'auto' },
{ name: 'rb5', type: 'auto' },
{ name: 'time', type: 'auto' },
{ name: 'rb6', type: 'auto' },
{ name: 'rb7', type: 'auto' }
],
proxy: {
type: 'ajax',
noCache: false,
actionMethods: {'read': 'POST'},
api: {
read: utils.createUrl('api', 'report-read'),
//create: utils.createUrl('api', 'user-update'),
// update: utils.createUrl('api', 'user-update'),
// destroy: utils.createUrl('api', 'user-delete')
},
reader: {
type: 'json',
root: 'data'
},
listeners: {
exception: function(proxy, response, operation) {
App.showHttpError('Reports', response);
//console.log(this.fields);
}
}
}
Using these files I send data to controller. That's where my API is defined.
This is my controller function.
public function actionReportRead(){
$post = Yii::$app->request->post();
$time = 0;
$_vals = (new Order())->readReports(
#$post['start'],
#$post['limit'],
$post['from'],
$post['to'],
#$post['rb1'],
#$post['rb2'],
#$post['rb3'],
#$post['rb5'],
#$post['rb4'],
#$time,
#$post['rb6'],
#$post['rb7']
);
$this->setOutputData($_vals);
$this->setOutputStatus(true);
}
This is the model for that.
public function readReports($start, $limit,$from,$to, $rb1, $rb2, $rb3, $rb5, $rb4, $time, $rb6, $rb7 )
{
if (!$start) { $start = 0; };
if (!$limit) { $limit = Config::PAGE_SIZE; };
//$q = (new ActiveQuery(self::className()));
$q = self::find();
//$q->where(['between', 'submitted_time', $from, $to ]);
$q->alias('T')->andWhere(['BETWEEN', 'T.submitted_time', $from, $to ]);
$q->limit($limit);
$q->offset($start);
$q->orderBy(['T.order_id' => SORT_ASC]);
$data = [];
$action = null;
foreach ($q->all() as $_o) {
if($_o->status == 2){
$action = 'Data Entry Verified';
$time = $_o->timeDataEntry;
}else if($_o->status == 3){
$action = 'QC Accepted';
$time = $_o->timeQcPass;
}else if($_o->status == 4){
$action = 'Accepted';
$time = $_o->timeVerify;
}else if($_o->status == 1){
$action = 'Verification Pending';
$time = $_o->timeQcReject;
}else if($_o->status == 0){
$action = 'Rejected';
$time = $_o->timeQcReject;
}
$userlist='SELECT name FROM Company WHERE id = '.$_o->company_id;
$rsuserlist = Yii::$app->db->createCommand($userlist)->query();
$row = $rsuserlist->read();
$data[] = (object) array(
'date' =>$_o->submitted_time,
'rb1' =>$_o->order_id,
'rb2' =>$_o->conn,
'rb3' =>$_o->status,
'rb5' =>$_o->conn_type,
'rb4' =>$action,
'time' =>$time,
'rb6' =>$_o->channel,
'rb7' =>$row['name']
);
}
$json=Json::encode($data);
$this->logger->actLog($json);
return $data;
}
As I have found backend is fine. But I am not pretty sure. I new to extjs. So, I tried many ways but nothing worked. Data is not being loaded to grid and API sends me the error, I mentioned before. Please help me to solve this problem. What should I do more.
I found the answer and I am answering my own question.
Here, one API gets all the data correctly. Other one doesn't get 'from' and 'to' values. So I used following code.
me.store.getProxy().extraParams = {
from: vals.from,
to: vals.to
};
Using this I could send all the parameters to other API and eliminate that issue. Now data is fetched to the grid without a problem.

Export buttons in meteor

Template.users.rendered = function () {
Template.instance().subscribe('userList');
if (Session.get('apply_tablestyling')==1) {
console.log('in datatable');
$('#users').dataTable({
"paging": true,
"lengthChange": false,
"searching": true,
"ordering": true,
"info": true,
"autoWidth": false
});
}
}
I am using datatables-bootstrap-3, I need to add export buttons. Everything is working except showing the export buttons.
have you tried adding buttons to your initialization?
buttons: ['copy', 'csv', 'excel', 'pdf', 'print']
dom: 'Bfrtip',
buttons: [
{
text: 'Export to JSON',
action: function ( e, dt, node, config ) {
var data = dt.buttons.exportData();
$.fn.dataTable.fileSave(
new Blob( [ beautify(data , null, 2, 100) ] ),
'Families_'+ Date.now() +'.json'
);
}
}
,{
text: 'Export to CSV',
action: function ( e, dt, node, config ) {
var data = dt.buttons.exportData();
$.fn.dataTable.fileSave(
new Blob( [json2csv({ data: data.body, fields: null })]),
'Families_'+ Date.now() +'.csv'
);
}
}
]
then in both routes.js :
Router.route('/users', {
name: 'users',
action: function() {
var self = this;
$.getScript('https://cdn.datatables.net/buttons/1.2.4/js/dataTables.buttons.min.js', function(data, textStatus, jqxhr) {
if(jqxhr.status === 200) {
//self.render();
$.getScript('https://cdn.datatables.net/buttons/1.2.4/js/buttons.html5.min.js', function(data, textStatus, jqxhr) {
if(jqxhr.status === 200) {
self.render();
}
});
}
});
}
});

aurelia bridge kendo grid refresh

I'm trying to use Aurelia KendoUi Bridge in my application.
In my code I have a service which returns a new KendoDataSource :
export class KendoDataSource {
ToKendoDataSource(data: any, recordCount: number, pageSize: number, currentPage: number): any {
return {
transport: {
read: (p) => {
p.success({ data: data, recordCount: recordCount });
}
},
pageSize: pageSize,
serverPaging: true,
serverFiltering: true,
serverSorting: true,
schema: {
data: (result) => {
console.log('Transforming data to kendo datasource.');
return result.data;
},
total: (result) => {
return result.recordCount;
}
}
};
}
}
And this is my viewModel:
#inject(HttpService, KendoDataSource, EventAggregator)
export class GroupList {
grid: any;
gridVM: any;
datasource: any;
pageable: any;
subscriber: any;
paginationDetailsRequest: PaginationDetailsRequest;
test: string;
constructor(private httpService: HttpService, private kendoDataSource: KendoDataSource, private eventAggregator: EventAggregator) {
this.httpService = httpService;
this.kendoDataSource = kendoDataSource;
this.eventAggregator = eventAggregator;
this.paginationDetailsRequest = new PaginationDetailsRequest(4, 1);
this.GetGroups(this.paginationDetailsRequest);
this.datasource = {
transport: {
read: {
url: 'PersonGroup/GetGroups',
type: 'POST',
contentType: "application/json; charset=utf-8",
dataType: 'json'
},
parameterMap: function (data, type) {
if (type == "read") {
let paginationDetails = new PaginationDetailsRequest(data.pageSize, data.page);
if(data.sort && data.sort.length > 0){
paginationDetails.orderBy = data.sort[0].field;
paginationDetails.OrderDesc = (data.sort[0].dir == 'desc');
}
console.log(this.datasource);
return JSON.stringify(paginationDetails);
}
}
},
schema: {
data: "data.currentPageData",
total: "data.totalCount"
},
pageSize: 2,
serverPaging: true,
serverFiltering: true,
serverSorting: true
};
};
attached() {
this.subscriber = this.eventAggregator.subscribe('Search', response => {
this.search(response);
});
}
activate() {
this.pageable = {
refresh: true,
pageSizes: true,
buttonCount: 10
};
}
GetGroups(paginationDetails: PaginationDetailsRequest): void {
this.httpService.post('PersonGroup/GetGroups', paginationDetails)
.then(response => response.json())
.then(groups => {
console.log(groups);
if (groups.succeeded) {
this.datasource = this.kendoDataSource.ToKendoDataSource(groups.data.currentPageData, groups.totalCount, groups.pageSize, groups.currentPage);
this.grid.setDataSource(this.datasource); // initialize the grid
}
else {
//TODO: Show error messages on screen
console.log(groups.errors);
}
})
.catch(error => {
//TODO: Show error message on screen.
console.log(error);
});
}
search(searchDetails: Filter) {
console.log(searchDetails);
this.paginationDetailsRequest.filters.push(searchDetails);
console.log(this.paginationDetailsRequest);
this.GetGroups(this.paginationDetailsRequest);
}
detached() {
this.subscriber.dispose();
}
}
I understand that kendo does not have two-way data binding, But I'm trying to find a way to refresh the grid when I filter the data and the data source has changed.
Thanks.
I had this problem and found the solution by creating a new dataSource and assigning it to setDataSource, as follows... Note, getClients() is a search activated by a button click.
Here is the grid:
<ak-grid k-data-source.bind="datasource"
k-pageable.bind="{ input: true, numeric: false}"
k-filterable.bind="true"
k-sortable.bind="true"
k-scrollable.bind="true"
k-widget.bind="clientgrid"
k-selectable.bind="true">
<ak-col k-title="First Name" k-field="firstName" k-width="120px"></ak-col>
<ak-col k-title="Last Name" k-field="lastName" k-width="120px"></ak-col>
<ak-col k-title="Email Address" k-field="primaryEmail" k-width="230px"></ak-col>
</ak-grid>
And here is the code that updates the dataSource
public getClients()
{
console.log("ClientService.getClients");
this.clientService.getClients()
.then(result =>
{
this.clientList = result;
// the new datasource in the next line is displayed
// after the call to setDataSource(ds) below.
let ds: kendo.data.DataSource = new kendo.data.DataSource({
data: this.clientList,
schema: {
model: {
id: "id",
fields: {
firstName: { type: 'string' },
id: { type: 'number' },
lastName: { type: 'string' },
primaryEmail: { type: 'string' }
}
}
},
pageSize: 10
});
this.clientgrid.setDataSource(ds);
this.clientgrid.refresh();
})
.catch(err => console.log("Error returned from getClients " + err));
}
You don't really need to create a brand new datasource. To refresh the grid after changing the underlying data you can just replace the data element in the dataSource like so:
this.clientgrid.dataSource.data(this.datasource.data);

jqGrid inline edit not working

I am new to jqGrid and I tried to implement inline editing on the same. i could see no error but the rows are not edited and the grid will be in "saving" mode forever once i click submit button. please shed some light on where I am going wrong.
<script type="text/javascript">
$(document).ready(function () {
jQuery("#tabl").jqGrid({
url: "UserDetails.aspx/GetAllRecords",
datatype: "json",
mtype: 'POST',
ajaxGridOptions: { contentType: 'application/json; charset=utf-8' },
serializeGridData: function (postData) {
//alert(postData);
//alert(JSON.stringify(postData));
return JSON.stringify(postData);
},
jsonReader: {
root: function (obj) {
//alert(JSON.stringify(obj.d));
return typeof obj.d === "string" ? $.parseJSON(obj.d) : obj.d;
},
page: function (obj) { return 1; },
total: function (obj) { return 1; },
records: function (obj) { return obj.d.length; },
id: '0',
cell: '',
caption: "",
repeatitems: false
},
colNames: ['Category', 'ParamCode', 'ParamName', 'Description', 'DefaultValue', 'CompId', 'SiteId', 'SysTerminal', 'UserId', 'LastUpdateDt'],
colModel: [
{ name: 'Category' },
{ name: 'ParamCode' },
{ name: 'ParamName' },
{ name: 'Description' },
{ name: 'DefaultValue' },
{ name: 'QueryCompId', formatter: 'checkbox' },
{ name: 'QuerySiteId', formatter: 'checkbox' },
{ name: 'QuerySysTerminal', formatter: 'checkbox' },
{ name: 'QueryUserId', formatter: 'checkbox' },
{ name: 'LastUpdateDt', formatter: 'date' }
],
multiselect: false,
height: 'auto',
autoencode: true,
rowList: [10, 20, 30],
rowNum: 10,
pager: '#pager',
loadonce: true,
viewrecords: true,
gridview: true,
caption: "",
onCellSelect: function (rowid, iCol, cellcontent, e) {
pCode = cellcontent;
jQuery("#tablParamValues").jqGrid({
url: "UserDetail.aspx/GetParamValues",
editurl: "UserDetail.aspx/EditParamValue",
datatype: "json",
mtype: 'POST',
ajaxGridOptions: { contentType: 'application/json; charset=utf-8' },
serializeGridData: function (postData) {
//alert(JSON.stringify(postData));
return JSON.stringify({ paramcode: pCode });
},
jsonReader: {
root: function (obj) {
//alert(JSON.stringify(obj.d));
return typeof obj.d === "string" ? $.parseJSON(obj.d) : obj.d;
},
page: function (obj) { return 1; },
total: function (obj) { return 1; },
records: function (obj) { return obj.d.length; },
id: '0',
cell: '',
caption: "Manipulating Array Data",
repeatitems: false
},
colNames: ['ParamValueId', 'ParamCode', 'CompId', 'SiteId', 'SysTerminal', 'UserId', 'ParamValue'],
colModel: [
{ name: 'ParamValueId', index: 'ParamValueId' },
{ name: 'ParamCode' },
{ name: 'CompId' },
{ name: 'SiteId' },
{ name: 'SysTerminal' },
{ name: 'UserId' },
{ name: 'ParamValue', index: 'ParamValue', editable: true }
],
multiselect: false,
height: 'auto',
autoencode: true,
rowList: [10, 20, 30],
rowNum: 10,
pager: '#pager2',
loadonce: false,
viewrecords: true,
gridview: true,
caption: "",
ajaxRowOptions: {
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json"
},
serializeRowData: function (postdata) {
for (propertyName in data) {
if (data.hasOwnProperty(propertyName)) {
propertyValue = data[propertyName];
if ($.isFunction(propertyValue)) {
dataToSend[propertyName] = propertyValue();
} else {
dataToSend[propertyName] = propertyValue;
}
}
}
return JSON.stringify(dataToSend);
}
}).trigger("reloadGrid").inlineNav('#pager2', { edit: true, add: false, del: false, search: false },
{
ajaxEditOptions: { type :"POST",
contentType :"application/json; charset=utf-8",
dataType :"json"
},
serializeEditData: function createJSON(postdata) {
if (postdata.id === '_empty')
postdata.id = null;
return JSON.stringify(postdata)
},
closeAfterEdit: true
}).jqGrid('filterToolbar', { autoSearch: true });
//set width of grid
jQuery("#tablParamValues").jqGrid('setGridWidth', '700');
}
}).navGrid('#pager', { edit: false, add: false, del: false, search: false })
.jqGrid('filterToolbar', { autoSearch: true });
jQuery("#tabl").jqGrid('setGridWidth', '700');
});
</script>
<script type="text/javascript">
$(document).ready(function () {
jQuery("#tblData").jqGrid({
url: "CurrencySetting.aspx/GetAllRecords",
editurl:"CurrencySetting.aspx/EditRecord",
datatype: "json",
mtype: 'POST',
ajaxGridOptions: { contentType: 'application/json; charset=utf-8' },
serializeGridData: function (postData) {
//alert(postData);
//alert(JSON.stringify(postData));
return JSON.stringify(postData);
},
jsonReader: {
root: function (obj) {
//alert(JSON.stringify(obj.d));
return typeof obj.d === "string" ? $.parseJSON(obj.d) : obj.d;
},
page: function (obj) { return 1; },
total: function (obj) { return 1; },
records: function (obj) { return obj.d.length; },
id: '0',
cell: '',
caption: "",
repeatitems: false
},
colNames: ['Cd', 'Ds', 'Culture', 'DecimalPlaces', 'ShortDescription', 'Rate', 'Symbol', 'DateTimeFormat'],
colModel: [
{ name: 'Cd', formoptions: { rowpos: 1, colpos: 1} },
{ name: 'Ds', formoptions: { rowpos: 1, colpos: 2} },
{ name: 'Culture', formoptions: { rowpos: 1, colpos: 3}, },
{ name: 'DecimalPlaces', formoptions: { rowpos: 2, colpos: 1} },
{ name: 'ShortDescription', formoptions: { rowpos: 2, colpos: 2} },
{ name: 'CurrencyRate', formoptions: { rowpos: 2, colpos: 3} },
{ name: 'Symbol', formoptions: { rowpos: 3, colpos: 1} },
{ name: 'DateTimeFormat', formoptions: { rowpos: 3, colpos: 2} }
],
cmTemplate: { editable: true },
multiselect: false,
height: 'auto',
autoencode: true,
rowList: [10, 20, 30],
rowNum: 10,
pager: '#pager',
loadonce: true,
viewrecords: true,
gridview: true,
sortable: true,
caption: "",
loadComplete: function () {
// alert("OK");
},
loadError: function (jqXHR, textStatus, errorThrown) {
// alert(jqXHR.status + textStatus + errorThrown);
//alert(jqXHR.responseText);
}
}).navGrid('#pager', { edit: true, add: true, del: true, search: false },
{
ajaxEditOptions: { type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json"
},
serializeEditData: function createJSON(postdata) {
if (postdata.id === '_empty')
postdata.id = null;
return JSON.stringify({id:'AED',decPlace:'10'})
},
closeAfterEdit: true}
) .jqGrid('filterToolbar', { autoSearch: true });
//set width of grid
jQuery("#tblData").jqGrid('setGridWidth', '700');
$.extend($.jgrid.view, { width: 450, recreateForm: true });
$.extend($.jgrid.edit, { width: 450, recreateForm: true });
$.extend($.jqgrid.del, {width:300, recreateform:true});
});
$(window).on("resize", function () {
var newWidth = $("#tblData").closest(".ui-jqgrid").parent().width();
$("#tblData").jqGrid("setGridWidth", newWidth, true);
});
</script>