rally combobox doesn't show properly as expected - rally

I want to create a combobox listing all user story's formatted id.
The js is somethiing like below:
Ext.define('CustomApp', {
extend : 'Rally.app.App',
componentCls : 'app',
launch : function() {
var usComboBox = Ext.create('Ext.Container', {
items : [ {
xtype : 'rallycombobox',
storeConfig : {
autoLoad : true,
model : 'User story',
displayField:'FormattedId',
}
} ],
});
this.add(usComboBox);
},
});
First of all, the comboBox cannot show any formatted id;
Secondly, if I removed the "displayField" config, I can see list of user story names but somehow it's not always showing like that. Sometime if I refresh the page, the list may not be shown.
I tested this by changing the App.js file and view App-debug.html file in Chrome since Chrome extension terminal couldn't be installed properly in Windows 7. Is this the right way to do?

You may use filterFieldName of rallymultiobjectpicker, and fetch FormattedID. It currently does not automatically add the value in filterFieldName to the fetch.
var box = Ext.create('Ext.Container', {
items: [{
xtype: 'rallymultiobjectpicker',
modelType: 'userstory',
filterFieldName: 'FormattedID',
storeConfig: {
fetch:['FormattedID']
}
}]
});
this.add(box);

Related

rally iteration combobox returns empty

I'm new to rally app SDK and trying to do the tutorials (from Youtube and from rally site)
when I'm trying to create an iterationComboBox the object is created but with no values ("There are no Iterations defined").
i tried to run both the video tutorial code from github (session_4_interactive_grid)
// Custom Rally App that displays Defects in a grid and filter by Iteration and/or Severity.
//
// Note: various console debugging messages intentionally kept in the code for learning purposes
Ext.define('CustomApp', {
extend: 'Rally.app.App', // The parent class manages the app 'lifecycle' and calls launch() when ready
componentCls: 'app', // CSS styles found in app.css
defectStore: undefined, // app level references to the store and grid for easy access in various methods
defectGrid: undefined,
// Entry Point to App
launch: function() {
console.log('our second app'); // see console api: https://developers.google.com/chrome-developer-tools/docs/console-api
this.pulldownContainer = Ext.create('Ext.container.Container', { // this container lets us control the layout of the pulldowns; they'll be added below
id: 'pulldown-container-id',
layout: {
type: 'hbox', // 'horizontal' layout
align: 'stretch'
}
});
this.add(this.pulldownContainer); // must add the pulldown container to the app to be part of the rendering lifecycle, even though it's empty at the moment
this._loadIterations();
},
// create iteration pulldown and load iterations
_loadIterations: function() {
this.iterComboBox = Ext.create('Rally.ui.combobox.IterationComboBox', {
fieldLabel: 'Iteration',
labelAlign: 'right',
width: 300,
listeners: {
ready: function(combobox) { // on ready: during initialization of the app, once Iterations are loaded, lets go get Defect Severities
this._loadSeverities();
},
select: function(combobox, records) { // on select: after the app has fully loaded, when the user 'select's an iteration, lets just relaod the data
this._loadData();
},
scope: this
}
});
this.pulldownContainer.add(this.iterComboBox); // add the iteration list to the pulldown container so it lays out horiz, not the app!
},
// create defect severity pulldown then load data
_loadSeverities: function() {
this.severityComboBox = Ext.create('Rally.ui.combobox.FieldValueComboBox', {
model: 'Defect',
field: 'Severity',
fieldLabel: 'Severity',
labelAlign: 'right',
listeners: {
ready: function(combobox) { // this is the last 'data' pulldown we're loading so both events go to just load the actual defect data
this._loadData();
},
select: function(combobox, records) {
this._loadData();
},
scope: this // <--- don't for get to pass the 'app' level scope into the combo box so the async event functions can call app-level func's!
}
});
this.pulldownContainer.add(this.severityComboBox); // add the severity list to the pulldown container so it lays out horiz, not the app!
},
// Get data from Rally
_loadData: function() {
var selectedIterRef = this.iterComboBox.getRecord().get('_ref'); // the _ref is unique, unlike the iteration name that can change; lets query on it instead!
var selectedSeverityValue = this.severityComboBox.getRecord().get('value'); // remember to console log the record to see the raw data and relize what you can pluck out
console.log('selected iter', selectedIterRef);
console.log('selected severity', selectedSeverityValue);
var myFilters = [ // in this format, these are AND'ed together; use Rally.data.wsapi.Filter to create programatic AND/OR constructs
{
property: 'Iteration',
operation: '=',
value: selectedIterRef
},
{
property: 'Severity',
operation: '=',
value: selectedSeverityValue
}
];
// if store exists, just load new data
if (this.defectStore) {
console.log('store exists');
this.defectStore.setFilter(myFilters);
this.defectStore.load();
// create store
} else {
console.log('creating store');
this.defectStore = Ext.create('Rally.data.wsapi.Store', { // create defectStore on the App (via this) so the code above can test for it's existence!
model: 'Defect',
autoLoad: true, // <----- Don't forget to set this to true! heh
filters: myFilters,
listeners: {
load: function(myStore, myData, success) {
console.log('got data!', myStore, myData);
if (!this.defectGrid) { // only create a grid if it does NOT already exist
this._createGrid(myStore); // if we did NOT pass scope:this below, this line would be incorrectly trying to call _createGrid() on the store which does not exist.
}
},
scope: this // This tells the wsapi data store to forward pass along the app-level context into ALL listener functions
},
fetch: ['FormattedID', 'Name', 'Severity', 'Iteration'] // Look in the WSAPI docs online to see all fields available!
});
}
},
// Create and Show a Grid of given defect
_createGrid: function(myDefectStore) {
this.defectGrid = Ext.create('Rally.ui.grid.Grid', {
store: myDefectStore,
columnCfgs: [ // Columns to display; must be the same names specified in the fetch: above in the wsapi data store
'FormattedID', 'Name', 'Severity', 'Iteration'
]
});
this.add(this.defectGrid); // add the grid Component to the app-level Container (by doing this.add, it uses the app container)
}
});
and the code from Rally site (https://help.rallydev.com/apps/2.0rc2/doc/#!/guide/first_app).
// Custom Rally App that displays Defects in a grid and filter by Iteration and/or Severity.
//
// Note: various console debugging messages intentionally kept in the code for learning purposes
Ext.define('CustomApp', {
extend: 'Rally.app.App', // The parent class manages the app 'lifecycle' and calls launch() when ready
componentCls: 'app', // CSS styles found in app.css
launch: function() {
this.iterationCombobox = this.add({
xtype: 'rallyiterationcombobox',
listeners: {
change: this._onIterationComboboxChanged,
ready: this._onIterationComboboxLoad,
scope: this
}
});
},
_onIterationComboboxLoad: function() {
var addNewConfig = {
xtype: 'rallyaddnew',
recordTypes: ['User Story', 'Defect'],
ignoredRequiredFields: ['Name', 'ScheduleState', 'Project'],
showAddWithDetails: false,
listeners: {
beforecreate: this._onBeforeCreate,
scope: this
}
};
this.addNew = this.add(addNewConfig);
var cardBoardConfig = {
xtype: 'rallycardboard',
types: ['Defect', 'User Story'],
attribute: 'ScheduleState',
storeConfig: {
filters: [this.iterationCombobox.getQueryFromSelected()]
}
};
this.cardBoard = this.add(cardBoardConfig);
},
_onBeforeCreate: function(addNewComponent, record) {
record.set('Iteration', this.iterationCombobox.getValue());
},
_onIterationComboboxChanged: function() {
var config = {
storeConfig: {
filters: [this.iterationCombobox.getQueryFromSelected()]
}
};
this.cardBoard.refresh(config);
}
});
both give me an empty iteration box.
i'm getting user stories data when running code from session 3 on the video,by creating a store of user stories. I googled it and searched here for duplicates but with no successso far, so what can be the issue?
Thanks!
I copied the code you posted, both apps, without making any changes, ran the apps and the iteration box was populated in both cases. It's not the code.
Maybe if you are getting "There are no Iterations defined" there are no iterations in your project?
The second code you posted which you copied from the example in the documentation has a bug in it and even though the iteration combobox is populated, the cards do not show on a board. DevTools console has error: "Cannot read property 'refresh' of undefined".
I have a working version of this app in this github repo.

Rally text field access issue

Developing custom HTML app using Rally:
I want to present a text box and pull value from the enterd data in it. How do i access the text in a rallytextfield while creating a custom html app using App SDK ?
Make sure you use the API docs provided - you can find information about a rallytextbox here.
Specifically, there is a method called:
getValue()
That you will find in the documentation - I think that is what you are looking for.
Here is a piece of code which is causing problems on this:
How do i access the value of the datepicker, i tried the .getValue. It is not able to get the value.Please help
Ext.define('CustomApp', {
extend: 'Rally.app.App', componentCls: 'app', id: 'appid', launch: function () {
var datepickerfrom = Ext.create('Ext.Container', {
id: 'datepickerfrom',
items: [{
xtype: 'rallytextfield',
fieldLabel: 'Enter text: ',
labelWidth: 10
}],
renderTo: Ext.getBody().dom
});
this.add(datepickerfrom);
button = {
xtype: 'rallybutton',
text: 'Generate Report',
handler: function () {
console.clear();
console.log(datepickerfrom.getRawValue());
},
};
});

Refreshing rallycombobox after adding new rollup

I have a rallycombobox that is configured to show the Rollups in the current scope:
App.down('#associateWith').add({
xtype : 'rallycombobox',
fieldLabel : 'Dropdown',
id : 'association',
allowNoEntry : true,
storeConfig : {
autoLoad : true,
model : 'PortfolioItem/Rollup'
}
});
This app also has an addnew component that enables users to add a new PortfolioItem/Rollup - If they add a new one, then I want to refresh this combobox to have that rollup as an option as well. I was not able to find a way to refresh the combobox in the API docs, so I am doing the messy version - which involves creating and destroying the combobox quite frequently.
I tried doing a:
setStoreConfig(...);
But that did not seem to refresh the data at all. Any way to accomplish this without destroying and re-creating?
The easiest way to to this is to hook into the AddNew's create event. It will give you a record of the newly created Rollup, and from there you can place it in your ComboBox's store
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
this.combobox = this.add({
xtype: 'rallycombobox',
allowNoEntry: true,
storeConfig: {
autoLoad: true,
model: 'PorfolioItem/Rollup'
}
});
this.add({
xtype: 'rallyaddnew',
recordTypes: ['PortfolioItem/Rollup'],
listeners: {
create: this._onCreate,
scope: this
}
});
},
_onCreate: function(addNew, record) {
this.combobox.getStore().add(record);
}
});

Nested grid in ExtJS 4.1 using Row Expander

On the front-end I have a Calls grid. Each Call may have one or more Notes associated with it, so I want to add the ability to drill down into each Calls grid row and display related Notes.
On the back-end I am using Ruby on Rails, and the Calls controller returns a Calls json recordset, with nested Notes in each row. This is done using to_json(:include => blah), in case you're wondering.
So the question is: how do I add a sub-grid (or just a div) that gets displayed when a user double-clicks or expands a row in the parent grid? How do I bind nested Notes data to it?
I found some answers out there that got me part of the way where I needed to go. Thanks to those who helped me take it from there.
I'll jump straight into posting code, without much explanation. Just keep in mind that my json recordset has nested Notes records. On the client it means that each Calls record has a nested notesStore, which contains the related Notes. Also, I'm only displaying one Notes column - content - for simplicity.
Ext.define('MyApp.view.calls.Grid', {
alias: 'widget.callsgrid',
extend: 'Ext.grid.Panel',
...
initComponent: function(){
var me = this;
...
var config = {
...
listeners: {
afterrender: function (grid) {
me.getView().on('expandbody',
function (rowNode, record, expandbody) {
var targetId = 'CallsGridRow-' + record.get('id');
if (Ext.getCmp(targetId + "_grid") == null) {
var notesGrid = Ext.create('Ext.grid.Panel', {
forceFit: true,
renderTo: targetId,
id: targetId + "_grid",
store: record.notesStore,
columns: [
{ text: 'Note', dataIndex: 'content', flex: 0 }
]
});
rowNode.grid = notesGrid;
notesGrid.getEl().swallowEvent(['mouseover', 'mousedown', 'click', 'dblclick', 'onRowFocus']);
notesGrid.fireEvent("bind", notesGrid, { id: record.get('id') });
}
});
}
},
...
};
Ext.apply(me, Ext.apply(me.initialConfig, config));
me.callParent(arguments);
},
plugins: [{
ptype: 'rowexpander',
pluginId: 'abc',
rowBodyTpl: [
'<div id="CallsGridRow-{id}" ></div>'
]
}]
});

Sencha : can't call method "update" of undefined

Here, i'm registering my app:
App = new Ext.Application({
name: "App",
launch: function() {
this.views.viewport = new this.views.Viewport();
}
});
This is the way i register new panels and components. I put each of them into seperate js files.
App.views.Viewport = Ext.extend(Ext.TabPanel, {
fullscreen: true,
tabBar: {
dock: 'bottom',
layout: {
pack: 'center'
}
},
items: [
{
xtype: 'cPanel'
},
{
xtype: 'anotherPanel'
}
]
});
// register this new extended type
Ext.reg('App.views.viewport', App.views.Viewport);
I added the other components in the same manner.
In one my components which is a list view, I want to change the container panel's activeItem with another panel when tappen on an item, like this: ( Viewport contains this container panel)
App.views.ListApp = Ext.extend(Ext.List, {
store: App.store,
itemTpl: "...",
onItemDisclosure: function(record) {
App.detailPanel.update(record.data);
App.cPanel.setActiveItem("detailPanel");
},
listeners: {
itemtap: function(view, index, item, e) {
var rec = view.getStore().getAt(index);
App.views.detailPanel.update(rec.data);
App.views.cPanel.setActiveItem("detailPanel", {type:"slide", direction: "left"});
}
}
});
App.views.detailPanel.update(rec.data);
But it says: can't call method "update" of undefined
I tried different variations on that line, like:
App.detailPanel.update(rec.data);
and i tried to give detailPanel and cPanel ids, where they were added to their container panel, and tried to reach them with Ext.get(), but none of these worked.
What is the problem here?
And any other advices would be appreciated.
Thanks.
The lazy way: give the panels ids and use:
Ext.getCmp(id)
The recommended way: Assign itemId to your panel and use:
App.views.viewport.getComponent(itemId)
This will allow you to have more than one instance of the same component at aby given time, the first example is not valid cause you can only have a singular id in the DOM tree.
Also getComponent only works for components stored in the items collection.