Is there a extJS tri state/three state checkbox? - extjs

Looking for a checkbox that can hold three states.
Use:
True, False, Unknown.
Expected behavior:
[x], [ ], [~]
Anyone know of anything?

Ext 3.* Tri-state from this website
Ext 6.2.1
This code exerpt is from sencha forums
{
name: 'optionalChange',
fieldLabel: 'Optional change',
xtype: 'tri-checkbox',
value: 'null'
},
.x-checkbox-null .x-form-checkbox-default {
border: 1px inset #a0a0a0;
background: lightgrey;
box-shadow: 0 0 0 1px hsl(0, 0%, 80%);
}
/**
* Tri-state Checkbox.
* Author: ontho & nux
* Source: https://www.sencha.com/forum/showthread.php?138664-Ext.ux.form.TriCheckbox&p=619810
*
* Note! You must add `x-checkbox-null` style for yourself.
* This might work for classic theme:
.x-checkbox-null .x-form-checkbox-default {
background-position: -39px -26px;
}
*
*/
Ext.define('Ext.ux.form.TriCheckbox', {
extend: 'Ext.form.field.Checkbox',
alias: ['widget.xtricheckbox', "widget.tri-checkbox"],
triState: true, // triState can dynamically be disabled using enableTriState
values: ['null', '0', '1'], // The values which are toggled through
checkedClasses: ['x-checkbox-null', '', Ext.baseCSSPrefix + 'form-cb-checked'], // The classes used for the different states
currentCheck: 0, // internal use: which state we are in?
getSubmitValue: function()
{
return this.value;
},
getRawValue: function()
{
return this.value;
},
getValue: function()
{
return this.value;
},
initValue: function()
{
var me = this;
me.originalValue = me.lastValue = me.value;
me.suspendCheckChange++;
me.setValue(me.value);
me.suspendCheckChange--;
},
setRawValue: function(v)
{
var me = this;
if (v === false || v == 0)
v = '0';
if (v === true || v == 1)
v = '1';
if (v == null || v == '' || v === undefined)
{
if (!this.triState)
v = '0';
else
v = 'null';
}
var oldCheck = me.currentCheck;
me.currentCheck = me.getCheckIndex(v);
me.value = me.rawValue = me.values[me.currentCheck];
// Update classes
var inputEl = me.inputEl;
if (inputEl)
{
inputEl.dom.setAttribute('aria-checked', me.value == '1' ? true : false);
}
me['removeCls'](me.checkedClasses)
me['addCls'](me.checkedClasses[this.currentCheck]);
},
// this is a defaul Checkbox style setter we need to override to remove defult behaviour
updateCheckedCls: function(checked) {
},
// Returns the index from a value to a member of me.values
getCheckIndex: function(value)
{
for (var i = 0; i < this.values.length; i++)
{
if (value === this.values[i])
{
return i;
}
}
return 0;
},
// Handels a click on the checkbox
listeners: {
afterrender: function()
{
var me = this;
this.el.dom.onclick = function(){
me.toggle();
return false;
};
}
},
// Switches to the next checkbox-state
toggle: function()
{
var me = this;
if (!me.disabled && !me.readOnly)
{
var check = me.currentCheck;
check++;
if (check >= me.values.length) {
check = (me.triState == false) ? 1 : 0;
}
this.setValue(me.values[check]);
}
},
// Enables/Disables tristate-handling at runtime (enableTriState(false) gives a 'normal' checkbox)
enableTriState: function(bTriState)
{
if (bTriState == undefined)
bTriState = true;
this.triState = bTriState;
if (!this.triState)
{
this.setValue(this.value);
}
},
// Toggles tristate-handling ar runtime
toggleTriState: function()
{
this.enableTriState(!this.triState);
}
});

Related

Date range picker for extjs?

Is there a good date-range picker for ExtJs?
Something like this: http://www.daterangepicker.com/?
I whipped this up in about 2 hours, so I'm sure there are some lingering bugs and things left to be desired, but it at least gets you started with a custom date range component. Here's my Fiddle. And the code:
Ext.define('DatePickerEnhanced', {
extend: 'Ext.picker.Date',
alias: 'widget.datePickerEnhanced',
config: {
startDate: null,
endDate: null
},
isDateRange: true,
isDragging: false,
initComponent: function () {
this.callParent()
this.on({
mouseover: {
element: 'el',
fn: 'onMouseOverEnhanced',
delegate: 'td.x-datepicker-cell',
scope: this
}
});
},
handleDateClick: function (e, t) {
this.callParent(arguments)
if (this.isDateRange) {
if (this.isDragging) {
this.isDragging = false;
var startCell = this.getCellByValue(this.startCell)
if (startCell) {
Ext.get(startCell).addCls(this.selectedCls)
}
this.setEndDate(new Date(this.getCellDateValue(this.activeCell)))
this.updateDateRange(this.startCell, this.endCell);
} else {
this.setStartDate(new Date(this.getCellDateValue(this.activeCell)))
this.isDragging = true;
this.updateDateRange(this.getCellDateValue(), -1);
}
}
},
getCellByValue: function (value) {
var cells = this.cells.elements;
for (var i = 0; i < cells.length; i++) {
var cell = cells[i]
if (cell.firstChild.dateValue === value) {
return cell;
}
}
},
onMouseOverEnhanced: function (e, target, eOpts) {
if (this.isDragging) {
this.updateDateRange(this.getCellDateValue(), this.getCellDateValue(target));
}
},
updateDateRange: function (startValue, endValue) {
var cells = this.cells.elements;
var selectedCls = this.selectedCls;
for (var i = 0; i < cells.length; i++) {
var cell = Ext.fly(cells[i])
var dateValue = this.getCellDateValue(cells[i]);
if (dateValue !== startValue && (dateValue < startValue || dateValue > endValue)) {
cell.removeCls(selectedCls)
} else {
cell.addCls(selectedCls)
}
}
},
getCellDateValue: function (cell) {
return cell && cell.firstChild.dateValue || this.startCell;
},
getDateRange: function () {
return {
start: this.getStartDate(),
end: this.getEndDate()
}
},
/**
* Update the contents of the picker for a new month
* #private
* #param {Date} date The new date
*/
fullUpdate: function (date) {
var me = this;
me.callParent(arguments);
Ext.asap(function () {
if (me.isDateRange && me.endCell) {
me.updateDateRange(me.startCell, me.endCell)
}
})
},
updateStartDate: function (value) {
this.startCell = value.getTime()
this.publishState('startDate', value);
},
updateEndDate: function (value) {
this.endCell = value.getTime()
this.publishState('endDate', value);
}
});
Ext.create('Ext.container.Viewport', {
viewModel: {
data: {
theStart: Ext.Date.add(new Date(), Ext.Date.DAY, 2),
theEnd: Ext.Date.add(new Date(), Ext.Date.DAY, 5)
}
},
items: [{
xtype: 'datePickerEnhanced',
minDate: new Date(),
bind: {
startDate: '{theStart}',
endDate: '{theEnd}'
}
}, {
xtype: 'displayfield',
fieldLabel: 'Start',
bind: {
value: '{theStart:date("m/d/Y")}'
}
}, {
xtype: 'displayfield',
fieldLabel: 'End',
bind: {
value: '{theEnd:date("m/d/Y")}'
}
}]
});

Dots persist on D3 graph for angularjs

I am using NVD3 for my graphs and I have this issue where the dots that show up on hover will start to persist as you over over the line. Does anyone have any idea on how to make sure these disappear when the move moves away from them?
Here is the component:
;(function() {
angular.module('canopy.common.components.largeStandardChart')
.component('largeStandardChart', {
templateUrl: 'app/common/components/chart-components/large-standard-chart/large-standard-chart.html',
controller: LargeStandardChartController,
controllerAs: 'vm',
bindings: {
kpi: "<",
updateGraph: '=',
frequency: '<'
}
});
LargeStandardChartController.$inject = ['$rootScope', 'BanyanUtilsService', 'ConfigurationService', '$timeout'];
function LargeStandardChartController($rootScope, UtilsService, CS, $timeout) {
var vm = this;
vm.kpiTrend = [];
vm.kpiTargetTrend = [];
vm.kpiProjectedTrend = [];
vm.predictedDate = null;
var allTrends = vm.kpi.trend.length && vm.kpi.trend[0].values.length ? vm.kpi.trend[0].values : [];
vm.chart = {
chartOptions: {
chart: {
type: 'lineChart',
height: 250,
area: CS.getOrgConfig().graph.general.fillArea,
margin : {
top: 15,
right: 40,
bottom: 50,
left: 70
},
x: (function(d) { return d.time }),
y: (function(d) { return d.value }),
clipVoronoi: false,
xAxis: {
showMaxMin: false,
staggerLabels: vm.frequency === 'DAY' ? false : true,
tickFormat: function(d) {
return vm.frequency === 'DAY'
? d3.time.format(CS.getOrgConfig().dateTime.d3DateFormat)(new Date(d))
: d3.time.format(CS.getOrgConfig().dateTime.d3DateTimeFormat)(new Date(d));
}
},
yAxis: {
showMaxMin: true,
tickFormat: function (d) {
return vm.kpi.kpiMeasure === 'NUMBER' && d ? d.toFixed(1) : UtilsService.getFormattedData(d, vm.kpi.kpiMeasure);
}
},
tooltip: {
hideDelay: 0
},
showXAxis: CS.getOrgConfig().graph.xAxis.showXAxis,
showYAxis: CS.getOrgConfig().graph.yAxis.showYAxis,
showLegend: false,
transitionDuration: 350,
useInteractiveGuideline: false
}
}
};
vm.$onInit = function() {
if(vm.updateGraph) { vm.updateGraph.handler = vm.updateGraphData; }
if (!vm.kpi) { vm.kpi = { trend: vm.kpiTrend, kpiMeasure: "PERCENTAGE" } }
setTrends();
d3.select(window).on('mouseout', function () {
d3.selectAll('.nvtooltip').style('opacity', '0');
});
};
function setTrends() {
_.set(vm.chart, 'chartData', []);
vm.kpiTrend = [];
vm.kpiProjectedTrend = [];
_.forEach(allTrends, function(kpi) {
if (_.has(kpi, 'predict')) {
vm.kpiProjectedTrend.push(kpi);
} else {
if (CS.getOrgConfig().graph.general.showNullValues) {
vm.kpiTrend.push(kpi);
} else {
if (kpi.value) { vm.kpiTrend.push(kpi) }
}
}
});
if (!vm.kpi.hideTarget && !vm.kpiProjectedTrend.length) {
vm.chart.chartData.push({
key: CS.getOrgConfig().labels.target.single,
classed: "dashed",
color: $rootScope.branding.canopyBrandColor,
seriesIndex: 2,
strokeWidth: 1,
values: getTargetValues()
});
}
if (vm.kpiTrend.length) {
vm.chart.chartData.push({
key: 'Value',
classed: "solid",
area: CS.getOrgConfig().graph.general.fillArea,
color: $rootScope.branding.canopyBrandColor,
seriesIndex: 0,
strokeWidth: 2,
values: vm.kpiTrend
});
}
if (vm.kpiProjectedTrend.length) {
vm.chart.chartOptions.chart.useInteractiveGuideline = false;
var lastCurrentValue = angular.copy(vm.kpiTrend).pop();
var firstPredictedValue = angular.copy(vm.kpiTrend).pop();
vm.kpiProjectedTrend.unshift(firstPredictedValue);
vm.endDate = moment.unix(allTrends[ allTrends.length - 1 ].time / 1000).format(CS.getOrgConfig().dateTime.dateFormat); // Divide by 1000 for miliseconds coming from server
vm.chart.chartData.push({
key:'Projected',
classed: "dashed",
color: $rootScope.branding.canopyBrandColor,
strokeWidth: 1,
seriesIndex: 3,
values: vm.kpiProjectedTrend
});
var top = 0, bottom = 0;
if (allTrends.length) {
var top = _.maxBy(allTrends, function(tr) { return tr.value }).value;
var bottom = _.minBy(allTrends, function(tr) { return tr.value }).value;
}
var yTop = vm.kpi.kpiMeasure === 'PERCENTAGE' ? 103 : top + ((top - bottom) * 0.07);
var yBottom = vm.kpi.kpiMeasure === 'PERCENTAGE' ? 0 : bottom - ((top - bottom) * 0.04);
vm.chart.chartData.push({
classed: "solid",
strokeWidth: 1,
seriesIndex: 4,
values: [
{time: lastCurrentValue.time, value: yTop},
{time: lastCurrentValue.time, value: yBottom},
],
color: '#ff0005'
});
}
setDomain();
}
function setDomain () {
var top = 0, bottom = 0;
if (allTrends.length) {
top = _.maxBy(allTrends, function(tr) { return tr.value }).value;
bottom = _.minBy(allTrends, function(tr) { return tr.value }).value;
}
bottom = bottom < 1 && bottom > 0 ? 0 : bottom;
if (top === bottom) { bottom = top - bottom; }
if (top + bottom === 0) { top = 1; }
var yTop = vm.kpi.kpiMeasure === 'PERCENTAGE' ? 103 : top + ((top - bottom) * 0.05);
var yBottom = vm.kpi.kpiMeasure === 'PERCENTAGE' ? 0 : bottom - ((top - bottom) * 0.05);
vm.chart.chartOptions.chart.yDomain = [yBottom, yTop];
}
vm.updateGraphData = function(trend) {
allTrends = trend.length && trend[0].values.length ? trend[0].values : [];
setTrends();
vm.api.updateWithOptions(vm.chart.chartOptions);
vm.api.updateWithData(trend);
vm.api.refresh();
};
function getTargetValues() {
var trend = angular.copy(allTrends);
_.forEach(trend, function(t) {
t.value = vm.kpi.targetValue;
});
return trend;
}
}
})();
and here is what it looks like when I hover:
For anyone having this issue I have finally found the solution. I had to add a listener on the mouseout event and remove the hover class that is added to the .nv-point which is the dot. It looks like this:
d3.select(window).on('mouseout', function () {
d3.selectAll('.nv-point').classed('hover', false);
});

ExtJS5: Custom component(ticker) increasing CPU cycles 10 times

I am using a ticker component in my application. When the text is rolling, the CPU cycles hit 10+. As soon as I hover cursor over it, the scrolling stops and the CPU cycles comes down to 0
Can someone tell if this is normal? If not, how can I make this component use less CPU cycles?
Here is the code for ticker:
Ext.define('MyApp.ux.Ticker', {
extend: 'Ext.Component',
xtype: 'ticker',
baseCls: 'x-ticker',
autoEl: {
tag: 'div',
cls: 'x-ticker-wrap',
children: {
tag: 'div',
cls: 'x-ticker-body'
}
},
body: null,
constructor: function (config) {
Ext.applyIf(config, {
direction: 'left',
speed: 10,
pauseOnHover: true
});
if (config.speed < 1) config.speed = 1;
else if (config.speed > 20) config.speed = 20;
Ext.applyIf(config, {
refreshInterval: parseInt(10 / config.speed * 15)
});
config.unitIncrement = 1;
this.callParent([config]);
},
afterRender: function () {
this.body = this.el.first('.x-ticker-body');
this.body.addCls(this.direction);
this.taskCfg = {
interval: this.refreshInterval,
scope: this
};
var posInfo, body = this.body;
switch (this.direction) {
case "left":
case "right":
posInfo = { left: body.getWidth() };
this.taskCfg.run = this.scroll.horz;
break;
case "up":
case "down":
posInfo = { top: body.getHeight() };
this.taskCfg.run = this.scroll.vert;
break;
}
posInfo.position = 'relative';
body.setPositioning(posInfo);
DHT.ux.Ticker.superclass.afterRender.call(this);
if (this.pauseOnHover) {
this.el.on('mouseover', this.onMouseOver, this);
this.el.on('mouseout', this.onMouseOut, this);
this.el.on('click', this.onMouseClick, this);
}
this.task = Ext.apply({}, this.taskCfg);
Ext.util.TaskManager.start(this.task);
},
add: function (o) {
var dom = Ext.DomHelper.createDom(o);
this.body.appendChild(Ext.fly(dom).addCls('x-ticker-item').addCls(this.direction));
},
onDestroy: function () {
if (this.task) {
Ext.util.TaskManager.stop(this.task);
}
DHT.ux.Ticker.superclass.onDestroy.call(this);
},
onMouseOver: function () {
if (this.task) {
Ext.util.TaskManager.stop(this.task);
delete this.task;
}
},
onMouseClick: function (e, t, o) {
var item = Ext.fly(t).up('.x-ticker-item');
if (item) {
this.fireEvent('itemclick', item, e, t, o);
}
},
onMouseOut: function () {
if (!this.task) {
this.task = Ext.apply({}, this.taskCfg);
Ext.util.TaskManager.start(this.task);
}
},
scroll: {
horz: function () {
var body = this.body;
var bodyLeft = body.getLeft(true);
if (this.direction == 'left') {
var bodyWidth = body.getWidth();
if (bodyLeft <= -bodyWidth) {
bodyLeft = this.el.getWidth(true);
} else {
bodyLeft -= this.unitIncrement;
}
} else {
var elWidth = this.el.getWidth(true);
if (bodyLeft >= elWidth) {
bodyLeft = -body.getWidth(true);
} else {
bodyLeft += this.unitIncrement;
}
}
body.setLeft(bodyLeft);
},
vert: function () {
var body = this.body;
var bodyTop = body.getTop(true);
if (this.direction == 'up') {
var bodyHeight = body.getHeight(true);
if (bodyTop <= -bodyHeight) {
bodyTop = this.el.getHeight(true);
} else {
bodyTop -= this.unitIncrement;
}
} else {
var elHeight = this.el.getHeight(true);
if (bodyTop >= elHeight) {
bodyTop = -body.getHeight(true);
} else {
bodyTop += this.unitIncrement;
}
}
body.setTop(bodyTop);
}
}
});
And this is how I am using it:
{
xtype: 'panel',
border: false,
height: 40,
width: 256,
layout: {
type: 'hbox',
align: 'stretch'
},
items: [{
width: 200,
direction: 'left',
xtype: 'ticker',
itemId: 'rollerPanel'
}],
listeners: {
afterrender: function (panel) {
var ticker = panel.down('ticker');
ticker.add({
tag: 'div',
cls: 'title',
html: "Ticker content."
});
}
}
}
What's wrong with the above code? What may be the reason for higher CPU usage?
The Chrome developer tools will help you profile this but it wouldn't hurt to cache some of the things like the width/height of the body and elements so that you're only reading it when you start up and not on every tick.

Exporting Rally grid information to CSV

I am trying to export rally grid data to csv. 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,
launch: function() {
this.globalStore = null;
this.count = 0;
this._addPrintButton();
list = [];
//Write app code here
this._get_stories_of_feature();
},
_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._onClickExport();
}
});
},
_onClickExport: function () { //using this function to export to csv
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");
}
},
_createStore: function(){
var me = this;
//var f = [{property: 'UserStories', operator: '!=', value: null}];
Ext.create('Rally.data.WsapiDataStore',{
autoLoad: true,
model: "PortfolioItem/Feature",
limit: 5000,
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_ID', dataIndex: 'ide'},
{text: 'Feature Name', dataIndex: 'name'},
{text: 'Feature DIteration', dataInfex: 'fDIteration'},
{text: 'Story Name', dataIndex: 'UserStories'},
{text: 'Story ID', dataIndex: 'FormattedID'},
{text: 'Story DIteration', dataIndex: 'DIteration'},
{text: 'Story DPSI', dataIndex: 'DPSI'},
{text: 'Unscheduled', dataIndex: 'Unscheduled'}
]
});
me.globalStore = this.grid;
this.down('#grid_box').add(this.grid);
}
},
_get_stories_of_feature: function(){
var me = this;
Ext.create('Rally.data.WsapiDataStore',{
autoLoad: true,
model: "hierarchicalrequirement",
limit: 5000,
fetch: ['Name','ObjectID','FormattedID','Feature','c_DIteration','c_DPSI','DragAndDropRank'],
sorters:[{
property: 'DragAndDropRank', direction: 'ASC'
}],
filters:{
property: 'Feature', operator: '!=', value:null
},
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++){
var flag;
if(data[i].data.Feature.c_DIteration==null || data[i].data.Feature.c_DIteration.toString().indexOf("*")!=-1)
flag = "YES";
else flag = "NO";
var element = {
ide: data[i].data.Feature.FormattedID,
name: data[i].data.Feature.Name,
fDIteration: data[i].data.Feature.c_DIteration,
UserStories: data[i].data.Name,
FormattedID: data[i].data.FormattedID,
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++;
}
}
if(me.count==data_length){
console.log("Building store");
//once all the stories and feature data is computed
var myStore = Ext.create("Rally.data.custom.Store",{
data: list,
pageSize: 100
});
me._showGrid(myStore);
}
}
}
});
},
exportGrid: function(grid) {
if (Ext.isIE) {
this._ieToExcel(grid);
} else {
var data = this._getCSV(grid);
var a = document.createElement('a');
a.href = 'data:attachment/csv,' + data;
a.target ='_blank';
a.download = 'myFile.csv,' + encodeURIComponent(data); ;
a.innerHTML = "Click me to download the file.";
window.location = a;
}
},
_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 = '';
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;
}
}
});
I am using the "_onClickExport" function that I read about here to export my grid data to CSV but when I execute that function, it can't find ElementId "grid_box", although I have defined it.
I was able to export with your code after making these changes:
line 31, change to
if (this.down('#grid_box')){
line 52, change to
var table = that.getComponent('grid_box');
where that is defined on the top of _onClickExport
var that = this;
line 57, and a similar line below it, replace table.innerHTML.match with table.getEl().dom.outerHTML.match
Ext.Array.each(table.getEl().dom.outerHTML.match

Loading grid only after "all" the data stores have loaded

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.

Resources