How to make ajax call on end of each block with infinite scrolling in ag-grid? - ajax

I am using ag-grid with angular 4.
I am using infinite scrolling as the rowModelType. But since my data is huge, we want to first call just 100 records in the first ajax call and when the scroll reaches the end, the next ajax call needs to be made with the next 100 records? How can i do this using ag-grid in angular 4.
This is my current code
table-component.ts
export class AssaysTableComponent implements OnInit{
//private rowData;
private gridApi;
private gridColumnApi;
private columnDefs;
private rowModelType;
private paginationPageSize;
private components;
private rowData: any[];
private cacheBlockSize;
private infiniteInitialRowCount;
allTableData : any[];
constructor(private http:HttpClient, private appServices:AppServices) {
this.columnDefs = [
{
headerName: "Date/Time",
field: "createdDate",
headerCheckboxSelection: true,
headerCheckboxSelectionFilteredOnly: true,
checkboxSelection: true,
width: 250,
cellRenderer: "loadingRenderer"
},
{headerName: 'Assay Name', field: 'assayName', width: 200},
{headerName: 'Samples', field: 'sampleCount', width: 100}
];
this.components = {
loadingRenderer: function(params) {
if (params.value !== undefined) {
return params.value;
} else {
return '<img src="../images/loading.gif">';
}
}
};
this.rowModelType = "infinite";
//this.paginationPageSize = 10;
this.cacheBlockSize = 10;
this.infiniteInitialRowCount = 1;
//this.rowData = this.appServices.assayData;
}
ngOnInit(){
}
onGridReady(params) {
this.gridApi = params.api;
this.gridColumnApi = params.columnApi;
//const allTableData:string[] = [];
//const apiCount = 0;
//apiCount++;
console.log("assayApiCall>>",this.appServices.assayApiCall);
const assaysObj = new Assays();
assaysObj.sortBy = 'CREATED_DATE';
assaysObj.sortOder = 'desc';
assaysObj.count = "50";
if(this.appServices.assayApiCall>0){
console.log("this.allTableData >> ",this.allTableData);
assaysObj.startEvalulationKey = {
}
}
this.appServices.downloadAssayFiles(assaysObj).subscribe(
(response) => {
if (response.length > 0) {
var dataSource = {
rowCount: null,
getRows: function (params) {
console.log("asking for " + params.startRow + " to " + params.endRow);
setTimeout(function () {
console.log("response>>",response);
if(this.allTableData == undefined){
this.allTableData = response;
}
else{
this.allTableData = this.allTableData.concat(response);
}
var rowsThisPage = response.slice(params.startRow, params.endRow);
var lastRow = -1;
if (response.length <= params.endRow) {
lastRow = response.length;
}
params.successCallback(rowsThisPage, lastRow);
}, 500);
}
}
params.api.setDatasource(dataSource);
this.appServices.setIsAssaysAvailable(true);
this.appServices.assayApiCall +=1;
}
else{
this.appServices.setIsAssaysAvailable(false)
}
}
)
}
}
I will need to call this.appServices.downloadAssayFiles(assaysObj) at the end of 100 rows again to get the next set of 100 rows.
Please suggest a method of doing this.
Edit 1:
private getRowData(startRow: number, endRow: number): Observable<any[]> {
var rowData =[];
const assaysObj = new Assays();
assaysObj.sortBy = 'CREATED_DATE';
assaysObj.sortOder = 'desc';
assaysObj.count = "10";
this.appServices.downloadAssayFiles(assaysObj).subscribe(
(response) => {
if (response.length > 0) {
console.log("response>>",response);
if(this.allTableData == undefined){
this.allTableData = response;
}
else{
rowData = response;
this.allTableData = this.allTableData.concat(response);
}
this.appServices.setIsAssaysAvailable(true);
}
else{
this.appServices.setIsAssaysAvailable(false)
}
console.log("rowdata>>",rowData);
});
return Observable.of(rowData);
}
onGridReady(params: any) {
console.log("onGridReady");
var dataSource = {
getRows: (params: IGetRowsParams) => {
this.info = "Getting datasource rows, start: " + params.startRow + ", end: " + params.endRow;
console.log(this.info);
this.getRowData(params.startRow, params.endRow)
.subscribe(data => params.successCallback(data));
}
};
params.api.setDatasource(dataSource);
}
Result 1 : The table is not loaded with the data. Also for some reason the service call this.appServices.downloadAssayFiles is being made thrice . Is there something wrong with my logic here.

There's an example of doing exactly this on the ag-grid site: https://www.ag-grid.com/javascript-grid-infinite-scrolling/.
How does your code currently act? It looks like you're modeling yours from the ag-grid docs page, but that you're getting all the data at once instead of getting only the chunks that you need.
Here's a stackblitz that I think does what you need. https://stackblitz.com/edit/ag-grid-infinite-scroll-example?file=src/app/app.component.ts
In general you want to make sure you have a service method that can retrieve just the correct chunk of your data. You seem to be setting the correct range of data to the grid in your code, but the issue is that you've already spent the effort of getting all of it.
Here's the relevant code from that stackblitz. getRowData is the service call that returns an observable of the records that the grid asks for. Then in your subscribe method for that observable, you supply that data to the grid.
private getRowData(startRow: number, endRow: number): Observable<any[]> {
// This is acting as a service call that will return just the
// data range that you're asking for. In your case, you'd probably
// call your http-based service which would also return an observable
// of your data.
var rowdata = [];
for (var i = startRow; i <= endRow; i++) {
rowdata.push({ one: "hello", two: "world", three: "Item " + i });
}
return Observable.of(rowdata);
}
onGridReady(params: any) {
console.log("onGridReady");
var datasource = {
getRows: (params: IGetRowsParams) => {
this.getRowData(params.startRow, params.endRow)
.subscribe(data => params.successCallback(data));
}
};
params.api.setDatasource(datasource);
}

Related

How to update CSV in each it blocks in Cypress

I want to update CSV file data (Ex: columns data like orderId, date etc...) in each it blocks of spec file. I have written code to update CSV inside Cypress.config.js file and calling cy.task from spec file. But everytime first it block updated CSV is passed to all other it blocks. Please let me know how can I achieve this
Under uploadOrders.cy.js
/// <reference types='Cypress'/>
import { ORDERS } from '../../selector/orders';
import BU from '../../fixtures/BU.json';
import Helper from '../../e2e/utils/Helper';
const helper = new Helper();
let getTodaysDate = helper.getTodaysDate(); // get today's date and store in getTodaysDate variable
let getTomorrowssDate = helper.getTomorrowsDate(); // get tomorrows's date and store in getTomorrowssDate variable
let getYesterdaysDate = helper.getYesterdaysDate(); // get tomorrows's date and store in getTomorrowssDate variable
describe('Upload Orders', () => {
// Before start executing all it blocks
before(() => {
cy.login(); //login code written in cypress commands.js file
cy.get(ORDERS.ORDER_ICON).click();
});
// Before start executing each it block
beforeEach(() => {
cy.writeFile('cypress/fixtures/finalCsvToBeUploaded.csv', ''); // clears the file before each it block executes
});
// First it block
it('Upload orders and check its successful', () => {
let csvData = {
orderId: 'OrderId_' + helper.getCurrentDateAndTimeInMiliseconds(),
orderDate: getTomorrowssDate,
homebaseExecutionDate: getTomorrowssDate,
customerExecutionDate: getTomorrowssDate,
}
cy.readFile('cypress/fixtures/referenceCsvFile.csv')
.then((data) => {
cy.task('csvToJson', data)
.then(finalJsonArray => {
cy.task('updateCsvData', { csvData, finalJsonArray })
.then(finalUpdatedJsonArray => {
cy.log("Update JSON array: " + finalUpdatedJsonArray[0]['Order ID']);
cy.task('finalCsv', finalUpdatedJsonArray);
});
})
})
cy.get(ORDERS.ORDER_UPLOAD).click();
cy.attachCsvFile('finalCsvToBeUploaded.csv');
cy.validateToastMsg('Orders uploaded successfully');
cy.log('Order is uploaded successfully via csv file and orderId is ');
});
// Second it block
it('Upload orders and check validation for past customer execution date', () => {
cy.wait(5000);
let csvData = {
orderId: 'OrderId_' + helper.getCurrentDateAndTimeInMiliseconds(),
orderDate: getTomorrowssDate,
homebaseExecutionDate: getYesterdaysDate,
customerExecutionDate: getYesterdaysDate,
}
cy.readFile('cypress/fixtures/finalCsvToBeUploaded.csv')
.then((data) => {
cy.task('csvToJson', data)
.then(finalJsonArray => {
cy.task('updateCsvData', { csvData, finalJsonArray })
.then(finalUpdatedJsonArray => {
cy.log("Update JSON array: " + finalUpdatedJsonArray);
cy.task('finalCsv', finalUpdatedJsonArray);
});
})
})
cy.get(ORDERS.ORDER_UPLOAD).click();
cy.attachCsvFile('finalCsvToBeUploaded.csv');
cy.validateToastMsg('Orders uploaded successfully');
cy.log('Order is uploaded successfully via csv file and orderId is');
});
// After exection of all it blocks
after(() => {
// clear cookies and localStorage
cy.clearCookies();
cy.clearLocalStorage();
});
});
Under cypress.config.js file
const { defineConfig } = require("cypress");
const converter = require('json-2-csv');
const csv = require('csv-parser');
const fs = require('fs');
const { default: Helper } = require("./cypress/e2e/utils/Helper");
const csvToJson1 = require('convert-csv-to-json');
const helper = require("csvtojson");
module.exports = defineConfig({
chromeWebSecurity: false,
watchFileForChanges: false,
defaultCommandTimeout: 10000,
pageLoadTimeout: 50000,
viewportWidth: 1280,
viewportHeight: 800,
video: false,
screenshotOnRunFailure: true,
"reporter": "mochawesome",
"reporterOptions": {
"charts": true,
"overwrite": false,
"html": false,
"json": true,
"timestamp": 'dd_mm_yy_HH_MM_ss',
"reportDir": "cypress/reports/mochawesome-report"
},
e2e: {
//To invoke test runner to pick files from the below path
specPattern: 'cypress/e2e/**/*.cy.js',
setupNodeEvents(on, config) {
// implement node event listeners here
// return require('./cypress/plugins/index.js')(on, config)
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
require('#cypress/code-coverage/task')(on, config)
//Start full screen
on('before:browser:launch', (browser = {}, launchOptions) => {
console.log(launchOptions.args);
if (browser.family === 'chromium' && browser.name !== 'electron') {
launchOptions.args.push('--start-fullscreen');
}
if (browser.name === 'electron') {
launchOptions.preferences.fullscreen = true;
}
return launchOptions;
});
//Convert CSV to JSON
on('task', {
csvToJson(data) {
var lines = data.split("\n");
var result = [];
var headers = lines[0].split(",");
for (var i = 1; i < (lines.length); i++) {
var obj = {};
var currentline = lines[i].split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/);
for (var j = 0; j < headers.length; j++) {
obj[headers[j]] = currentline[j].replace(/["']/g, "");
}
result.push(obj);
}
console.log(result);
return result;
}
})
// Write updated csv data into file
on('task', {
finalCsv(updatedJSON) {
converter.json2csvAsync(updatedJSON).then(updatedCsv => {
fs.writeFileSync('cypress/fixtures/finalCsvToBeUploaded.csv', updatedCsv);
}).catch(err => console.log(err));
return null;
}
});
//For log purpose; prints message in the console
on('task', {
log(message) {
console.log(message);
return null;
},
});
on('task', {
updateCsvData({ csvData, finalJsonArray }) {
let updatedJSON,orderIds = [];
for (let i = 0; i < (finalJsonArray.length); i++) {
if ('orderId' in csvData) {
orderIds[i] = csvData.orderId;
finalJsonArray[i]['Order ID'] = csvData.orderId;
}
else {
// orderIds[i] = 'OrderId_' + helper.getCurrentDateAndTimeInMiliseconds();
orderIds[i] = 'OrderId_' + Date.now();
finalJsonArray[i]['Order ID'] = orderIds[i];
}
if ('orderDate' in csvData) {
finalJsonArray[i]['Order Date'] = csvData.orderDate;
}
if ('homebaseExecutionDate' in csvData) {
finalJsonArray[i]['Homebase Execution Date'] = csvData.homebaseExecutionDate;
}
if ('customerExecutionDate' in csvData) {
finalJsonArray[i]['Customer Execution Date'] = csvData.customerExecutionDate;
}
}
updatedJSON = finalJsonArray;
return updatedJSON;
}
})
on('task', {
updateCsvFile(csvData) {
const finalJsonArray = [];
let updatedJSON, orderIds = [];
//readFile
fs.createReadStream('cypress/fixtures/referenceCsvFile.csv')
.pipe(csv())
.on('data', (data) => finalJsonArray.push(data))
.on('end', () => {
console.log(finalJsonArray); // CSV converted to json object
//Logic to update json objects; for loop to update csv columns in json array
for (let i = 0; i < (finalJsonArray.length); i++) {
if ('orderId' in csvData) {
orderIds[i] = csvData.orderId;
finalJsonArray[i]['Order ID'] = csvData.orderId;
}
else {
orderIds[i] = 'OrderId_' + this.getCurrentDateAndTimeInMiliseconds();
finalJsonArray[i]['Order ID'] = orderIds[i];
}
if ('orderDate' in csvData) {
finalJsonArray[i]['Order Date'] = csvData.orderDate;
}
if ('homebaseExecutionDate' in csvData) {
finalJsonArray[i]['Homebase Execution Date'] = csvData.homebaseExecutionDate;
}
if ('customerExecutionDate' in csvData) {
finalJsonArray[i]['Customer Execution Date'] = csvData.customerExecutionDate;
}
}
updatedJSON = finalJsonArray;
converter.json2csvAsync(updatedJSON).then(csvFile => {
fs.writeFileSync('cypress/fixtures/' + fileName, csvFile)
}).catch(err => console.log(err));
})
return orderIds;
}
})
return config;
}
}
});
In first it block, CSV file is updating but when controller comes to second it block - considering the same csv file which is updated in first it block but I need to update the csv file separately in second it block
Finally got the answer to my question:
csvData is an object where column data are stored
let csvData = {
orderDate: getTodaysDate,
homebaseExecutionDate: getTomorrowsDate,
customerExecutionDate: getTomorrowsDate
};
Common method to upload the file under commands.js.
Cypress.Commands.add('updateCsvFileData', (csvData, referenceFileName, updatedCsvFileName) => {
cy.readFile('cypress/fixtures/' + referenceFileName)
.then((data) => {
cy.wait(100).then(() => {
cy.task('csvToJson', data)
.then((finalJsonArray) => {
cy.wait(100).then(() => {
cy.task('updateCsvData', { csvData, finalJsonArray })
.then((finalUpdatedJsonArray) => {
cy.wait(100).then(() => {
cy.task('finalCsv', { finalUpdatedJsonArray, updatedCsvFileName })
});
})
})
})
})
})
})
node.js methods:
Convert CSV to JSON object
on('task', {
csvToJson(data) {
var lines = data.split("\n");
var result = [];
var headers = lines[0].split(",");
for (var i = 1; i < (lines.length); i++) {
var obj = {};
var currentline = lines[i].split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/);
for (var j = 0; j < headers.length; j++) {
obj[headers[j]] = currentline[j].replace(/["']/g, "");
}
result.push(obj);
}
return result;
}
})
Write updated csv data into CSV file
on('task', {
finalCsv({ finalUpdatedJsonArray, updatedCsvFileName }) {
converter.json2csvAsync(finalUpdatedJsonArray).then(updatedCsv => {
fs.writeFile('cypress/fixtures/' + updatedCsvFileName, updatedCsv);
}).catch(err => console.log(err));
return null;
}
});
Update required fields in CSV file
on('task', {
updateCsvData({ csvData, finalJsonArray }) {
let updatedJSON, orderIds = [];
for (let i = 0; i < (finalJsonArray.length); i++) {
if (csvData.hasOwnProperty('orderId')) {
orderIds[i] = csvData.orderId;
finalJsonArray[i]['Order ID'] = csvData.orderId;
}
else {
let orderIdRandomNum = Date.now() + "_" + Math.floor((Math.random() * 9999) + 1);
orderIds[i] = 'OrderId_' + orderIdRandomNum;
orders[i] = orderIds[i];
finalJsonArray[i]['Order ID'] = orderIds[i];
}
if ('orderDate' in csvData) {
finalJsonArray[i]['Order Date'] = csvData.orderDate;
}
if ('homebaseExecutionDate' in csvData) {
finalJsonArray[i]['Homebase Execution Date'] = csvData.homebaseExecutionDate;
}
if ('customerExecutionDate' in csvData) {
finalJsonArray[i]['Customer Execution Date'] = csvData.customerExecutionDate;
}
if ('teamId' in csvData) {
finalJsonArray[i]['Team ID'] = csvData.teamId;
}
}
updatedJSON = finalJsonArray;
return updatedJSON;
}
})

local storage value gets overwritten

I have initiated 2 localstorage variables within a typescript function. The second variable holding the value overwrites the first variable. How do I fix it?
OnSelectedOppPropStatsChange(TypeId: string, StrSelectedValue: string): void {
this.appService.SetLoadingShow(true);
var url = this.configs.DashboardDemandStatsURL();
var Input = {
"TypeId": TypeId,
"PS_No": this.user.PS_No,
"StrSelectedValue": StrSelectedValue
};
localStorage.setItem(this.strTypeSelected, StrSelectedValue);
localStorage.setItem(this.strTypeIdValue, TypeId);
this.appService.GetDataFromAPIPost(url, Input)
.then(response => {
this.appService.SetLoadingShow(false);
if (response.ResponseCode == this.configs.RetCodeFailure()) {
this.ShowDemandDetails = false;
this.errorMessage = response.ResponseData;
this.appService.ShowMessagePopup(this.configs.MESSAGETYPEERROR(), this.errorMessage);
}
else {
this.OpenDemandStatsDetails = JSON.parse(response.ResponseData.strDemandStatsOpen);
this.TeamFulfilledStatsDetails = JSON.parse(response.ResponseData.strDemandStatsTeam);
this.RPMFulfilledStatsDetails = JSON.parse(response.ResponseData.strDemandStatsRPM);
this.TotalRRCount = this.OpenDemandStatsDetails.length + this.TeamFulfilledStatsDetails.length + this.RPMFulfilledStatsDetails.length;
}
},
error => { this.errorMessage = <string>error; this.appService.SetLoadingShow(false) });
}
OnClickOpenRRNavigate(): void {
let SelectedItem = localStorage.getItem(this.strTypeSelected);
let SelectedType = localStorage.getItem(this.strTypeIdValue);
this.appService.SetLoadingShow(true);
var url = this.configs.DashboardDemandStatsTableURL();
var Input = {
"TypeId": SelectedType,
"PS_No": this.user.PS_No,
"StrSelectedValue": SelectedItem,
"strRRAllocationValue": this.StrOpenValue
};
this.appService.GetDataFromAPIPost(url, Input)
.then(response => {
this.appService.SetLoadingShow(false);
if (response.ResponseCode == this.configs.RetCodeFailure()) {
this.errorMessage = response.ResponseData;
this.appService.ShowMessagePopup(this.configs.MESSAGETYPEERROR(), this.errorMessage);
}
else {
this.DemandTableDetails = JSON.parse(response.ResponseData.strDemandStatsTable);
this.ShowDemandTable = true;
}
},
error => { this.errorMessage = <string>error; this.appService.SetLoadingShow(false) });
}
In the function OnClickOpenRRNavigate() , the SelectedType and SelectedItem holds the same value. How can I fix it?

How to working with data from client side using Observables

I am using the Grid of Kendo (Angular 2) for Add/Edit/Delete a Row in the grid:
http://www.telerik.com/kendo-angular-ui/components/grid/editing/
In the original Code, the data is obtained from a rest service like this:
private fetch(action: string = "", data?: Product): Observable<Product[]> {
return this.jsonp
.get(`http://demos.telerik.com/kendo-ui/service/Products/${action}? callback=JSONP_CALLBACK${this.serializeModels(data)}`)
.map(response => response.json());
}
But, I want to work with a array for add/edit/delete rows in memory. Next, I want to do click in the button submit and send the data (with all my changes) to the server.
My solution for this is like this:
https://gist.github.com/joedayz/9e318a47d06a7a8c2170017eb133a87e
Overview:
I declare an array:
private view: Array = [{ProductID: 1, ProductName: "pelotas", Discontinued: undefined, UnitsInStock: 80}];
and override the fetch method like this:
private fetch(action: string = "", data?: Product): Observable<Product[]> {
/*return this.jsonp
.get(`http://demos.telerik.com/kendo-ui/service/Products/${action}?callback=JSONP_CALLBACK${this.serializeModels(data)}`)
.map(response => response.json());*/
debugger;
if(action=="create"){
var product : Product = new Product(-1, data.ProductName, data.Discontinued, data.UnitsInStock);
this.view.push(product);
}else if(action=="update"){
var indice = this.view.indexOf(data);
if(indice>=0)
this.view[indice] = (JSON.parse(JSON.stringify(data)));
}else if(action=="destroy"){
var indice = this.view.indexOf(data);
if(indice>=0)
this.view.splice(indice, 1);
}
return Observable.of(this.view);
}
My Question is: Exists some way of communicate the create/update/delete of items in my array of a simple or reactive form to my grid?
As you are using in-memory array you do not need to use Observables. The Grid component is already bound to the array, thus it is just necessary to manipulate the data. For example:
export class AppComponent {
public dataItem: Product;
#ViewChild(GridEditFormComponent) protected editFormComponent: GridEditFormComponent;
private view: Array<Product> = [{ ProductID: 1, ProductName: "pelotas", Discontinued: undefined, UnitsInStock: 80 }];
public onEdit(dataItem: any): void {
this.dataItem = Object.assign({}, dataItem);
}
public onCancel(): void {
this.dataItem = undefined;
}
public addProduct(): void {
this.editFormComponent.addProduct();
}
public onSave(product: Product): void {
if (product.ProductID === undefined) {
this.createProduct(product);
} else {
this.saveProducts(product);
}
}
public onDelete(e: Product): void {
this.deleteProduct(e);
}
public saveProducts(data: Product): void {
var index = this.view.findIndex(x => x.ProductID === data.ProductID);
if (index !== -1) {
this.view = [
...this.view.slice(0, index),
data,
...this.view.slice(index + 1)
];
}
}
public createProduct(data: Product): void {
this.view = [...this.view, data];
}
public deleteProduct(data: Product): void {
this.view = this.view.filter(x => x.ProductID !== data.ProductID);
}
}

How to map column to complex object in SlickGrid

var data = [{"Id":40072,"Id2":40071,"SmDetails":{"Id1":40071,"Id2":40072}}]
I want to display SmDetails.Id1 in a column. How is this possible? I tried:
var columns = [{name:'Personnel',field:SmDetails.id1,id:'detailId'}];
Please help me
Please help me
**My latest code**
var data = [{"Id":40072,"Id2":40071,"allocationDetails":{"Id1":40071,"allocationDetails":{"accommodationId":4007}}}]
var grid;
var columns = [ {name:"Personnel",field:"allocationDetails",fieldIdx:'accommodationId', id:"accommodationId"}];
var options = {
enableCellNavigation: true,
enableColumnReorder: false,
dataItemColumnValueExtractor:
function getValue(item, column) {
var values = item[column.field];
if (column.fieldIdx !== undefined) {
return values && values[column.fieldIdx];
} else {
return values;
}}};
var gridData=$scope.Vo;//This return as json format
grid = new Slick.Grid("#testGrid",gridData, columns);
This is the code tried recently.
You'll need to provide a custom value extractor to tell the grid how to read your object.
var options = {
enableCellNavigation: true,
enableColumnReorder: false,
dataItemColumnValueExtractor:
// Get the item column value using a custom 'fieldIdx' column param
function getValue(item, column) {
var values = item[column.field];
if (column.fieldIdx !== undefined) {
return values && values[column.fieldIdx];
} else {
return values;
}
}
};
The column definitions would look like:
{
id: "field1",
name: "Id1",
field: "SmDetails",
fieldIdx: 'Id1'
}, {
id: "field2",
name: "Id2",
field: "SmDetails",
fieldIdx: 'Id2'
} //... etc
Check out this fiddle for a working example.
try this to convert your data into object of single length values ...
newData = {};
for(key in data[0]){
parentKey = key;
if(typeof(data[0][key]) == "object"){
childData = data[0][key];
for(key in childData){
childKey = key;
newKey = parentKey+childKey;
newData[newKey] = childData[childKey];
}
} else {
newData[key] = data[0][key];
}
}
This will convert your data object like this
newData = {Id: 40072, Id2: 40071, SmDetailsId1: 40071, SmDetailsId2: 40072};
Now use this newData to map your data items in grid
I find this works well for nested properties, eg:
var columns = [
{ id: "someId", name: "Col Name", field: "myRowData.myObj.myProp", width: 40}
..
];
var options {
...
dataItemColumnValueExtractor: function getItemColumnValue(item, column) {
var val = undefined;
try {
val = eval("item." + column.field);
} catch(e) {
// ignore
}
return val;
}
};

Ext js sorting custom column by contents

I have a grid in ext with some custom columns, and I want to be able to sort this column - I want to sort it by what is displayed inside of it, but really I just cannot figure out how to define a sorter for a column that will not be based on the dataIndex - I tried using a custom model, but I could not get that to work.
{
text: 'Parent',
dataIndex: 'Parent',
renderer: function(value, meta, record) {
var ret = record.raw.Parent;
if (ret) {
return ret.Name;
} else {
meta.tdCls = 'invisible';
return record.data.Name;
}
},
sortable: true
},
You should be able to override the doSort method of the column. Here's the gist of it. I also created a working fiddle (http://jsfiddle.net/cfarmerga/LG5uA/). The fiddle uses the string length of a field as the property to sort on, but of course you could apply your own custom sort logic.
var grid = Ext.create('Ext.grid.Panel',{
//...
columns: [
{ text: 'name', dataIndex: 'name', sortable: true },
{
text: 'Custom',
sortable : true,
dataIndex: 'customsort',
doSort: function(state) {
var ds = this.up('grid').getStore();
var field = this.getSortParam();
ds.sort({
property: field,
direction: state,
sorterFn: function(v1, v2){
v1 = v1.get(field);
v2 = v2.get(field);
return v1.length > v2.length ? 1 : (v1.length < v2.length ? -1 : 0);
}
});
}
}
]
//....
});
For Ext JS version 5, it looks like doSort was taken out, so I couldn't override that. Instead, I went the route of listening to the sortchange event, and from there, I used the Ext.data.Store.setSorters method. The code is a bit custom, and overly complex because of the data that I'm using, so keep that in mind (Fiddle here):
// grid class
initComponent: function() {
...
this.on('sortchange', this.onSortChange, this);
},
onSortChange: function(container, column, direction, eOpts) {
// check for dayColumnIndex
if (column && column.dayColumnIndex !== undefined) {
this.sortColumnByIndex(column.dayColumnIndex, direction);
}
},
sortColumnByIndex: function(columnIndex, direction) {
var store = this.getStore();
if (store) {
var sorterFn = function(rec1, rec2) {
var sortValue = false;
if (rec1 && rec2) {
var day1;
var daysStore1 = rec1.getDaysStore();
if (daysStore1) {
day1 = daysStore1.getAt(columnIndex);
}
var day2;
var daysStore2 = rec2.getDaysStore();
if (daysStore2) {
day2 = daysStore2.getAt(columnIndex);
}
if (day1 && day2) {
var val1 = day1.get('value');
var val2 = day2.get('value');
sortValue = val1 > val2 ? 1 : val1 === val2 ? 0 : -1;
}
}
return sortValue;
};
if (direction !== 'ASC') {
sorterFn = function(rec1, rec2) {
var sortValue = false;
if (rec1 && rec2) {
var day1;
var daysStore1 = rec1.getDaysStore();
if (daysStore1) {
day1 = daysStore1.getAt(columnIndex);
}
var day2;
var daysStore2 = rec2.getDaysStore();
if (daysStore2) {
day2 = daysStore2.getAt(columnIndex);
}
if (day1 && day2) {
var val1 = day1.get('value');
var val2 = day2.get('value');
sortValue = val1 < val2 ? 1 : val1 === val2 ? 0 : -1;
}
}
return sortValue;
};
}
store.setSorters([{
sorterFn: sorterFn
}]);
}
}
There is a convert method on the Ext.data.Model class that allows you to convert the data before it's being used. Then you can just specify this 'dataIndex' in your column and do a normal sort. The column will be sorted by that converted value. Here is the a sample model with just one field (Parent) and with it's corresponding conversion:
Ext.define('MyModel', {
extend: 'Ext.data.Model',
fields: [
{name: 'Parent', type: 'string', convert: sortParent},
// other fields...
],
sortParent: function(value, record) {
var ret = record.raw.Parent;
if (ret) {
return ret.Name;
} else {
meta.tdCls = 'invisible';
return record.data.Name;
}
}
});

Resources