store data issue with generic grid rendered in tabs - extjs

I have a generic grid component.
on click of menu item corresponding grid is displayed in independent tabs.
on rendering the grid component, store data is set dynamically and grid is populated.
The problem if I open two grids in two tabs, on navigating to the first tab, grid data is not displayed as the store data is set to second grid data.
Hoping to find solution.Thank you
code in main controller:
OnMenuItemClick: function(c){
var nodeText = c.text,
tabs = Ext.getCmp('app-tab'),
tabBar = tabs.getTabBar(),
tabIndex;
for(var i = 0; i < tabBar.items.length; i++) {
if (tabBar.items.get(i).getText() === nodeText) {
tabIndex = i;
}
}
if (Ext.isEmpty(tabIndex)) {
/* Note: While creating the Grid Panel,here we are passing the Menu/Grid Id along with it for future reference */
tabs.add(Ext.create('DemoApp.view.grid.GenericGrid',{title:nodeText,gridId:c.id,overflowY: 'scroll',closable:true}));
tabIndex = tabBar.items.length - 1 ;
}
tabs.setActiveTab(tabIndex);
}
code in generic grid controller:
renderGridMetadata: function(genericGrid) {
var store = Ext.getStore("DemoApp.store.GenericGrid"),
gridId = genericGrid.up().gridId,
resourceURL = "resources/data/" + gridId + ".json";
var serviceInput = Util.createServiceResponse(gridId);
/*Dynamically add the proxy URL to the ViewModel
DemoApp.model.GenericGrid.getProxy().setUrl(resourceURL);*/
Ext.getBody().mask("Loading... Please wait...", 'loading');
Ext.Ajax.request({
url: Util.localGridService,
method: 'POST',
headers: {
"Content-Type": "application/json",
'SM_USER': 'arun.x.kumar.ap#nielsen.com',
'SM_SERVERSESSIONID': 'asdfadsf'
},
jsonData: {
getConfigurationAndDataRequestType: serviceInput
},
success: function(conn, response, options, eOpts) {
Ext.getBody().unmask();
var data = Util.decodeJSON(conn.responseText);
/* Apply REST WebServices response Metadata to the Grid */
var recordsMetaData = data.getConfigurationAndDataReplyType.gridConfigDataResponse.data.record;
var jsonMetaDataArray = [];
for (var c = 0; c < recordsMetaData.length; c++) {
var jsonMetaDataObject = {};
var text = data.getConfigurationAndDataReplyType.gridConfigDataResponse.data.record[c].displayName;
var dataIndex = data.getConfigurationAndDataReplyType.gridConfigDataResponse.data.record[c].columnName;
jsonMetaDataObject["text"] = text;
jsonMetaDataObject["dataIndex"] = dataIndex;
jsonMetaDataArray.push(jsonMetaDataObject);
}
/* Apply REST WebServices response data to the Grid */
var recordsData = data.getConfigurationAndDataReplyType.gridDataResponse.record;
var jsonDataArray = [];
for (var r = 0; r < recordsData.length; r++) {
var columnsData = data.getConfigurationAndDataReplyType.gridDataResponse.record[r].column;
var jsonDataObject = {};
for (var c = 0; c < columnsData.length; c++) {
jsonDataObject[columnsData[c].columnId] = columnsData[c].columnValue;
}
jsonDataArray.push(jsonDataObject);
}
store.setData(jsonDataArray);
genericGrid.reconfigure(store, jsonMetaDataArray);
},
failure: function(conn, response, options, eOpts) {
Ext.getBody().unmask();
Util.showErrorMsg(conn.responseText);
}
});
store.load();
}
});

Most likely there is only one instance of DemoApp.store.GenericGrid.
Frankly, I only guess because I see that you call Ext.getStore("DemoApp.store.GenericGrid") that implies the store is declared in stores:["DemoApp.store.GenericGrid"] array probably in the application class.
If a store is declared this way then Ext automatically creates one instance of it setting storeId to the string listed in stores:[]. Hence, Ext.getStore() returns that instance.
If you want to have two independent instances of the grid you have to create store instances yourself preferably in initComponent override.

Related

Issues with AnyGantt

Im using AnyGantt, but Im having problems setting it up correctly.
Here is the full code:
var endpoint = '/api/chart/data/'
var label = []
var start = []
var end = []
var werk = []
$.ajax({
method: 'GET',
url: endpoint,
success: function(data){
labels = data.label
start = data.start
end = data.end
uplant = data.werk
var obj = {}
var finalArray = []
for (var i = 1; i <= start.length; i++) {
var first = { id: i, name: uplant[i] }
obj = { ...obj, ...first }
var periods = { id: labels[i], start: start[i - 1], end: end[i - 1] }
if (obj.periods) {
obj.periods.push(periods)
} else {
obj.periods = [periods]
}
finalArray.push(obj)
}
anychart.onDocumentReady(function () {
var data = finalArray;
var treeData = anychart.data.tree(data, "asTable");
chart = anychart.ganttResource();
chart.data(treeData);
chart.getTimeline().scale().minimum("2018-01-01");
chart.getTimeline().scale().maximum("2020-01-01");
var dataGrid = chart.dataGrid();
dataGrid.column(0)
.title('#')
.width(30)
.cellTextSettings({hAlign: 'center'});
dataGrid.column(1)
.title('Werk')
.width(60)
.cellTextSettings({hAlign: 'left'})
.format(function () {
return this.name;
});
chart.getTimeline().horizontalScrollBar().enabled(true);
/* chart.getTimeline().periods().edit(true); */
chart.getTimeline().edit(true);
chart.getTimeline().tooltip(false);
chart.getTimeline().elements().labels(false);
chart.container("containerx");
chart.draw();
chart.fitAll();
});
},
error:function(error_data){
console.log("error")
console.log(error_data)
}});
I can't click and move the periods (tasks) and I cant scroll.
Thank you very much for any suggestions
Please find below a screenshot of the chart:
Please find below a screenshot of the chart:
Scale range
You are applying the scale min/max correctly:
chart.getTimeline().scale().minimum("2018-01-01");
chart.getTimeline().scale().maximum("2020-01-01");
But then you override the default scale and it drops the min/max settings:
var dateTimeScale = anychart.scales.dateTime();
var dateTimeTicks = dateTimeScale.ticks();
chart.xScale(dateTimeScale);
There's no need to do this! The default Gantt Chart is already a dateTime type. Solution - simply remove those three lines above from your code.
LiveEdit
Your line chart.getTimeline().periods().edit(true); is correct, but due to a little bug in the current version 8.7.0 (Aug 2019) this setter doesn't work for types of elements. To avoid it replace this line with the following line chart.getTimeline().edit(true);.
Scrollers
The Gantt chart doesn't support x/yScrollers, only simple scroll bars.
The following methods the Gantt chart doesn't support:
chart.xScroller(true);
chart.yScroller(true);
For zooming, you can use one of the API functions. This subject is described in detail in the Gantt zooming article.

extjs treenode appendchild not working correctly

I have a treepanel which is loaded on demand from a web rest api. The rest api will return an array with the data according to the id of the selected node. Here is the code:
itemdblclick: function(item, record, eOpts) {
var store = Ext.getStore('mystore');
var newStore = Ext.create('mystore', {
autoDestroy: true,
storeId: 'otherId'
});
var parentid = record.data.id;
var that = this;
newStore.proxy.extraParams = {...};
newStore.autoDestroy = true;
newStore.storeId = 'otherId';
newStore.load({
callback: function(items) {
var node = store.getRootNode().findChild('id', record.data.idelement, true);
for (var i = 0, l = items.length; i < l; i++) {
var item = items[i].data;
var child = {..., idparent: parentid};
var newnode = node.createNode(child);
node.appendChild(newnode, true);
}
node.expand();
}
});
}
Thanks to norbeq who gave me the light to change the id of the second store. The thing is the tree is nicely populated and the node is expanded, but (why there is always a but?) next the expanded node there is no a -, the + remains the same.
This is what I mean:
I've sourrounded in red that the + mark remains and that the folder is still closed.
Also, if I click the + symbol this is what happend:
How can I solve this?
Well, finally I have to say that the official extjs documentation is quite poor for me. I found a solution by test and reading a lot of posts in several foros. I found a solution that might be helpful to others:
var rootNode = store.getRootNode();
for (var i = 0, l = records.length; i < l; i++) {
var x = records[i].data;
var child = { ... };
if (!child.idparent) {
rootNode.appendChild(child);
} else {
var parent = rootNode.findChild('idelement', child.idparent, true);
parent.appendChild(child);
}
if (!child.leaf) {
var node = store.findNode('idelement', child.idelement);
node.set('expanded', true);
}
}
rootNode.set('expanded', true);
That's it

Fabric.js group/ungroup - individual objects disappear while ungrouping

I have this functions in my angularJS controller:
function group(){
var activegroup = canvas.getActiveGroup();
var objectsInGroup = activegroup.getObjects();
activegroup.clone(function(newgroup) {
canvas.discardActiveGroup();
objectsInGroup.forEach(function(object) {
canvas.remove(object);
});
canvas.add(newgroup);
});
}
function ungroup(){
var activeObject = canvas.getActiveObject();
if(activeObject.type=="group"){
var items = activeObject._objects;
activeObject._restoreObjectsState();
canvas.remove(activeObject);
for(var i = 0; i < items.length; i++) {
canvas.add(items[i]);
canvas.item(canvas.size()-1).hasControls = true;
}
}
canvas.renderAll();
}
Working almost perfectly - jus when I ungroup the objects are not rendered (they are still in the canvas, but not visible). I can select the objects individually even if they are invisible. Selectin multiple object will show them while they are selected – deselecting one will let the other disappear. In short: ungrouping objects will not show as individual objects again.
This applys only to primitives like, box, circle, triangle. Text an images are not affected.
Help is appreciated!
function ungroup(){
var activeObject = canvas.getActiveObject();
if(activeObject.type=="group"){
var items = activeObject._objects;
alert(items);
activeObject._restoreObjectsState();
canvas.remove(activeObject);
for(var i = 0; i < items.length; i++) {
canvas.add(items[i]);
items[i].dirty = true; //set object dirty true
canvas.item(canvas.size()-1).hasControls = true;
}
canvas.renderAll();
}
}
If you set object dirty true, it will render in renderAll() call and redraw again.

How to merge REST call results in Angular app more efficiently

I have an Angular SPA running on a SharePoint 2013 page. In the code, I'm using $q to pull data from 10 different SharePoint lists using REST and then merging them into one JSON object for use in a grid. The code runs and outputs the intended merged data but it's leaky and crashes the browser after a while.
Here's the code in the service:
factory.getGridInfo = function() {
var deferred = $q.defer();
var list_1a = CRUDFactory.getListItems("ListA", "column1,column2,column3");
var list_1b = CRUDFactory.getListItems("ListB", "column1,column2,column3");
var list_2a = CRUDFactory.getListItems("ListC", "column4");
var list_2b = CRUDFactory.getListItems("ListD", "column4");
var list_3a = CRUDFactory.getListItems("ListE", "column5");
var list_3b = CRUDFactory.getListItems("ListF", "column5");
var list_4a = CRUDFactory.getListItems("ListG", "column6");
var list_4b = CRUDFactory.getListItems("ListH", "column6");
var list_5a = CRUDFactory.getListItems("ListI", "column7");
var list_5b = CRUDFactory.getListItems("ListJ", "column7");
$q.all([list_1a, list_1b, list_2a, list_2b, list_3a, list_3b, list_4a, list_4b, list_5a, list_5b])
.then(function(results){
var results_1a = results[0].data.d.results;
var results_1b = results[1].data.d.results;
var results_2a = results[2].data.d.results;
var results_2b = results[3].data.d.results;
var results_3a = results[4].data.d.results;
var results_3b = results[5].data.d.results;
var results_4a = results[6].data.d.results;
var results_4b = results[7].data.d.results;
var results_5a = results[8].data.d.results;
var results_5b = results[9].data.d.results;
var combined_1 = results_1a.concat(results_1b);
var combined_2 = results_2a.concat(results_2b);
var combined_3 = results_3a.concat(results_3b);
var combined_4 = results_4a.concat(results_4b);
var combined_5 = results_5a.concat(results_5b);
for(var i = 0; i < combined_1.length; i++){
var currObj = combined_1[i];
currObj["column4"] = combined_2[i].column4;
currObj["column5"] = combined_3[i].column5;
currObj["column6"] = combined_4[i].column6;
currObj["column7"] = combined_5[i].column7;
factory.newObjectArray[i] = currObj;
}
deferred.resolve(factory.newObjectArray);
},
function (error) {
deferred.reject(error);
});
return deferred.promise;
};
Here's the REST call in CRUDFactory:
factory.getListItems = function (listName, columns){
var webUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getByTitle('"+listName+"')/items?$select="+columns+"&$top=5000";
var options = {
headers: { "Accept": "application/json; odata=verbose" },
method: 'GET',
url: webUrl
};
return $http(options);
};
And then here's the controller bit:
$scope.refreshGridData = function(){
$scope.hideLoadingGif = false;
$scope.GridData = "";
GlobalFactory.getGridInfo()
.then(function(){
$scope.GridData = GlobalFactory.newObjectArray;
$scope.hideLoadingGif = true;
});
};
UPDATE 1: Per request, Here's the HTML (just a simple div that we're using angular-ui-grid on)
<div ui-grid="GridOptions" class="grid" ui-grid-selection ui-grid-exporter ui-grid-save-state></div>
This code starts by declaring some get calls and then uses $q.all to iterate over the calls and get the data. It then stores the results and merges them down to 5 total arrays. Then, because my list structure is proper and static, I'm able to iterate over one of the merged arrays and pull data from the other arrays into one master array that I'm assigning to factory.newObjectArray, which I'm declaring as a global in my service and using as my grid data source.
The code runs and doesn't kick any errors up but the issue is with (I believe) the "getGridInfo" function. If I don't comment out any of the REST calls, the browser uses 45 MB of data that doesn't get picked up by GC which is then compounded for each click until the session is ended or crashes. If I comment out all the calls but one, my page only uses 18.4 MB of memory, which is high but I can live with it.
So what's the deal? Do I need to destroy something somewhere? If so, what and how? Or does this relate back to the REST function I'm using?
UPDATE 2: The return result that the grid is using (the factory.newObjectArray) contains a total of 5,450 items and each item has about 80 properties after the merge. The code above is simplified and shows the pulling of a couple columns per list, but in actuality, I'm pulling 5-10 columns per list.
At the end of the day you are dealing with a lot of data, so memory problems are potentially always going to be an issue and you should probably consider whether you need to have all the data in memory.
The main goal you should probably be trying to achieve is limiting duplication of arrays, and trying to keep the memory footprint as low as possible, and freeing memory as fast as possible when you're done processing.
Please consider the following. You mention the actual number of columns being returned are more than your example so I have taken that into account.
factory.getGridInfo = function () {
var deferred = $q.defer(),
// list definitions
lists = [
{ name: 'ListA', columns: ['column1', 'column2', 'column3'] },
{ name: 'ListB', columns: ['column1', 'column2', 'column3'], combineWith: 'ListA' },
{ name: 'ListC', columns: ['column4'] },
{ name: 'ListD', columns: ['column4'], combineWith: 'ListC' },
{ name: 'ListE', columns: ['column5'] },
{ name: 'ListF', columns: ['column5'], combineWith: 'ListE' },
{ name: 'ListG', columns: ['column6'] },
{ name: 'ListH', columns: ['column6'], combineWith: 'ListG' },
{ name: 'ListI', columns: ['column7'] },
{ name: 'ListJ', columns: ['column7'], combineWith: 'ListI' },
],
// Combines two arrays without creating a new array, mindful of lenth limitations
combineArrays = function (a, b) {
var len = b.length;
for (var i = 0; i < len; i = i + 5000) {
a.unshift.apply(a, b.slice(i, i + 5000));
}
};
$q.all(lists.map(function (list) { return CRUDFactory.getListItems(list.name, list.columns.join()); }))
.then(function (results) {
var listResultMap = {}, var baseList = 'ListA';
// map our results to our list names
for(var i = 0; i < results.length; i++) {
listResultMap[lists[i].name] = results[i].data.d.results;
}
// loop around our lists
for(var i = 0; i < lists.length; i++) {
var listName = lists[i].name, combineWith = lists[i].combineWith;
if(combineWith) {
combineArrays(listResultMap[combineWith], listResultMap[listName]);
delete listResultMap[listName];
}
}
// build result
factory.newObjectArray = listResultMap[baseList].map(function(item) {
for(var i = 0; i < lists.length; i++) {
if(list.name !== baseList) {
for(var c = 0; c < lists[i].columns.length; c++) {
var columnName = lists[i].columns[c];
item[columnName] = listResultMap[list.name][columnName];
}
}
}
return item;
});
// clean up our remaining results
for (var i = 0; i < results.length; i++) {
delete results[i].data.d.results;
delete results[i];
}
deferred.resolve(factory.newObjectArray);
},
function (error) {
deferred.reject(error);
});
return deferred.promise;
};
I would suggest to add some sort of paging option... It's perhaps not a great idea to add all results to one big list.
Next i would suggest against ng-repeat or add a "track by" to the repeat function.
Check out: http://www.alexkras.com/11-tips-to-improve-angularjs-performance/
Fiddler your queries, the issue is probably rendering all the elements in the dom... Which could be kinda slow ( investigate)

CheckBox in ComboBox

I would like to have checkBoxes inside a comboBox, like in this simplified example :
var rawData = [];
for (var i = 0; i < 20; i++) {
rawData.push(i);;
}
var data = new qx.data.Array(rawData);
var list = new qx.ui.form.ComboBox();
list.setWidth(150);
this.getRoot().add(list);
var controller = new qx.data.controller.List(null, list);
var delegate = {
createItem : function() {
return new qx.ui.form.CheckBox();
}
};
controller.setDelegate(delegate);
controller.setModel(data);
It's working but i'm not able to "check" the checkboxes because the combobox is closed when i click on it, so i would like to open/close the combobox only with the button.
How to do it? Thanks in advance.
Some event of the ComboBox is responsible for closing the PopUp (see code on GitHub) before the click can get to an underlying checkbox. If you implement your own ComboBox and overwrite the close method it works.
qx.Class.define("foo.ComboBox", {
extend: qx.ui.form.ComboBox,
members: {
close: function() {
}
}
})
var rawData = [];
for (var i = 0; i < 20; i++) {
rawData.push(i);;
}
var data = new qx.data.Array(rawData);
var list = new foo.ComboBox();
list.setWidth(150);
var controller = new qx.data.controller.List(null, list);
var delegate = {
createItem : function() {
return new qx.ui.form.CheckBox();
}
};
controller.setDelegate(delegate);
controller.setModel(data);
this.getRoot().add(list);
However now you have to think about how you will handle multiple selection of checkboxes and when to close the popup.

Resources