Existing Custom Rally App is producign results as expected - rally

I got the below reference of CustomHTML App for Rally and added into my custom report page in my project workspace. UI Worked, but somehow whatever simple query I give in, there is no result shown. Please review and correct me if I am doing any wrong.
Find fixed defects within certain dates
<script type="text/javascript" src="/apps/2.0rc1/sdk.js"></script>
<script type="text/javascript">
Rally.onReady(function() {
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
layout: {
type: 'vbox',
align: 'stretch'
},
items:[
{
xtype: 'panel',
layout: 'anchor',
border: true,
fieldDefaults: {
labelWidth: 40
},
defaultType: 'textfield',
bodyPadding: 5,
items: [
{
fieldLabel: 'Query',
itemId: 'queryField',
anchor:'100%',
width: 700,
height: 100,
xtype: 'textarea',
value: '{\n'+
' "_TypeHierarchy": "Defect",\n'+
'"__At": "2016-10-14T00:00:00Z"'+
'}'
},
{
fieldLabel: 'Fields',
itemId: 'fieldsField',
anchor: '100%',
width: 700,
value: "ObjectID, _ValidFrom, Name, State, Resolution"
},
{
fieldLabel: 'Sort',
itemId: 'sortField',
anchor: '100%',
width: 700,
value: "{'ObjectID' : -1, '_ValidFrom': 1}"
},
{
fieldLabel: 'Page Size',
itemId: 'pageSizeField',
anchor: '100%',
width: 700,
value: '10'
},
{
fieldLabel: 'Hydrate',
itemId: 'hydrate',
anchor: '100%',
width: 700,
value: "State, Resolution"
},
],
buttons: [
{
xtype: 'rallybutton',
text: 'Search',
itemId: 'searchButton'
}
]
},
{
xtype: 'panel',
itemId: 'gridHolder',
layout: 'fit',
height: 400
}
],
launch: function() {
var button = this.down('#searchButton');
button.on('click', this.searchClicked, this);
},
searchClicked: function(){
var queryField = this.down('#queryField');
var query = queryField.getValue();
var selectedFields = this.down('#fieldsField').getValue();
if(selectedFields){
if(selectedFields === 'true'){
selectedFields = true;
}
else{
selectedFields = selectedFields.split(', ');
}
}
var sort = this.down('#sortField').getValue();
var pageSize = this.down('#pageSizeField').getValue();
var parsedPageSize = parseInt(pageSize, 10);
// don't allow empty or 0 pagesize
pageSize = (parsedPageSize) ? parsedPageSize : 10;
var callback = Ext.bind(this.processSnapshots, this);
this.doSearch(query, selectedFields, sort, pageSize, callback);
},
createSortMap: function(csvFields){
var fields = csvFields.split(', ');
var sortMap = {};
for(var field in fields){
if(fields.hasOwnProperty(field)){
sortMap[field] = 1;
}
}
return sortMap;
},
doSearch: function(query, fields, sort, pageSize, callback){
var transformStore = Ext.create('Rally.data.lookback.SnapshotStore', {
context: {
workspace: this.context.getWorkspace(),
project: this.context.getProject()
},
fetch: fields,
find: query,
autoLoad: true,
hydrate: ["State","Resolution"],
listeners: {
scope: this,
load: this.processSnapshots
}
});
},
processSnapshots: function(store, records){
var snapshotGrid = Ext.create('Rally.ui.grid.Grid', {
title: 'Snapshots',
store: store,
columnCfgs: [
{
text: 'ObjectID',
dataIndex: 'ObjectID'
},
{
text: 'Name',
dataIndex: 'Name'
},
{
text: 'Project',
dataIndex: 'Project'
},
{
text: '_ValidFrom',
dataIndex: '_ValidFrom'
},
{
text: '_ValidTo',
dataIndex: '_ValidTo'
},
{
text: 'State',
dataIndex: 'State'
},
{
text: 'Resolution',
dataIndex: 'Resolution'
},
],
height: 400
});
var gridHolder = this.down('#gridHolder');
}
gridHolder.removeAll(true);
gridHolder.add(snapshotGrid);
});
Rally.launchApp('CustomApp', {
name: 'lbapi'
});
});
</script>
<style type="text/css">
.app {
/* Add app styles here */
}
</style>
</head>
<body></body>
</html>

There were a couple syntax errors in the posted code above. It was also written using a super old version of the sdk. I updated to the latest 2.1 and it seems to work pretty well now. More than likely most of the issues with the old app was the Lookback API request timing out. The new SDK has a longer default timeout.
<!DOCTYPE html>
<html>
<head>
<title>Lookback API Query</title>
<script type="text/javascript" src="/apps/2.1/sdk.js"></script>
<script type="text/javascript">
Rally.onReady(function() {
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
layout: {
type: 'vbox',
align: 'stretch'
},
items: [{
xtype: 'panel',
layout: 'anchor',
border: true,
fieldDefaults: {
labelWidth: 40
},
defaultType: 'textfield',
bodyPadding: 5,
items: [{
fieldLabel: 'Query',
itemId: 'queryField',
anchor: '100%',
width: 700,
height: 100,
xtype: 'textarea',
value: '{\n' +
' "_TypeHierarchy": "Defect",\n' +
'"__At": "2016-10-14T00:00:00Z"\n' +
'}'
}, {
fieldLabel: 'Fields',
itemId: 'fieldsField',
anchor: '100%',
width: 700,
value: "ObjectID, _ValidFrom, Name, State, Resolution"
}, {
fieldLabel: 'Sort',
itemId: 'sortField',
anchor: '100%',
width: 700,
value: "{'ObjectID' : -1, '_ValidFrom': 1}"
}, {
fieldLabel: 'Page Size',
itemId: 'pageSizeField',
anchor: '100%',
width: 700,
value: '10'
}, {
fieldLabel: 'Hydrate',
itemId: 'hydrate',
anchor: '100%',
width: 700,
value: "State, Resolution"
}, ],
buttons: [{
xtype: 'rallybutton',
text: 'Search',
itemId: 'searchButton'
}]
}, {
xtype: 'panel',
itemId: 'gridHolder',
layout: 'fit',
height: 400
}],
launch: function() {
var button = this.down('#searchButton');
button.on('click', this.searchClicked, this);
},
searchClicked: function() {
var queryField = this.down('#queryField');
var query = queryField.getValue();
var selectedFields = this.down('#fieldsField').getValue();
if (selectedFields) {
if (selectedFields === 'true') {
selectedFields = true;
} else {
selectedFields = selectedFields.split(', ');
}
}
var sort = this.down('#sortField').getValue();
var pageSize = this.down('#pageSizeField').getValue();
var parsedPageSize = parseInt(pageSize, 10);
// don't allow empty or 0 pagesize
pageSize = (parsedPageSize) ? parsedPageSize : 10;
var callback = Ext.bind(this.processSnapshots, this);
this.doSearch(query, selectedFields, sort, pageSize, callback);
},
createSortMap: function(csvFields) {
var fields = csvFields.split(', ');
var sortMap = {};
for (var field in fields) {
if (fields.hasOwnProperty(field)) {
sortMap[field] = 1;
}
}
return sortMap;
},
doSearch: function(query, fields, sort, pageSize, callback) {
var transformStore = Ext.create('Rally.data.lookback.SnapshotStore', {
context: {
workspace: this.context.getWorkspace(),
project: this.context.getProject()
},
fetch: fields,
pageSize: pageSize,
find: query,
autoLoad: true,
hydrate: ["State", "Resolution"],
listeners: {
scope: this,
load: this.processSnapshots
}
});
},
processSnapshots: function(store, records) {
var snapshotGrid = Ext.create('Rally.ui.grid.Grid', {
title: 'Snapshots',
store: store,
columnCfgs: [{
text: 'ObjectID',
dataIndex: 'ObjectID'
}, {
text: 'Name',
dataIndex: 'Name'
}, {
text: 'Project',
dataIndex: 'Project'
}, {
text: '_ValidFrom',
dataIndex: '_ValidFrom'
}, {
text: '_ValidTo',
dataIndex: '_ValidTo'
}, {
text: 'State',
dataIndex: 'State'
}, {
text: 'Resolution',
dataIndex: 'Resolution'
}, ],
height: 400
});
var gridHolder = this.down('#gridHolder');
gridHolder.removeAll(true);
gridHolder.add(snapshotGrid);
}
});
Rally.launchApp('CustomApp', {
name: 'lbapi'
});
});
</script>
<style type="text/css">
.app {
/* Add app styles here */
}
</style>
</head>
<body></body>
</html>

Related

How to show task revisions in custom grid?

I have a custom grid that displays open tasks filtered by (Owner = some-user#company.com).
I would like to include the last revision for each task in a custom grid, but the Revision column is not available on the settings dialog. How to traverse from Revision History to individual revisions?
It can't be done with a custom grid, but can be done with a custom code. Here is an app example that populates a grid based on a selection in the UserSearchComboBox , and then displays the last revision of a selected task on a click event.
You may copy the html file into a custom page from this github repo:
Here is the js file:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
var context = this.getContext ();
var currentProject = context.getProject()._ref;
var panel = Ext.create('Ext.panel.Panel', {
layout: 'hbox',
itemId: 'parentPanel',
componentCls: 'panel',
items: [
{
xtype: 'rallyusersearchcombobox',
fieldLabel: 'SELECT USER:',
project: currentProject,
listeners:{
ready: function(combobox){
this._onUserSelected(combobox.getRecord());
},
select: function(combobox){
if (this.down('#c').html !== 'No task is selected') {
Ext.getCmp('c').update('No task is selected');
}
this._onUserSelected(combobox.getRecord());
},
scope: this
}
},
{
xtype: 'panel',
title: 'Tasks',
width: 600,
itemId: 'childPanel1'
},
{
xtype: 'panel',
title: 'Last Revision',
width: 600,
itemId: 'childPanel2'
}
],
});
this.add(panel);
this.down('#childPanel2').add({
id: 'c',
padding: 10,
maxWidth: 600,
maxHeight: 400,
overflowX: 'auto',
overflowY: 'auto',
html: 'No task is selected'
});
},
_onUserSelected:function(record){
var user = record.data['_ref'];
if(user){
var filter = Ext.create('Rally.data.QueryFilter', {
property: 'Owner',
operator: '=',
value: user
});
filter = filter.and({
property: 'State',
operator: '<',
value: 'Completed'
});
filter.toString();
Ext.create('Rally.data.WsapiDataStore', {
model: 'Task',
fetch: [ 'DragAndDropRank','FormattedID','Name','State','RevisionHistory'],
autoLoad: true,
filters : [filter],
sorters:[
{
property: 'DragAndDropRank',
direction: 'ASC'
}
],
listeners: {
load: this._onTaskDataLoaded,
scope: this
}
});
}
},
_onTaskDataLoaded: function(store, data) {
var customRecords = [];
Ext.Array.each(data, function(task, index) {
customRecords.push({
_ref: task.get('_ref'),
FormattedID: task.get('FormattedID'),
Name: task.get('Name'),
RevisionID: Rally.util.Ref.getOidFromRef(task.get('RevisionHistory')),
});
}, this);
this._updateGrid(store,data);
},
_updateGrid: function(store, data){
if (!this.down('#g')) {
this._createGrid(store,data);
}
else{
this.down('#g').reconfigure(store);
}
},
_createGrid: function(store,data){
var that = this;
var g = Ext.create('Rally.ui.grid.Grid', {
id: 'g',
store: store,
enableRanking: true,
columnCfgs: [
{text: 'Formatted ID', dataIndex: 'FormattedID'},
{text: 'Name', dataIndex: 'Name'},
{text: 'State', dataIndex: 'State'},
{text: 'Last Revision',
renderer: function (v, m, r) {
var id = Ext.id();
Ext.defer(function () {
Ext.widget('button', {
renderTo: id,
text: 'see',
width: 50,
handler: function () {
console.log('r', r.data);
that._getRevisionHistory(data, r.data);
}
});
}, 50);
return Ext.String.format('<div id="{0}"></div>', id);
}
}
],
height: 400,
});
this.down('#childPanel1').add(g);
},
_getRevisionHistory: function(taskList, task) {
this._task = task;
this._revisionModel = Rally.data.ModelFactory.getModel({
type: 'RevisionHistory',
scope: this,
success: this._onModelCreated
});
},
_onModelCreated: function(model) {
model.load(Rally.util.Ref.getOidFromRef(this._task.RevisionHistory._ref),{
scope: this,
success: this._onModelLoaded
});
},
_onModelLoaded: function(record, operation) {
record.getCollection('Revisions').load({
fetch: true,
scope: this,
callback: function(revisions, operation, success) {
this._onRevisionsLoaded(revisions, record);
}
});
},
_onRevisionsLoaded: function(revisions, record) {
var lastRev = _.first(revisions).data;
console.log('_onRevisionsLoaded: ',lastRev.Description, lastRev.RevisionNumber, lastRev.CreationDate );
this._displayLastRevision(lastRev.Description,lastRev.RevisionNumber, lastRev.CreationDate );
},
_displayLastRevision:function(desc, num, date){
Ext.getCmp('c').update('<b>' + this._task.FormattedID + '</b><br/><b>Revision CreationDate: </b>' + date +'<br /><b>Description:</b>' + desc + '<br /><b>Revision Number:</b>' + num + '<br />');
}
});

Rally Lookback call in custome HTML app

Rally Lookback API:
I need to query using the Rally Lookback API in a custom HTML App inside Rally.
I dont know how to call the Lookback API, in the overall HTML.
Could anyone please send me a sample App HTML ?
Lookback API works with App SDK 2.
Rally App SDK 2.0 RC1 documentation on Lookback API and a link to Lookback API manual are available here:
This app builds a grid of defects fixed between certain dates. You may directly modify the default query after you deploy the app in Rally.
<!DOCTYPE html>
<html>
<head>
<title>Find fixed defects within certain dates</title>
<script type="text/javascript" src="/apps/2.0rc1/sdk.js"></script>
<script type="text/javascript">
Rally.onReady(function() {
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
layout: {
type: 'vbox',
align: 'stretch'
},
items:[
{
xtype: 'panel',
layout: 'anchor',
border: true,
fieldDefaults: {
labelWidth: 40
},
defaultType: 'textfield',
bodyPadding: 5,
items: [
{
fieldLabel: 'Query',
itemId: 'queryField',
anchor:'100%',
width: 700,
height: 100,
xtype: 'textarea',
value: '{\n'+
' "State":"Fixed",\n'+
'"_PreviousValues.State":{$gte:"Submitted"},\n'+
'"_ValidFrom":{$gte:"2013-06-01TZ",$lt:"2013-07-01TZ"}\n'+
'}'
},
{
fieldLabel: 'Fields',
itemId: 'fieldsField',
anchor: '100%',
width: 700,
value: "ObjectID, _ValidFrom, Name, State, Resolution"
},
{
fieldLabel: 'Sort',
itemId: 'sortField',
anchor: '100%',
width: 700,
value: "{'ObjectID' : -1, '_ValidFrom': 1}"
},
{
fieldLabel: 'Page Size',
itemId: 'pageSizeField',
anchor: '100%',
width: 700,
value: '10'
},
{
fieldLabel: 'Hydrate',
itemId: 'hydrate',
anchor: '100%',
width: 700,
value: "State, Resolution"
},
],
buttons: [
{
xtype: 'rallybutton',
text: 'Search',
itemId: 'searchButton'
}
]
},
{
xtype: 'panel',
itemId: 'gridHolder',
layout: 'fit',
height: 400
}
],
launch: function() {
var button = this.down('#searchButton');
button.on('click', this.searchClicked, this);
},
searchClicked: function(){
var queryField = this.down('#queryField');
var query = queryField.getValue();
var selectedFields = this.down('#fieldsField').getValue();
if(selectedFields){
if(selectedFields === 'true'){
selectedFields = true;
}
else{
selectedFields = selectedFields.split(', ');
}
}
var sort = this.down('#sortField').getValue();
var pageSize = this.down('#pageSizeField').getValue();
var parsedPageSize = parseInt(pageSize, 10);
// don't allow empty or 0 pagesize
pageSize = (parsedPageSize) ? parsedPageSize : 10;
var callback = Ext.bind(this.processSnapshots, this);
this.doSearch(query, selectedFields, sort, pageSize, callback);
},
createSortMap: function(csvFields){
var fields = csvFields.split(', ');
var sortMap = {};
for(var field in fields){
if(fields.hasOwnProperty(field)){
sortMap[field] = 1;
}
}
return sortMap;
},
doSearch: function(query, fields, sort, pageSize, callback){
var transformStore = Ext.create('Rally.data.lookback.SnapshotStore', {
context: {
workspace: this.context.getWorkspace(),
project: this.context.getProject()
},
fetch: fields,
find: query,
autoLoad: true,
hydrate: ["State","Resolution"],
listeners: {
scope: this,
load: this.processSnapshots
}
});
},
processSnapshots: function(store, records){
var snapshotGrid = Ext.create('Rally.ui.grid.Grid', {
title: 'Snapshots',
store: store,
columnCfgs: [
{
text: 'ObjectID',
dataIndex: 'ObjectID'
},
{
text: 'Name',
dataIndex: 'Name'
},
{
text: 'Project',
dataIndex: 'Project'
},
{
text: '_ValidFrom',
dataIndex: '_ValidFrom'
},
{
text: '_ValidTo',
dataIndex: '_ValidTo'
},
{
text: 'State',
dataIndex: 'State'
},
{
text: 'Resolution',
dataIndex: 'Resolution'
},
],
height: 400
});
var gridHolder = this.down('#gridHolder');
gridHolder.removeAll(true);
gridHolder.add(snapshotGrid);
}
});
Rally.launchApp('CustomApp', {
name: 'lbapi'
});
});
</script>
<style type="text/css">
.app {
/* Add app styles here */
}
</style>
</head>
<body></body>
</html>

Remove a record from a Grid Locally

I have a Grid in a Window. When i click on a row of that window and click on the remove button, that row should get removed from the window. (I think i will have to remove it from Store and reload the grid, so the changes will be picked)
I am unable to get the click event and remove the row from the store. I have added the button for this but not able to get the Grid record and remove it from store and reloading it.
My code is as follows;
Ext.define('MyApp.view.Boy', {
extend: 'Ext.window.Window',
alias: 'widget.boy',
height: 800,
width: 900,
layout: {
type: 'absolute'
},
initComponent: function() {
var me = this;
Ext.applyIf(me, {
items: [
{
xtype: 'gridpanel',
height: 500,
width: 800,
title: 'My Grid Panel',
store: 'School',
viewConfig: {
},
columns: [
{
xtype: 'gridcolumn',
dataIndex: 'Id',
text: 'id'
},
{
xtype: 'gridcolumn',
dataIndex: 'name',
text: 'name'
}
]
},
{
xtype: 'button',
height: 40,
width: 150,
text: 'Remove',
listeners: {
click: {
fn: me.removebuttonclick,
scope: me
}
}
}
]
});
me.callParent(arguments);
},
removebuttonclick: function(button, e, options) {
console.log('removebuttonclick');
}
});
Something like:
Ext.define('MyApp.view.Boy', {
extend: 'Ext.window.Window',
alias: 'widget.boy',
height: 800,
width: 900,
layout: {
type: 'absolute'
},
initComponent: function() {
var me = this;
var this.grid = Ext.widget({
xtype: 'gridpanel',
height: 500,
width: 800,
title: 'My Grid Panel',
store: 'School',
viewConfig: {
},
columns: [
{
xtype: 'gridcolumn',
dataIndex: 'Id',
text: 'id'
},
{
xtype: 'gridcolumn',
dataIndex: 'name',
text: 'name'
}
]
});
Ext.applyIf(me, {
items: [
this.grid, //oopsie
{
xtype: 'button',
height: 40,
width: 150,
text: 'Remove',
listeners: {
click: {
fn: me.removebuttonclick,
scope: me
}
}
}
]
});
me.callParent(arguments);
},
removebuttonclick: function(button, e, options) {
var me = this;
Ext.Array.each(this.grid.getSelectionModel().selected,function(record, index,selectedRows){
me.grid.getStore().remove(record);
});
}
});

Changing the Detail Container in a NestedList?

In a small program that I have, I'm trying to have custom containers for every leaf node of my Nested List.
Here are a couple arbitrary example containers that I'm trying to test with:
Ext.define('DetailContainer1', {
extend: 'Ext.Container',
xtype: 'detail-container1',
layout: {
type: 'vbox'
},
height: 300,
style: 'background-color: #a9a9a9;',
// flex: 1,
items: [{
html: 'Detail Container1'
}]
});
Ext.define('DetailContainer2', {
extend: 'Ext.Container',
xtype: 'detail-container2',
layout: {
type: 'vbox'
},
height: 300,
style: 'background-color: #c9c9c9;',
// flex: 1,
items: [{
html: 'Detail Container2',
flex: 1
}, {
xtype: 'button',
text: 'Hit me!',
flex: 1
}]
});
How can I switch in the new containers when the user clicks on the leaf node?
This action should happen in onLeafItemTap(). Btw the initial container (#2) isn't showing at the moment. Is this a layout issue?
Here's some idea of what the screen should look like:
Complete source:
Ext.Loader.setConfig({
enabled: true
});
Ext.define('DetailContainer1', {
extend: 'Ext.Container',
xtype: 'detail-container1',
layout: {
type: 'vbox'
},
height: 300,
style: 'background-color: #a9a9a9;',
// flex: 1,
items: [{
html: 'Detail Container1'
}]
});
Ext.define('DetailContainer2', {
extend: 'Ext.Container',
xtype: 'detail-container2',
layout: {
type: 'vbox'
},
height: 300,
style: 'background-color: #c9c9c9;',
// flex: 1,
items: [{
html: 'Detail Container2',
flex: 1
}, {
xtype: 'button',
text: 'Hit me!',
flex: 1
}]
});
Ext.define('ListItem', {
extend: 'Ext.data.Model',
config: {
fields: ['text']
}
});
Ext.define('Sencha.view.MainView', {
extend: 'Ext.Container',
xtype: 'mainview',
layout: {
type: 'hbox'
},
initialize: function() {
this.treeStore = Ext.create('Ext.data.TreeStore', {
model: 'ListItem',
defaultRootProperty: 'items',
root: {
items: [{
text: 'Containers',
items: [{
text: 'Detail #1',
leaf: true
}, {
text: 'Detail #2',
leaf: true
}]
}]
}
});
this.detailContainer = Ext.create("DetailContainer2", {});
this.nestedList = Ext.create('Ext.NestedList', {
docked: 'left',
width: 300,
flex: 1,
store: this.treeStore,
detailCard: true,
detailContainer: this.detailContainer,
listeners: {
scope: this,
leafitemtap: this.onLeafItemTap
}
});
this.setItems([this.detailContainer, this.nestedList]);
},
onLeafItemTap: function(nestedList, list, index, node, record, e) {
var detailCard = nestedList.getDetailCard();
// nestedList.setDetailContainer(Ext.create("DetailContainer1", {}))
// detailCard.setHtml(record.get('text') + "...");
}
});
Ext.application({
launch: function() {
var container = Ext.create("Ext.Container", {
layout: {
type: 'hbox'
},
items: [{
xtype: 'mainview'
}]
});
Ext.Viewport.add(container);
}
});
Finally I've figured out the proper way to solve your problem.
Some explanations:
If you want to display "customized detailContainer" at the right side of your hbox, it's quite obvious that you should disable detailCard config for your Ext.NestedList because it's designed to display inline (i.e. take place of your Ext.NestedList).
When using Ext.define, everything should be included in config (except extend, xtype, alias, id, so in this case, layout has to be put in config).
flex should be defined in config as well.
At leafitemtap event, simply update your detailContainer config and remove/add it again as it would not be updated dynamically.
Please take a look at modified code snippet below, it works perfectly for me.
Ext.Loader.setConfig({ enabled: true });
Ext.define('DetailContainer1', {
extend: 'Ext.Container',
xtype: 'detail-container1',
config: {
flex: 1,
layout: {
type: 'vbox'
},
style: 'background-color: #a9a9a9;',
items: [
{html: 'Detail Container1'}
]
}
});
Ext.define('DetailContainer2', {
extend: 'Ext.Container',
xtype: 'detail-container2',
config: {
flex: 1,
layout: {
type: 'vbox'
},
style: 'background-color: #c9c9c9;',
items: [
{html: 'Detail Container2', flex: 1},
{xtype: 'button', text: 'Hit me!', flex: 1}
]
}
});
Ext.define('ListItem', {
extend: 'Ext.data.Model',
config: {
fields: ['text']
}
});
Ext.define('Sencha.view.MainView', {
extend: 'Ext.Container',
xtype: 'mainview',
id: 'mainview',
config: {
layout: {
type: 'hbox'
},
},
initialize: function() {
this.treeStore = Ext.create('Ext.data.TreeStore', {
model: 'ListItem',
defaultRootProperty: 'items',
root: {
items: [
{
text: 'Containers',
items: [
{ text: 'Detail #1', leaf: true },
{ text: 'Detail #2', leaf: true }
]
}
]
}
});
this.detailContainer = Ext.create("DetailContainer2");
this.nestedList = Ext.create('Ext.NestedList', {
flex: 1,
store: this.treeStore,
listeners: {
scope: this,
leafitemtap: this.onLeafItemTap
}
});
this.setItems([this.nestedList, this.detailContainer]);
},
onLeafItemTap: function(nestedList, list, index, node, record, e) {
mainview = Ext.getCmp('mainview');
if (index==0) {
mainview.detailContainer = Ext.create("DetailContainer1");
} else {
mainview.detailContainer = Ext.create("DetailContainer2");
}
mainview.removeAt(1);
mainview.add(mainview.detailContainer);
}
});
Ext.application({
launch: function() {
Ext.Viewport.add(
Ext.create("Ext.Container", {
layout: {
type: 'card'
},
items: [
{ xtype : 'mainview'}
]
}));
}
});

Finding the row id in a gridpanel

How do I find the row index in a gridpanel that has comboboxes in on of the columns and is used to update the store/database through and ajax proxy? I'm using Ext.grid.plugin.CellEditing. Here's my code. Thanks for looking at it!
Ext.Loader.setConfig({
enabled: true
});
Ext.Loader.setPath('Ext.ux', '/extjs4/examples/ux');
Ext.require([
'Ext.layout.container.Fit',
'Ext.grid.*',
'Ext.data.*',
'Ext.util.*',
'Ext.panel.*',
'Ext.selection.CellModel',
'Ext.state.*',
'Ext.form.*',
'Ext.ux.CheckColumn'
]);
Ext.define('Ext.app.HirePlanGrid', {
extend: 'Ext.panel.Panel',
alias: 'widget.hirePlangrid'
,hireplanstoreId: 'hireplanstore'
,hiremonthstoreId: 'hiremonthstore'
,renderMonth : function (value, p, record) {
var fkStore = Ext.getStore(this.up('hirePlangrid').hiremonthstoreId);
var rec = fkStore.findRecord("MONTH_ID", value);
//return rec.get("ABBREVIATED_MONTH");
}
,initComponent: function() {
this.editing = Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 2
});
var objMonthStore = Ext.getStore(this.hiremonthstoreId);
objMonthStore.load();
var objStore = Ext.getStore(this.hireplanstoreId);
objStore.setProxy( {
type: 'ajax',
url: 'hireplan.cfc?method=getEmployees'
});
objStore.load();
var onDeleteClick = function(field, value, options) {
// var objPanel = this.down('gridpanel');
var selection = Ext.getCmp('grid').getSelectionModel().getSelection();
alert(selection);
// var selection = getView().getSelectionModel().getSelection()[r];
if (value) {
alert(value);
objStore.remove(value);
objStore.sync();
}
};
var onUpdateClick = function(field, value, options) {
alert('field= ' + field + ' value= '+ value+ 'options= '+ options);
objStore.update(objStore.getAt(value));
onSync();
};
Ext.apply(this, {
layout: 'fit',
width: 800,
//height: 1500,
items: [{
xtype: 'grid',
id : 'gridgrid',
//height: 300,
store: objStore,
selModel: { selType: 'cellmodel' },
selType : 'rowmodel',
plugins: [this.editing],
// plugins: [cellEditing],
columnLines: true,
viewConfig: {stripeRows: true},
//loadMask: true,
disableSelection: true,
listeners: {
selectionchange: function(selModel, selected) {
var selection = Ext.getCmp('gridgrid').getSelectionModel().getSelection();
}
},
columns: [
{ header: 'rowid', hidden: true, dataIndex: 'ROWID'},
{
header: 'Indicator',
id: 'chkcolumn',
xtype: 'checkcolumn',
dataIndex: 'CHK_COL',
editor: {
xtype: 'checkbox',
cls: 'x-grid-checkheader-editor'
},
listeners : checkchange : function(column, recordIndex, checked)
{
alert('checked rindex= ' + recordIndex);
onDeleteClick(column, recordIndex, checked);
//or send a request
}
}
},
{
id: 'employeeid',
header: 'employeeid',
width: 80,
hidden: false,
sortable: true,
dataIndex: 'EMPLOYEEID',
flex: 1
},
{
id: 'NATIONALIDNUMBER',
header: 'NATIONALIDNUMBER',
width: 80,
sortable: true,
dataIndex: 'NATIONALIDNUMBER',
flex: 1
},
{
id: 'MARITALSTATUS',
header: 'MARITALSTATUS',
width: 80,
sortable: true,
dataIndex: 'MARITALSTATUS',
flex: 1
},
{
id: 'PotentialforInsourcingKV',
header: 'Potential for Insourcing',
width: 30,
sortable: true,
dataIndex: 'POTENTIAL_FOR_INSOURCING',
flex: 1,
editor: {
id: 'thiscombo',
xtype: 'combobox',
typeAhead: true,
triggerAction: 'all',
selectOnTab: true,
store: [
['1', 'Yes'],
['0', 'No']
],
lazyRender: true,
listClass: 'x-combo-list-small',
listeners: { 'select' : function(r){
var selval = Ext.getCmp("thiscombo").getValue();
//var recval = Ext.getCmp("grid").getValue();
//var selection = getView().getSelectionModel().getSelection()[r]
alert(selval + ' ' + rowIdx);
// onUpdateClick(editor, rowIdx, value );
}
},
}
},
{
id: 'ABBREVIATED_MONTH',
header: 'ABBREVIATED_MONTH',
width: 80,
sortable: true,
dataIndex: 'ABBREVIATED_MONTH',
flex: 1,
renderer: this.renderMonth,
field: {
xtype: 'combobox',
store: Ext.getStore(this.hiremonthstoreId),
typeAhead: true,
lazyRender: true,
queryMode: 'local',
displayField: 'ABBREVIATED_MONTH',
valueField: 'MONTH_ID',
listClass: 'x-combo-list-small'
}
},
{
id: 'SALARIEDFLAG',
header: 'SALARIEDFLAG',
width: 80,
sortable: true,
dataIndex: 'SALARIEDFLAG',
flex: 1
}],
features: [{
ftype: 'rowbody'
}]
}]
});
this.callParent(arguments);
//this.getSelectionModel().on('selectionchange', this.onSelectChange, this);
}, //initComponent
getSelectedRowIndex : function(){
var r, s;
r = this.getView().getSelectionModel().getSelection();
s = this.getStore();
return s.indexOf(r[0]);
},
onSelectChange: function(selModel, selections){
this.down('#delete').setDisabled(selections.length === 0);
},
onSync: function() {
objStore.sync();
},
viewConfig: {},
});
I read in another post that what I needed to do was add a listener to this.cellediting and use the 'beforeedit' event to find the row index, and then set to variables:
var rIdx = '';
var cIdx = '';
this.cellEditing = Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1,
listeners: {
'beforeedit': function(e){
var me = this;
var allowed = !!me.isEditAllowed;
if (!me.isEditAllowed)
Ext.Msg.confirm('confirm', 'Are you sure you want edit?', function(btn){
if (btn !== 'yes')
return;
me.isEditAllowed = true;
me.startEditByPosition({
row: e.rowIdx,
column: e.colIdx
});
});
rIdx = e.rowIdx;
cIdx = e.colIdx;
alert('rIdx= ' + rIdx + ' cIdx = ' + cIdx);
return allowed;
},
'edit': function(e){
this.isEditAllowed = true;
}
}
});