Export buttons are only exporting column headers not the data.
I am using datatables in angular5, with serverside processing.
Previously i was using clint-side processing with all data and it was working fine, later i moved for server-side processing with below code.
this.table = $('#my-data-table').DataTable({
serverSide: true,
filter: false,
sort: true,
orderCellsTop: true,
columnDefs: [{
targets: [-1, 0, 1, 2, 4, 10, 12],
orderable: false,
}],
ajax: (dataTablesParameters: any, callback) => {
this.draw += 1;
let info = $('#early-detection-data-table').DataTable().page.info();
if (info.length > 10) {
if (info.page > 0) {
this.offset = ((info.length) * (info.page));
} else {
this.offset = (((info.page + 1) * 10) - 10);
}
} else {
this.offset = (((info.page + 1) * 10) - 10);
}
this.countNumber = (this.offset + 1);
let limit = info.length;
this.patientService.getRecentTransmission(limit.toString(), this.offset.toString(), this.searchCriterian).subscribe(
(data: any) => {
this.earlyDetections = data;
let total: number;
$('.showbox').css('display', 'none');
//this.setVisiblility();
if (data[0] && data[0].recordsTotal > 0) {
total = data[0].recordsTotal;
} else {
total = 0;
}
callback({
recordsTotal: total,
recordsFiltered: total,
data: [],//JSON.stringify(data),
});
console.log(data)
if (data && data.length != 0) {
$('td.dataTables_empty').hide();
} else {
$('td.dataTables_empty').show();
}
});
}, loadingIndicator: true,
dom: 'lBfrtip',
// "order": [[ 7, "desc" ]],
buttons: {
buttons: [
{ extend: 'print', className: 'btn btn-primary btn-round' },
{ extend: 'excel', className: 'btn btn-primary btn-round' },
{ extend: 'pdf', className: 'btn btn-primary btn-round' }
]
},
});
Please help me and let me know if anything else required from my side.
Last week I had the same issue.
I spent almost 2 days to solve it, the solution that I come with was:
Go to the export buttons library and find where the data was built before exporting to file.
You will find there:
var = data;
data = {
body: [] //actual data of the table
footer: [] //footer of the table if exists
header: [] //header of the table
}
In my case here is the data object:
body: []
footer: null
header: (4) ["#", "Serial Number", "Filter Type", ""]
__proto__: Object
So as you can see the body is empty and that is why you get only headers are shown.
What I did is building the body from the response of the server call and store it on the local storage(so I can access it from everywhere).
Here is the code sample:
const TableData = [...resp.controllers];
this.utilService.getDataArrayForExport(TableData, 'Controllers');
getDataArrayForExport(TableData, TableType) {
const DataArray = [];
let formatedObject = {};
TableData.forEach(function (object, i) {
switch (TableType) {
case "Clients":
formatedObject = {
'email': object.email,
'name': object.name,
'jobDescription': object.jobDescription,
'company': object.company,
'countries': object.countries
};
break;
case "Controllers":
formatedObject = {
'controllerSN': object.controllerSN,
'filterType': object.filterType
};
break;
case "Flushes":
const pipeFlush = new DatePipe('en-US');
const timeFlush = pipeFlush.transform(object.time, 'short');
formatedObject = {
'controllerSN': object.controllerId,
'description': object.description,
'time': timeFlush,
'dpBefore': object.dpBefore,
'dpAfter': object.dpAfter
};
break;
case "Alerts":
const pipe = new DatePipe('en-US');
const time = pipe.transform(object.time, 'short');
formatedObject = {
'controllerSN': object.controllerId,
'description': object.description,
'time': time,
};
break;
case "Admins":
formatedObject = {
'email': object.email,
'jobDescription': object.jobDescription,
'company': object.company,
'countries': object.countries
};
break;
}
const array = [];
array.push((i + 1).toString());
$.each(formatedObject, function (key, value) {
array.push(value);
});
DataArray.push(array);
});
localStorage.setItem('export', JSON.stringify(DataArray));
console.dir(DataArray);
}
Now add a small logic on export if data.body is an empty array:
var data = dt.buttons.exportData( config.exportOptions );
var ddd = JSON.parse(localStorage.getItem("export"));
if(data.body.length === 0){
data.body = ddd;
}
Now the data object is populated with the data:
body: (10) [Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3)]
footer: null
header: (4) ["#", "Serial Number", "Filter Type", ""]
__proto__: Object
So now all set, and you will get all the data export correctly.
I hope my post will help you.
If you have some questions you are welcome to ask :)
Related
I want to achieve Tree Mapping from Gojs in React typescript.
I found one example of Go js in react but it's still confusing for me to make Tree Mapping in react. Any help would be appreciated to start with Tree Mapping in React TS.
Here is my repo: https://github.com/AdarshPawar29/map-tree-gojs
I manage to create the tree mapping but still some work to be done. I commented on some of the not working functions. I'm also looking for the functional component.
import React, { useState } from "react";
import * as go from "gojs";
import { ReactDiagram } from "gojs-react";
import "./App.css";
class TreeNode extends go.Node {
constructor() {
super();
this.treeExpandedChanged = (node) => {
if (node.containingGroup !== null) {
node.containingGroup
.findExternalLinksConnected()
.each((l) => l.invalidateRoute());
}
};
}
// findVisibleNode() {
// // redirect links to lowest visible "ancestor" in the tree
// var n = this;
// while (n !== null && !n.isVisible()) {
// n = n.findTreeParentNode();
// }
// return n;
// }
}
// end TreeNode
// Control how Mapping links are routed:
// - "Normal": normal routing with fixed fromEndSegmentLength & toEndSegmentLength
// - "ToGroup": so that the link routes stop at the edge of the group,
// rather than going all the way to the connected nodes
// - "ToNode": so that they go all the way to the connected nodes
// but only bend at the edge of the group
var ROUTINGSTYLE = "Normal";
// If you want the regular routing where the Link.[from/to]EndSegmentLength controls
// the length of the horizontal segment adjacent to the port, don't use this class.
// Replace MappingLink with a go.Link in the "Mapping" link template.
class MappingLink extends go.Link {
getLinkPoint(
node: go.Node | null | any,
port: go.GraphObject,
spot: go.Spot,
from: boolean,
ortho: boolean,
othernode: go.Node | null | any,
otherport: go.GraphObject
) {
if (ROUTINGSTYLE !== "ToGroup") {
return super.getLinkPoint(
node,
port,
spot,
from,
ortho,
othernode,
otherport
);
} else {
var r = port.getDocumentBounds();
var group = node.containingGroup;
var b = group !== null ? group.actualBounds : node.actualBounds;
var op = othernode.getDocumentPoint(go.Spot.Center);
var x = op.x > r.centerX ? b.right : b.left;
return new go.Point(x, r.centerY);
}
}
computePoints() {
var result = super.computePoints();
if (result && ROUTINGSTYLE === "ToNode") {
var fn = this.fromNode;
var tn = this.toNode;
if (fn && tn) {
var fg = fn.containingGroup;
var fb = fg ? fg.actualBounds : fn.actualBounds;
var fpt = this.getPoint(0);
var tg = tn.containingGroup;
var tb = tg ? tg.actualBounds : tn.actualBounds;
var tpt = this.getPoint(this.pointsCount - 1);
this.setPoint(
1,
new go.Point(fpt.x < tpt.x ? fb.right : fb.left, fpt.y)
);
this.setPoint(
this.pointsCount - 2,
new go.Point(fpt.x < tpt.x ? tb.left : tb.right, tpt.y)
);
}
}
return result;
}
}
// end MappingLink
// Create some random trees in each group
var nodeDataArray = [
{ isGroup: true, key: -1, text: "Left Side", xy: "0 0", width: 150 },
{ isGroup: true, key: -2, text: "Right Side", xy: "300 0", width: 150 },
];
var linkDataArray = [
{ from: 6, to: 1012, category: "Mapping" },
{ from: 4, to: 1006, category: "Mapping" },
{ from: 9, to: 1004, category: "Mapping" },
{ from: 1, to: 1009, category: "Mapping" },
{ from: 14, to: 1010, category: "Mapping" },
];
export default function App() {
// All links must go from a node inside the "Left Side" Group to a node inside the "Right Side" Group.
function checkLink(
fn: {
[x: string]: any;
containingGroup: { data: { key: number } } | null;
},
fp: any,
tn: {
[x: string]: any;
containingGroup: { data: { key: number } } | null;
},
tp: any,
link: any
) {
// make sure the nodes are inside different Groups
if (fn.containingGroup === null || fn.containingGroup.data.key !== -1)
return false;
if (tn.containingGroup === null || tn.containingGroup.data.key !== -2)
return false;
//// optional limit to a single mapping link per node
if (
fn.linksConnected.any(
(l: { category: string }) => l.category === "Mapping"
)
)
return false;
if (
tn.linksConnected.any(
(l: { category: string }) => l.category === "Mapping"
)
)
return false;
return true;
}
function initDiagram() {
const $ = go.GraphObject.make;
// set your license key here before creating the diagram: go.Diagram.licenseKey = "...";
const diagram = $(go.Diagram, {
"undoManager.isEnabled": true, // must be set to allow for model change listening
"undoManager.maxHistoryLength": 0, // uncomment disable undo/redo functionality
"clickCreatingTool.archetypeNodeData": {
text: "new node",
color: "lightblue",
},
"commandHandler.copiesTree": true,
"commandHandler.deletesTree": true,
// newly drawn links always map a node in one tree to a node in another tree
"linkingTool.archetypeLinkData": { category: "Mapping" },
"linkingTool.linkValidation": checkLink,
"relinkingTool.linkValidation": checkLink,
model: new go.GraphLinksModel({
linkKeyProperty: "key", // IMPORTANT! must be defined for merges and data sync when using GraphLinksModel
}),
});
// // define a simple Node template
// diagram.nodeTemplate = $(
// go.Node,
// "Auto", // the Shape will go around the TextBlock
// new go.Binding("location", "loc", go.Point.parse).makeTwoWay(
// go.Point.stringify
// ),
// $(
// go.Shape,
// "RoundedRectangle",
// { name: "SHAPE", fill: "white", strokeWidth: 0 },
// // Shape.fill is bound to Node.data.color
// new go.Binding("fill", "color")
// ),
// $(
// go.TextBlock,
// { margin: 8, editable: true }, // some room around the text
// new go.Binding("text").makeTwoWay()
// )
// );
diagram.nodeTemplate = $(
TreeNode,
{ movable: false, copyable: false, deletable: false }, // user cannot move an individual node
// no Adornment: instead change panel background color by binding to Node.isSelected
{
selectionAdorned: false,
background: "white",
mouseEnter: (e, node) => (node.background = "aquamarine"),
// mouseLeave: (e, node) =>
// (node.background = node.isSelected ? "skyblue" : "white"),
},
new go.Binding("background", "isSelected", (s) =>
s ? "skyblue" : "white"
).ofObject(),
// whether the user can start drawing a link from or to this node depends on which group it's in
new go.Binding("fromLinkable", "group", (k) => k === -1),
new go.Binding("toLinkable", "group", (k) => k === -2),
$(
"TreeExpanderButton", // support expanding/collapsing subtrees
{
width: 14,
height: 14,
"ButtonIcon.stroke": "white",
"ButtonIcon.strokeWidth": 2,
"ButtonBorder.fill": "goldenrod",
"ButtonBorder.stroke": null,
"ButtonBorder.figure": "Rectangle",
_buttonFillOver: "darkgoldenrod",
_buttonStrokeOver: null,
_buttonFillPressed: null,
}
),
$(
go.Panel,
"Horizontal",
{ position: new go.Point(16, 0) },
//// optional icon for each tree node
//$(go.Picture,
// { width: 14, height: 14,
// margin: new go.Margin(0, 4, 0, 0),
// imageStretch: go.GraphObject.Uniform,
// source: "images/defaultIcon.png" },
// new go.Binding("source", "src")),
$(go.TextBlock, new go.Binding("text", "key", (s) => "item " + s))
) // end Horizontal Panel
); // end Node
// These are the links connecting tree nodes within each group.
diagram.linkTemplate = $(go.Link); // without lines
diagram.linkTemplate = // with lines
$(
go.Link,
{
selectable: false,
routing: go.Link.Orthogonal,
fromEndSegmentLength: 4,
toEndSegmentLength: 4,
fromSpot: new go.Spot(0.001, 1, 7, 0),
toSpot: go.Spot.Left,
},
$(go.Shape, { stroke: "lightgray" })
);
// These are the blue links connecting a tree node on the left side with one on the right side.
diagram.linkTemplateMap.add(
"Mapping",
$(
MappingLink,
{
isTreeLink: false,
isLayoutPositioned: false,
layerName: "Foreground",
},
{ fromSpot: go.Spot.Right, toSpot: go.Spot.Left },
{ relinkableFrom: true, relinkableTo: true },
$(go.Shape, { stroke: "blue", strokeWidth: 2 })
)
);
function updateNodeWidths(
group: {
memberParts: {
each: (arg0: {
(n: any): void;
(n: any): void;
(n: any): void;
}) => void;
};
},
width: number
) {
if (isNaN(width)) {
group.memberParts.each((n: { width: number }) => {
if (n instanceof go.Node) n.width = NaN; // back to natural width
});
} else {
var minx = Infinity; // figure out minimum group width
group.memberParts.each((n: { actualBounds: { x: number } }) => {
if (n instanceof go.Node) {
minx = Math.min(minx, n.actualBounds.x);
}
});
if (minx === Infinity) return;
var right = minx + width;
group.memberParts.each(
(n: { width: number; actualBounds: { x: number } }) => {
if (n instanceof go.Node)
n.width = Math.max(0, right - n.actualBounds.x);
}
);
}
}
function makeGroupLayout() {
return $(
go.TreeLayout, // taken from samples/treeView.html
{
alignment: go.TreeLayout.AlignmentStart,
angle: 0,
compaction: go.TreeLayout.CompactionNone,
layerSpacing: 16,
layerSpacingParentOverlap: 1,
nodeIndentPastParent: 1.0,
nodeSpacing: 0,
setsPortSpot: false,
setsChildPortSpot: false,
// after the tree layout, change the width of each node so that all
// of the nodes have widths such that the collection has a given width
// commitNodes: function () {
// // overriding TreeLayout.commitNodes
// go.TreeLayout.prototype.commitNodes();
// if (ROUTINGSTYLE === "ToGroup") {
// updateNodeWidths(group, group.data.width || 100);
// }
// },
}
);
}
diagram.groupTemplate = $(
go.Group,
"Auto",
{ deletable: false, layout: makeGroupLayout() },
new go.Binding("position", "xy", go.Point.parse).makeTwoWay(
go.Point.stringify
),
new go.Binding("layout", "width", makeGroupLayout),
$(go.Shape, { fill: "white", stroke: "lightgray" }),
$(
go.Panel,
"Vertical",
{ defaultAlignment: go.Spot.Left },
$(
go.TextBlock,
{ font: "bold 14pt sans-serif", margin: new go.Margin(5, 5, 0, 5) },
new go.Binding("text")
),
$(go.Placeholder, { padding: 5 })
)
);
// initialize tree on left side
var root: any = { key: 0, group: -1 };
nodeDataArray.push(root);
for (var i = 0; i < 11; ) {
i = makeTree(3, i, 17, nodeDataArray, linkDataArray, root, -1, root.key);
}
// initialize tree on right side
root = { key: 1000, group: -2 };
nodeDataArray.push(root);
for (var i = 0; i < 15; ) {
i = makeTree(3, i, 15, nodeDataArray, linkDataArray, root, -2, root.key);
}
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
// help create a random tree structure
function makeTree(
level: number,
count: number,
max: number,
nodeDataArray:
| {
isGroup: boolean;
key: number;
text: string;
xy: string;
width: number;
}[]
| { key: any; group: any }[],
linkDataArray: { from: any; to: any }[],
parentdata: { key: any; group?: any },
groupkey: number,
rootkey: number
) {
var numchildren = Math.floor(Math.random() * 10);
for (var i = 0; i < numchildren; i++) {
if (count >= max) return count;
count++;
var childdata: any = { key: rootkey + count, group: groupkey };
nodeDataArray.push(childdata);
linkDataArray.push({ from: parentdata.key, to: childdata.key });
if (level > 0 && Math.random() > 0.5) {
count = makeTree(
level - 1,
count,
max,
nodeDataArray,
linkDataArray,
childdata,
groupkey,
rootkey
);
}
}
return count;
}
return diagram;
}
function handleModelChange(changes: any) {
alert("GoJS model changed!");
}
return (
<div>
<ReactDiagram
initDiagram={initDiagram}
divClassName="diagram-component"
nodeDataArray={nodeDataArray}
linkDataArray={linkDataArray}
onModelChange={handleModelChange}
/>
</div>
);
}
I am trying to create pagination for my table that lists the objects returned from my DB as an object. My data structure will look something like:
$scope.myJSONObj = {
app1: {
id: 1,
appName: "appIntegrated1",
status: "Pending"
},
app2: {
id: 2,
appName: "appIntegrated2",
status: "Pending"
},
app3: {
id: 3,
appName: "appIntegrated3",
status: "Completed"
},
app4: {
id: 4,
appName: "appIntegrated4",
status: "Pending"
},
app5: {
id: 5,
appName: "appIntegrated5",
status: "Pending"
},
app6: {
id: 6,
appName: "appIntegrated6",
status: "Pending"
},
app7: {
id: 7,
appName: "appIntegrated7",
status: "Pending"
},
app8: {
id: 8,
appName: "appIntegrated8",
status: "Pending"
},
app9: {
id: 9,
appName: "appIntegrated9",
status: "Pending"
},
app10: {
id: 10,
appName: "appIntegrated10",
status: "Pending"
}
I am trying to split my structure in half, and display the first five results. I have a prev/next button, and when I click next, it should display the next 5 results (in this case the last 5). However, for everything to work, I need to be able to split my object, and so far every method I've researched involves arrays, and objects requiring some hack. I was wondering if I was missing something, or I have to create a solution to work with?
In pure JavaScript :
function getEntries(from, to) {
var entries = [];
for(var key in myJSONObj) {
// extract index after `app`
// var index = key.substring(3);
// Better way : extract index using regular expression, so it will match `something1`, `foo2`, `dummy3`
var index = parseInt(key.replace( /^\D+/g, ''));
if(index >= from && index <= to) {
entries.push(myJSONObj[key]);
}
}
return entries;
}
console.log(getEntries(0, 5));
Try _.chunk
https://lodash.com/docs/4.17.4#chunk
$scope.pages = _.chunk($scope.myJSONObj,5);
$scope.getPage = function( pageIndex ){
return $scope.pages[pageIndex];
}
It's untested - but I wrote a chunk method for you in vanilla JS since you can't use lodash.
function chunk(obj, chunkSize) {
var resultArray = [];
var resultArrayCurrentIndex = 0;
for (var key in obj) {
var item = obj[key];
if (resultArray[resultArrayCurrentIndex].length <= chunkSize) {
if (!resultArray[resultArrayCurrentIndex]) {
resultArray[resultArrayCurrentIndex] = [item];
} else {
resultArray[resultArrayCurrentIndex].push(item)
}
} else {
resultArrayCurrentIndex++
resultArray[resultArrayCurrentIndex] = [item];
}
}
return resultArray;
}
Then you can access it like this:
$scope.pages = chunk(yourObject, 5);
$scope.getPage = function(index){
return $scope.pages[index];
}
EDIT - changed it to accept an obj.
Used Object.keys, Array.prototype.slice and Array.prototype.reduce to solve your issue. Hope this helps
angular.module('app',[])
.controller('TestCtrl', function($scope){
$scope.myJSONObj = {"app1":{"id":1,"appName":"appIntegrated1","status":"Pending"},"app2":{"id":2,"appName":"appIntegrated2","status":"Pending"},"app3":{"id":3,"appName":"appIntegrated3","status":"Completed"},"app4":{"id":4,"appName":"appIntegrated4","status":"Pending"},"app5":{"id":5,"appName":"appIntegrated5","status":"Pending"},"app6":{"id":6,"appName":"appIntegrated6","status":"Pending"},"app7":{"id":7,"appName":"appIntegrated7","status":"Pending"},"app8":{"id":8,"appName":"appIntegrated8","status":"Pending"},"app9":{"id":9,"appName":"appIntegrated9","status":"Pending"},"app10":{"id":10,"appName":"appIntegrated10","status":"Pending"}};
$scope.currentPage = 0;
$scope.pageSize = 5;
$scope.totalPage = Math.ceil( Object.keys($scope.myJSONObj).length/$scope.pageSize);
//pageNumber starts from 0 here
$scope.goToPage = function(pageNumber) {
pageNumber = pageNumber>=0?pageNumber:0;
var from = pageNumber*$scope.pageSize;
var to = from + $scope.pageSize;
return Object.keys($scope.myJSONObj).slice(from,to).reduce(function(a,b){
a[b] = $scope.myJSONObj[b];
return a;
},{});
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="TestCtrl">
<button ng-disabled="currentPage===0" ng-click="currentPage = currentPage - 1">prev</button>
<button ng-disabled="currentPage===totalPage-1" ng-click="currentPage = currentPage + 1">next</button>
<b>Page: {{currentPage+1}}/{{totalPage}}</b>
<pre>{{goToPage(currentPage) | json}}</pre>
</div>
I have the below to reconfigure gridpanel, it works fine the first time, but the second time it throws the following error:
JavaScript runtime error: unable to get property 'id' of undefined or null reference"
What is wrong with my code?
$.ajax({
url: "/Home/Create",
data: JSON.stringify({ inputdata: selectedValues }),
async: false,
type: "POST",
contentType: 'application/json',
success: function (result) {
var columns = [];
var _fields = [];
var data = {
Key: [],
Value: []
};
var nameCount = 0;
var resultSet = result.result;
resultSet.forEach(function (element) {
for (var key in element) {
if (element.hasOwnProperty(key)) {
var keyStr = key;
data.Key.push(keyStr);
data.Value.push(element[key]);
}
}
}
});
var column;
var count = 0;
resultSet.forEach(function (element, index, ar) {
for (var key in element) {
if (!element.hasOwnProperty(key)) continue;
if (element.hasOwnProperty(key)) {
var field = {};
var elementValue = element[key];
var typeCheck = typeof elementValue;
field['name'] = key;
if (key.startsWith('Completed')) {
field['type'] = 'date';
field['submitFormat'] = 'm/d/Y';
field['submitValue'] = true;
}
else {
switch (typeCheck) {
case 'number':
field['type'] = 'int';
break;
case 'boolean':
field['type'] = 'string';
break;
case 'string':
field['type'] = 'string';
break;
case 'object':
field['type'] = 'object';
break;
case 'date':
field['type'] = 'date';
break;
default:
}
}
_fields.push(field);
if (key == 'EmployeeId' || key == 'EmployeeGroup'
|| key == 'GroupMemberId') {
column = Ext.create('Ext.grid.column.Column', {
text: key,
dataIndex: key,
hidden: true
});
columns.push(column);
}
else {
if (!key.startsWith('EmployeeName') && !key.startsWith('EmployeeStatus') && !key.startsWith('Completed')) {
column = Ext.create('Ext.grid.column.Column', {
text: key,
dataIndex: key,
width: 80
});
columns.push(column);
}
}
}
}
});
var keyValue = data.Key;
var values = data.Value;
var nameKeyValue = [];
var nameFinalValue;
for (var i = 0; i < keyValue.length; i++) {
for (var j = 0; j < values.length; j++) {
if (keyValue[i].startsWith('Name')) {
nameKeyValue.push(values[j]);
}
}
}
for (var i = 0; i < keyValue.length; i++) {
nameFinalValue = nameKeyValue[i];
if (keyValue[i].startsWith('Name')) {
var status = keyValue[i + 1];
var completed = keyValue[i + 2];
column = Ext.create('Ext.grid.column.Column', {
text: nameFinalValue,
dataIndex: nameFinalValue,
columns: [
Ext.create('Ext.grid.column.Column', {
text: 'Employee Status',
dataIndex: status,
width: 80,
stopSelection: false,
editable: true,
editor: {
xtype: 'checkbox'
},
field: { xtype: 'checkbox' }
}),
Ext.create('Ext.grid.column.Column', {
text: 'Completed',
dataIndex: completedOn,
width: 80,
editor: new Ext.form.DateField({
xtype: 'datefield',
format: 'm/d/y',
renderer: Ext.util.Format.dateRenderer('m/d/Y')
})
})
]
});
columns.push(column);
}
}
// *** new code
var store = Ext.create("Ext.data.Store", {
id: 'myStore',
fields: _fields,
groupField: 'Group',
proxy: {
type: 'ajax',
reader: {
type: 'json',
root: 'data'
}
}
});
var grid = App.myGrid;
grid.reconfigure(Ext.getStore('myStore'), columns);//this line throws error
grid.getStore().loadData(result.result);
grid.getView().refresh();
selectedValues = [];
}
}
});
replace error-throwing line with
grid.reconfigure(store, columns);
Try clearing your store before loading new data
grid.getStore().removeAll();
I'm trying to create a dynamic chart from userTemplate object.
I'm using this directive angular-flot and I want create the dataset and options of directive dynamically.
Its work but I have this error
Error: [$rootScope:infdig] http://errors.angularjs.org/1.2.21/$rootScope/infdig?p0=10&p1=%5B%5B%22fn%3…ection%5C%22%3A%7B%5C%22color%5C%22%3A%5C%22%2354728c%5C%22%7D%7D%22%5D%5D
at Error (native)
at http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:6:450
at k.$get.k.$digest (http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:110:66)
at k.$get.k.$apply (http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:112:173)
at http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:122:253
at e (http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:37:440)
at http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:41:120
HTML
<div ng-repeat="panel in row.panels" class="{{panel.columnClass}}" resizable id="{{panel.id}}" r-directions="['right']">
<flot dataset="getDataForChart(panel)" options="getOptionForChart(panel)" height="{{panel.graph.height}}"></flot>
</div>
CONTROLLER
$scope.userTemplate = [
{
blockId: 'blockUno',
title: 'Block title',
rows: [
{
rowId: 'rowUno',
title: 'Row Title 1',
panels: [
{
id: 'palel-report-1',
title: 'uno',
columnClass: 'col-md-4',
graph: {
height: 250,
type: "BAR",
countBy: "status"
}
},
{
id: 'palel-report-2',
title: 'due',
columnClass: 'col-md-4',
graph: {
height: 250,
type: "PIE",
countBy: "status"
}
},
{
id: 'palel-report-3',
title: 'tre',
columnClass: 'col-md-4',
graph: {
height: 250,
type: "BAR",
countBy: "status"
}
}
]
}
],
tables: []
}
];
$scope.getDataForChart = function(panel) {
var graphData = [];
var countBy = panel.graph.countBy;
var arr = $scope.reportingData;
for (var i = 0; i < arr.length; i++) {
var valueOfkey = arr[i][countBy];
graphData.push(valueOfkey);
}
var a = [], b = [], prev;
graphData.sort();
for (var i = 0; i < graphData.length; i++) {
if (graphData[i] !== prev) {
a.push(graphData[i]);
b.push(1);
} else {
b[b.length - 1]++;
}
prev = graphData[i];
}
var graphData = [];
for (var i = 0; i < a.length; i++) {
var singleO = {label: '' + a[i], data: [[i, b[i]]]};
graphData.push(singleO);
}
return graphData;
};
$scope.getOptionForChart = function(panel) {
var options = angular.copy($scope.defaultPlotOptions);
var typeGraph = panel.graph.type;
switch (typeGraph) {
case "BAR":
options.series.bars.show = true;
break;
case "LINE":
options.series.lines.show = true;
break;
case "PIE":
options.series.pie.show = true;
break;
case "POINT":
options.series.points.show = true;
break;
case "TABLE":
break;
}
return options;
};
The error you get is from an infinite digest loop.
In a couple of places you are calling functions that return new items each time. Here's an example from the docs linked from the error message you received that suggests this may cause this error:
One common mistake is binding to a function which generates a new
array every time it is called. For example:
<div ng-repeat="user in getUsers()">{{ user.name }}</div>
$scope.getUsers = function() { return [ { name: 'Hank' }, { name: 'Francisco' } ]; };
Since getUsers() returns a new array, Angular
determines that the model is different on each $digest cycle,
resulting in the error. The solution is to return the same array
object if the elements have not changed:
var users = [ { name: 'Hank' }, { name: 'Francisco' } ];
$scope.getUsers = function() { return users; };
In your code, you are doing the same binding to getDataForChart and getOptionForChart.
I have this code that loads a data store for all stories that contain each of the names from an array.
var prefix_set = [list of names]
for(var i=0;i<prefix_set.length;i++)
_get_stories_of_feature(prefix_set[i]) //this function creates a data store
I am storing all the data into a global array and creating a data store which is passed to a grid in the end. The problem is that my grid loads up with incomplete data (the grid loads up even before all the data has been loaded into the global array).
Here's my code:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
items:[{ xtype: 'container', itemId: 'print_button_box', padding: 5},{xtype: 'container', itemId: 'grid_box'}],
count: 0,
globalStore: null,
totalDataLength: 0,
gridCounter: 0,
launch: function() {
var me = this;
this.globalStore = null;
this.gridCounter = 0;
this.totalDataLength=0;
this.count = 0;
this._addPrintButton();
list = [];
//Write app code here
var prefix_set = ["Epic:","Arch:","Refa:","Innov:","Spike:","Producer:","Dependency:","Consumer:"];
var i;
for(i=0;i<prefix_set.length;i++){
this._get_stories_of_feature(prefix_set[i],prefix_set.length,i);
}
},
_addPrintButton: function() {
var me = this;
this.down('#print_button_box').add( {
xtype: 'rallybutton',
itemId: 'print_button',
text: 'CSV',
disabled: false,
handler: function() {
console.log('globalStore ',me.globalStore);
me.exportGrid(me.globalStore);
}
});
},
_onClickExport: function () {
if (document.getElementById('grid_box')) {
//Ext.getBody().mask('Exporting Tasks...');
console.log('inside export');
setTimeout(function () {
var template = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-' +
'microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head>' +
'<!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>' +
'{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>' +
'</x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>{table}' +
'</table></body></html>';
var base64 = function (s) {
return window.btoa(unescape(encodeURIComponent(s)));
};
var format = function (s, c) {
return s.replace(/{(\w+)}/g, function (m, p) {
return c[p];
});
};
var table = document.getElementById('grid_box');
console.log("Exporting table ",table);
var excel_data = '<tr>';
Ext.Array.each(table.innerHTML.match(/<span .*?x-column-header-text.*?>.*?<\/span>/gm), function (column_header_span) {
excel_data += (column_header_span.replace(/span/g, 'td'));
});
excel_data += '</tr>';
Ext.Array.each(table.innerHTML.match(/<tr class="x-grid-row.*?<\/tr>/gm), function (line) {
excel_data += line.replace(/[^\011\012\015\040-\177]/g, '>>');
});
console.log("Excel data ",excel_data);
var ctx = {worksheet: name || 'Worksheet', table: excel_data};
window.location.href = 'data:application/vnd.ms-excel;base64,' + base64(format(template, ctx));
Ext.getBody().unmask();
}, 500);
}else{
console.log("grid_box does not exist");
}
},
tableToExcel: function(){
var me = this;
console.log("Global store ",me.globalStore);
var uri = 'data:application/vnd.ms-excel;base64,'
, template = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>{table}</table></body></html>'
, base64 = function(s) { return window.btoa(unescape(encodeURIComponent(s))); }
, format = function(s, c) { return s.replace(/{(\w+)}/g, function(m, p) { return c[p]; }); };
return function(table, name) {
if (!table.nodeType) table = document.getElementById(table);
var ctx = {worksheet: name || 'Worksheet', table: table.innerHTML};
window.location.href = uri + base64(format(template, ctx));
};
},
_createStore: function(){
var me = this;
//var f = [{property: 'UserStories', operator: '!=', value: null}];
Ext.create('Rally.data.WsapiDataStore',{
autoLoad: true,
model: "PortfolioItem/Feature",
limit: 10000,
fetch: ['FormattedID','Name','UserStories','c_DIteration','c_DPSI'],
listeners:{
load: function(store,data,success){
console.log("Store ",store);
var data_length = data.length;
console.log('Data length is '+data.length);
Ext.Array.each(data,function(item){
if(item.get('UserStories')==null){
store.remove(item);
}else{
var data = {
id: item.get("FormattedID"),
name: item.get("Name"),
UserStories: item.get("UserStories")._type,
DIteration: item.get("c_DIteration"),
DPSI: item.get("c_DPSI")
};
//list.push(data);
}
me._get_stories_of_feature(item.get("ObjectID"),item.get("Name"),data_length);
});
},
scope: this
}
});
},
_showGrid: function(store){
var me = this;
if(!this.grid){
this.grid = Ext.create('Rally.ui.grid.Grid',{
store: store,
columnCfgs:[
{text: 'Feature', dataIndex: 'name'},
{text: 'FormattedID', dataIndex: 'FormattedID'},
{text: 'Name', dataIndex: 'UserStories'},
{text: 'Release', dataIndex: 'Release'},
{text: 'Iteration', dataIndex: 'Iteration'},
{text: 'DIteration', dataIndex: 'DIteration'},
{text: 'DPSI', dataIndex: 'DPSI'},
{text: 'Schedule State', dataIndex: 'ScheduleState'},
{text: 'Task Remaining Total', dataIndex: 'TaskRemainingTotal'},
{text: 'Owner', dataIndex: 'Owner'},,
{text: 'Project', dataIndex: 'Project'},
{text: 'Unscheduled', dataIndex: 'Unscheduled'}
]
});
me.globalStore = this.grid;
this.down('#grid_box').add(this.grid);
}
},
_get_stories_of_feature: function(name,length,k){
var me = this;
Ext.create('Rally.data.WsapiDataStore',{
autoLoad: true,
model: "HierarchicalRequirement",
limit: 10000,
fetch: ['Name','ObjectID','FormattedID','Parent','Feature','TaskRemainingTotal','c_DIteration','c_DPSI','DragAndDropRank','Release','Iteration','Project','Owner','ScheduleState'],
sorters:[{
property: 'DragAndDropRank', direction: 'ASC'
,},{property: 'Project', direction: 'ASC'}],
filters:[{
property: 'Name', operator: 'contains', value: name
},{
property: 'ScheduleState', operator: '!=', value: 'Accepted'
}],
pageSize: 5000,
listeners:{
load: function(store,data,success){
var data_length = data.length;
if(data_length>0){
console.log("Total stories ",data_length);
for(var i=0;i<data_length;i++){
console.log("Data length for ",k," is ",data_length);
console.log("Data i ",data[i]);
me.totalDataLength++;
var flag;
var iteration=""; var release="";
var fid = "",fname="";
var owner="";
if(data[i].data.Feature!=null && (data[i].data.Feature.c_DIteration==null || data[i].data.Feature.c_DIteration.toString().indexOf("*")!=-1))
flag = "YES";
else flag = "NO";
if(data[i].data.Iteration!=null){
iteration = data[i].data.Iteration._refObjectName;
}
if(data[i].data.Release!=null){
release = data[i].data.Release._refObjectName;
}
if(data[i].data.Owner!=null){
owner = data[i].data.Owner._refObjectName;
}
if(data[i].data.Feature!=null){
fid = data[i].data.Feature.FormattedID;
fname = data[i].data.Feature.Name;
}
var element = {
name: fid+":"+fname,
UserStories: data[i].data.Name,
Project: data[i].data.Project._refObjectName,
Owner: owner,
FormattedID: data[i].data.FormattedID,
Iteration: iteration,
TaskRemainingTotal: parseInt(data[i].data.TaskRemainingTotal),
Release: release,
ScheduleState: data[i].data.ScheduleState,
DIteration: data[i].data.c_DIteration,
DPSI: data[i].data.c_DPSI,
Unscheduled: flag
};
list.push(element);
console.log("me count is ",me.count);
console.log("Found ",data[i].data);
me.count++;
}
}
console.log("Total Data Length is ",me.totalDataLength);
console.log("k is ",k," and length is ",length);
if(k==length-1){
console.log("Building store");
//once all the stories and feature data is computed
var myStore = Ext.create("Rally.data.custom.Store",{
data: list,
sortable: true,
pageSize: me.totalDataLength,
});
me._showGrid(myStore);
}
}
}
});
me.gridCounter++;
},
exportGrid: function(grid) {
if (Ext.isIE) {
this._ieToExcel(grid);
} else {
var data = this._getCSV(grid);
window.location = 'data:text/csv;charset=utf8,' + encodeURIComponent(data);
}
},
_escapeForCSV: function(string) {
if (string.match(/,/)) {
if (!string.match(/"/)) {
string = '"' + string + '"';
} else {
string = string.replace(/,/g, ''); // comma's and quotes-- sorry, just loose the commas
}
}
return string;
},
_getFieldText: function(fieldData) {
var text;
if (fieldData == null || fieldData == undefined) {
text = '';
} else if (fieldData._refObjectName && !fieldData.getMonth) {
text = fieldData._refObjectName;
} else if (fieldData instanceof Date) {
text = Ext.Date.format(fieldData, this.dateFormat);
} else if (!fieldData.match) { // not a string or object we recognize...bank it out
text = '';
} else {
text = fieldData;
}
return text;
},
_getFieldTextAndEscape: function(fieldData) {
var string = this._getFieldText(fieldData);
return this._escapeForCSV(string);
},
_getCSV: function (grid) {
var cols = grid.columns;
var store = grid.store;
var data = '';
console.log("Grid.Store is ",grid.store);
var that = this;
Ext.Array.each(cols, function(col, index) {
if (col.hidden != true) {
data += that._getFieldTextAndEscape(col.text) + ',';
}
});
data += "\n";
store.each(function(record) {
var entry = record.getData();
Ext.Array.each(cols, function(col, index) {
if (col.hidden != true) {
var fieldName = col.dataIndex;
var text = entry[fieldName];
data += that._getFieldTextAndEscape(text) + ',';
}
});
data += "\n";
});
return data;
},
_ieGetGridData : function(grid, sheet) {
var that = this;
var resourceItems = grid.store.data.items;
var cols = grid.columns;
Ext.Array.each(cols, function(col, colIndex) {
if (col.hidden != true) {
console.log('header: ', col.text);
sheet.cells(1,colIndex + 1).value = col.text;
}
});
var rowIndex = 2;
grid.store.each(function(record) {
var entry = record.getData();
Ext.Array.each(cols, function(col, colIndex) {
if (col.hidden != true) {
var fieldName = col.dataIndex;
var text = entry[fieldName];
var value = that._getFieldText(text);
sheet.cells(rowIndex, colIndex+1).value = value;
}
});
rowIndex++;
});
},
_ieToExcel: function (grid) {
if (window.ActiveXObject){
var xlApp, xlBook;
try {
xlApp = new ActiveXObject("Excel.Application");
xlBook = xlApp.Workbooks.Add();
} catch (e) {
Ext.Msg.alert('Error', 'For the export to work in IE, you have to enable a security setting called "Initialize and script ActiveX control not marked as safe" from Internet Options -> Security -> Custom level..."');
return;
}
xlBook.worksheets("Sheet1").activate;
var XlSheet = xlBook.activeSheet;
xlApp.visible = true;
this._ieGetGridData(grid, XlSheet);
XlSheet.columns.autofit;
}
}
});
Please take a look at the code in this post, where Mark uses promises, and builds three separate Rally.data.wsapi.Stores and only after all the data is there _makeGrid(resultArray) is called.