Paging and grouping in dynamic grid - extjs4

I am using dynamic grid using this plugin.
I want to make paging in it,
I tried like,
Ext.define('....', {
extend: 'Ext.data.Store',
pageSize: 10,
proxy: {
type: 'rest',
url: me.url,
reader: {
type: 'dynamicReader',
totalProperty: 'totalCount'
}
}
});
me.bbar = Ext.create('Ext.PagingToolbar', {
store: me.store,
displayInfo: true,
displayMsg: 'Displaying topics {0} - {1} of {2}',
emptyMsg: "No topics to display"
});
In DynamicGrid.js totalProperty is not working. Am I setting the property properly there?
Then I am also trying to make grouping in the same plugin.
I have a combobox with some fields and want to select grouping field from it dynamically. When I select a field in combo box, it sends that data to grid's groupField property.
I have that combo box value selected in controller like,
var groupData = Ext.ComponentQuery.query('#groupid')[0].getValue();
I am sending it to grid like,
Ext.define('Group', {
singleton: true,
param: groupData
});
I am getting that for grid property (in DynamicGrid.js) like,
groupField: [Group.param]
But this automatically selects first field for groupField property before even selecting anything in combo box and makes grouping, selecting other fields in combo box also doesn't work, it always has first field for grouping.
What is going wrong? Please help.

I did grouping successfully by adding the following code in listener,
me.store.group(Group.param);
Still having issues with totalProperty, can someone help me to make it work?
I think I am making a mistake, now actual JSON response is,
[{
"userId": 123,
"name": "Ed Spencer",
"email": "ed#sencha.com"
}]
So the code for getting data and manipulating works fine like,
readRecords: function(data) {
if (data.length > 0) {
var item = data[0];
var fields = new Array();
var columns = new Array();
var p;
for (p in item) {
if (p && p != undefined) {
fields.push({name: p, type: 'floatOrString'});
columns.push({text: p, dataIndex: p});
}
}
data.metaData = { fields: fields, columns: columns };
}
return this.callParent([data]);
}
But for sending other metaData properties, from the docs I should probably have the following JSON response,
{
"count": 1,
"ok": true,
"msg": "Users found",
"users": [{
"userId": 123,
"name": "Ed Spencer",
"email": "ed#sencha.com"
}],
"metaData": {
"root": "users",
"idProperty": 'userId',
"totalProperty": 'count',
"successProperty": 'ok',
"messageProperty": 'msg'
}
}
So how do I point root in the readReords function so that it knows data is in root?
Thereby I will have other metaData properties also passed.
Please help!

Related

Mimic the ( Show All ) link in datatables.net

I have a situation where I want to get the full (data) from the backend as a CSV file. I have already prepared the backend for that, but normally the front-end state => (filters) is not in contact with the backend unless I send a request, so I managed to solve the problem by mimicking the process of showing all data but by a custom button and a GET request ( not an ajax request ). knowing that I am using serverSide: true in datatables.
I prepared the backend to receive a request like ( Show All ) but I want that link to be sent by custom button ( Export All ) not by the show process itself as by the picture down because showing all data is not practical at all.
This is the code for the custom button
{
text: "Export All",
action: function (e, dt, node, config) {
// get the backend file here
},
},
So, How could I send a request like the same request sent by ( Show All ) by a custom button, I prepared the server to respond by the CSV file. but I need a way to get the same link to send a get request ( not by ajax ) by the same link that Show All sends?
If you are using serverSide: true that should mean you have too much data to use the default (serverSide: false) - because the browser/DataTables cannot handle the volume. For this reason I would say you should also not try to use the browser to generate a full export - it's going to be too much data (otherwise, why did you choose to use serverSide: true?).
Instead, use a server-side export utility - not DataTables.
But if you still want to pursuse this approach, you can build a custom button which downloads the entire data set to the DataTables (in your browser) and then exports that complete data to Excel.
Full Disclosure:
The following approach is inspired by the following DataTables forum post:
Customizing the data from export buttons
The following approach requires you to have a separate REST endpoint which delivers the entire data set as a JSON response (by contrast, the standard response should only be one page of data for the actual table data display and pagination.)
How you set up this endpoint is up to you (in Laravel, in your case).
Step 1: Create a custom button:
I tested with Excel, but you can do CSV, if you prefer.
buttons: [
{
extend: 'excelHtml5', // or 'csvHtml5'
text: 'All Data to Excel', // or CSV if you prefer
exportOptions: {
customizeData: function (d) {
var exportBody = getDataToExport();
d.body.length = 0;
d.body.push.apply(d.body, exportBody);
}
}
}
],
Step 2: The export function, used by the above button:
function GetDataToExport() {
var jsonResult = $.ajax({
url: '[your_GET_EVERYTHING_url_goes_here]',
success: function (result) {},
async: false
});
var exportBody = jsonResult.responseJSON.data;
return exportBody.map(function (el) {
return Object.keys(el).map(function (key) {
return el[key]
});
});
}
In the above code, my assumption is that the JSON response has the standard DataTables object structure - so, something like:
{
"data": [
{
"id": "1",
"name": "Tiger Nixon",
"position": "System Architect",
"salary": "$320,800",
"start_date": "2011/04/25",
"office": "Edinburgh",
"extn": "5421"
},
{
"id": "2",
"name": "Garrett Winters",
"position": "Accountant",
"salary": "$170,750",
"start_date": "2011/07/25",
"office": "Tokyo",
"extn": "8422"
},
{
"id": "3",
"name": "Ashton Cox",
"position": "Junior Technical Author",
"salary": "$86,000",
"start_date": "2009/01/12",
"office": "San Francisco",
"extn": "1562"
}
]
}
So, it's an object, containing a data array.
The DataTables customizeData function is what controls writing this complete JSON to the Excel file.
Overall, your DataTables code will look something like this:
$(document).ready(function() {
$('#example').DataTable( {
serverSide: true,
dom: 'Brftip',
buttons: [
{
extend: 'excelHtml5',
text: 'All Data to Excel',
exportOptions: {
customizeData: function (d) {
var exportBody = GetDataToExport();
d.body.length = 0;
d.body.push.apply(d.body, exportBody);
}
}
}
],
ajax: {
url: "[your_SINGLE_PAGE_url_goes_here]"
},
"columns": [
{ "title": "ID", "data": "id" },
{ "title": "Name", "data": "name" },
{ "title": "Position", "data": "position" },
{ "title": "Salary", "data": "salary" },
{ "title": "Start Date", "data": "start_date" },
{ "title": "Office", "data": "office" },
{ "title": "Extn.", "data": "extn" }
]
} );
} );
function GetDataToExport() {
var jsonResult = $.ajax({
url: '[your_GET_EVERYTHING_url_goes_here]',
success: function (result) {},
async: false
});
var exportBody = jsonResult.responseJSON.data;
return exportBody.map(function (el) {
return Object.keys(el).map(function (key) {
return el[key]
});
});
}
Just to repeat my initial warning: This is probably a bad idea, if you really needed to use serverSide: true because of the volume of data you have.
Use a server-side export tool instead - I'm sure Laravel/PHP has good support for generating Excel files.

How to display leaf node story count on a board

I' m struggling to display leaf node count on individual cards of a feature story board. I' m using Lookback API to query leaf node stories. Below code is not displaying data correctly and its skipping the field for an entire column. Could you please let me know what I 'm doing wrong here or if there's an easy way to do this. I 'm a novice app developer. Thanks in advance!
cardConfig: {
editable: false,
showIconsAndHighlightBorder: false,
fields: [
'Name',
{
name: 'LeafCount', //field name
hasValue: function() {return true;}, //always show this field
renderTpl: Ext.create('Rally.ui.renderer.template.LabeledFieldTemplate', {
fieldLabel: 'Leaf story Count', //the field label
valueTemplate: Ext.create('Ext.XTemplate',
['{[this.getLeafCount(values)]}',
{getLeafCount: function(data) {
var OID = data.ObjectID;
snapshotStore = Ext.create('Rally.data.lookback.SnapshotStore', {
listeners: {
load: function(store, records, success) {
console.log(records.length);
count = records.length;
}
},
autoLoad: true,
useHttpPost: true,
fetch: ['Name', 'FormattedID', 'ObjectID'],
find: {
"_ItemHierarchy": OID,
"_TypeHierarchy": "HierarchicalRequirement",
"Children": null,
"__At": "current"
},
scope: this
});
return count;
// return snapshotStore.totalCount;
}
}])
})
},
//additional string fields
'c_StoryType', 'Project', 'PlanEstimate', 'Parent', 'TaskEstimateTotal', 'TaskRemainingTotal']
},
This isn't working for you because all the data needs to be available when the template is evaluated- there isn't time to do an async store load before rendering the value.
For this specific case can't you just show the built-in LeafStoryCount field on your cards?

DataTables ajax requires explicit json collection name for the returned datasource?

I recently ran into a problem when implementing the ajax functionality of jquery DataTables. Until I actually gave my json object collection an explicit name I couldn't get anything to display. Shouldn't there be a default data source if nothing named is returned?
Client Side control setup (includes hidden field that supplies data to dynamic anchor:
$('#accountRequestStatus').dataTable(
{
"destroy": true, // within a method that will be called multiple times with new/different data
"processing": true,
"ajax":
{
"type": "GET",
"url": "#Url.Action("SomeServerMethod", "SomeController")",
"data": { methodParam1: 12341, methodParam2: 123423, requestType: 4123421 }
}
, "paging": false
, "columns": [
{ "data": "DataElement1" },
{ "data": "DataElement2", "title": "Col1" },
{ "data": "DataElement3", "title": "Col2" },
{ "data": "DataElement4", "title": "Col3" },
{ "data": "DataElement5", "title": "Col4" },
]
, "columnDefs": [
{
"targets": 0, // hiding first column, userId
"visible": false,
"searchable": false,
"sortable": false
},
{
"targets": 5, // creates action link using the hidden data for that row in column [userId]
"render": function (data, type, row) {
return "<a href='#Url.Action("ServerMethod", "Controller")?someParam=" + row["DataElement1"] + "'>Details</a>"
},
"searchable": false,
"sortable": false
}
]
});
Here's a snippet of my server side code that returns the json collection.
tableRows is a collection of models containing the data to be displayed.
var json = this.Json(new { data = tableRows });
json.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return json;
As I said before, the ajax call returned data but wouldn't display until I gave the collection a name. Maybe I missed this required step in the documentation, but wouldn't it make sense for the control to wire up to a single returned collection as the default data source and not require the name? Figuring out the name thing equated to about 2+ hours of messin' around trying different things. That's all I'm saying.
Maybe this'll help someone else too...
dataTables does actually have a dataSrc property! dataTables will look for either a data or an aaData section in the JSON. Thats why you finally got it to work with new { data=tableRows }. That is, if dataSrc is not specified! If your JSON differs from that concept you must specify dataSrc :
If you return a not named array / collection [{...},{...}] :
ajax: {
url: "#Url.Action("SomeServerMethod", "SomeController")",
dataSrc: ""
}
If you return a JSON array named different from data or aaData, like customers :
ajax: {
url: "#Url.Action("SomeServerMethod", "SomeController")",
dataSrc: "customers"
}
If the content is nested like { a : { b : [{...},{...}] }}
ajax: {
url: "#Url.Action("SomeServerMethod", "SomeController")",
dataSrc: "a.b"
}
If you have really complex JSON or need to manipulate the JSON in any way, like cherry picking from the content - dataSrc can also be a function :
ajax: {
url: "#Url.Action("SomeServerMethod", "SomeController")",
dataSrc: function(json) {
//do what ever you want
//return an array containing JSON / object literals
}
}
Hope the above clears things up!

Using collection summaries for multi-select fields

Using sdk2, I want to know how many tests are in a project, and how many of those tests are manual vs. automated. It seems like I should be able to use Collection Summaries to do this. The advantage of using summaries is that then I can get a count of tests back instead of a list of hundreds of tests, or making multiple queries (one for all tests, and one for manual tests).
But the example shows how to query for a summary of defects on a user story. It does now show if it is possible to get a summary of a multi-select or another type of field.
I tried to guess what the syntax might be below, but it didn't work:
Ext.create('Rally.data.wsapi.Store', {
model: 'TestCase',
fetch: ['Method:summary[Manual,Automated]'], // This is the key statement: how to fetch a summary?
pageSize: 1,
autoLoad: true,
listeners: {
load: function(store, records) {
var testcase = records[0];
var methodInfo = testase.get('Method');
var manualCount = methodInfo.Manual;
}
}
});
Is it possible to do this in a query with just one result using collection summaries?
This certainly would be useful for non-collection attributes such as TestCase.Method. WSAPI 2.0 Collection Summaries, however, were developed to provide a convenient way to get and summarize counts for Child Collections of Artifacts, without having to go back to WSAPI and query the collection itself. Because WSAPI 2.0 removed the ability to automatically hydrate Child Collections for performance reasons, the summary capability was important.
Thus, the summary method works for summarizing attribute counts for a Child Collections of Objects on an Artifact, for example:
Summarizing Tasks by State on Defects: https://rally1.rallydev.com/slm/webservice/v2.0/defect?fetch=Tasks:summary[State]&order=Rank
Defects by Owner on Stories: https://rally1.rallydev.com/slm/webservice/v2.0/hierarchicalrequirement?fetch=Defects:summary[Owner]&order=ScheduleState
To save loading of an entire store just to get attribute counts, you could set a filter on your store by TestCase Method, and use a unit page size to prevent loading the full set of records. Then use getTotalCount() to summarize the counts you want.
However, this could get a bit cumbersome by having to load a WsapiStore and deal with a callback for each attribute you wish to summarize.
By using Deft.js and Promises though, it is a bit more palatable. Here's a basic example that uses promises and Deft.Deferred to implement a _getCount(modelType, attribute, attrValue) function:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
items: [
{
xtype: 'container',
itemId: 'gridContainer',
columnWidth: 1
}
],
_summaryGrid: null,
launch: function() {
this._summarizeTestCaseCounts();
},
_summarizeTestCaseCounts: function() {
var me = this;
var promises = [];
var resultArray = [];
promises.push(me._getCount('TestCase', 'Method', 'Manual'));
promises.push(me._getCount('TestCase', 'LastVerdict', 'Failed'));
promises.push(me._getCount('TestCase', 'LastVerdict', 'Pass'));
Deft.Promise.all(promises).then({
success: function(results) {
Ext.Array.each(results, function(result) {
resultArray.push(result);
console.log(result);
});
// Create grid from summarized results
me._makeGrid(resultArray);
}
});
},
_getCount: function(modelType, attribute, attrValue) {
var deferred = Ext.create('Deft.Deferred');
var artifactStore = Ext.create('Rally.data.wsapi.Store', {
model: modelType,
pagesize: 1,
autoLoad: true,
filters: [
{
property: attribute,
operator: '=',
value: attrValue
}
],
sorters: [
{
property: 'FormattedID',
direction: 'ASC'
}
],
listeners: {
load: function(store, records) {
var manualCount = store.getTotalCount();
result = {
"ModelType": modelType,
"Attribute": attribute,
"Value": attrValue,
"Count": manualCount
};
deferred.resolve(result);
}
}
});
return deferred;
},
_makeGrid: function(results) {
var me = this;
if (me._summaryGrid) {
me._summaryGrid.destroy();
}
var gridStore = Ext.create('Rally.data.custom.Store', {
data: results,
pageSize: 5,
remoteSort: false
});
me._summaryGrid = Ext.create('Rally.ui.grid.Grid', {
itemId: 'artifactGrid',
store: gridStore,
columnCfgs: [
{
text: 'Artifact', dataIndex: 'ModelType'
},
{
text: 'Attribute', dataIndex: 'Attribute'
},
{
text: 'Value', dataIndex: 'Value'
},
{
text: 'Count', dataIndex: 'Count'
}
]
});
me.down('#gridContainer').add(me._summaryGrid);
me._summaryGrid.reconfigure(gridStore);
}
});
As an aside, Matt Greer recently wrote a fantastic blog posting outlining his deep-dive on using Deft.js promises. It was very helpful to me in understanding how to use them when building Rally Apps.

How to populate second combo depending on first combo value from json response in sencha

I am trying to populate a second combo depending on the first combo from json response like displaying subcategory value in second combo using category value in first combo. All my values are coming from json array response, I am trying to set root property dynamically and load the store of second combo box in controller in first combo change function but it's not populating the data. Can anybody tell me what the problem is. How do I fix it? I have posted my code below for the change function of first combo:
valueChange:function(combo, ewVal, oldVal,optionsVal) {
for(var i=0;i<tempstore.getCount();i++){
var record = tempstore.getAt(i);
//checking for user selection id with store id
if(record.get('categoryId')==ewVal)
{
value="category.category1.category["+i+"].subCategory.subCategory1";
tempsecondCompostore.getProxy().getReader().setRootProperty(value);
tempsecondCompostore.load();
cmbSecond.setStore(tempsecondCompostore);
mdSecond.setDisplayField('subCategoryName');
cmdSecond.setValueField('subCategoryId');
break;
}
}
This is my Second combo Model:
Ext.define('Test.model.SubCategoryModel', {
extend : 'Ext.data.Model',
fields : [
{
name:'subCategoryName',
type:'string'
},
{
name:'subCategoryId',
type:'string'
}
]
});
This is my Second Combo store:
Ext.define('Test.store.SubCategoryStore', {
extend : 'Ext.data.Store',
storeId : 'secondcombo',
model : 'Test.model.SubCategoryModel',
//autoLoad : 'true',
proxy : {
type : 'ajax',
url : 'data.json',
reader : {
type : 'json',
rootProperty:'category.category1.category[0].subCategory.subCategory1
}
}
});
In View Displaying combo:
xtype: 'fieldset',
width:400,
heigth:200,
items: [
{
xtype: 'selectfield',
label: 'Select',
store : 'secondcombo',
width:400,
heigth:200,
queryMode: 'local',
displayField :'subCategoryName',
valueField :'subCategoryId',
id:'cmbSecond'
}
]
Thanks
The problem is that the load() of the store is asynchronous and you need to include the lines after this call in the callback.