how can i add spinner to tree column? - extjs

I have following code:
function selectClassWindow() {
classes = Ext.create('Ext.tree.Panel', {
store: Ext.create('Ext.data.TreeStore', {
autoLoad: true,
autoSync: true,
fields: ['id','name', 'description','cost'],
proxy: {
type: 'ajax',
api: {
read: '/otp/getClass/'
}
},
root: {
name: 'Name1',
id: 0,
expanded: true
},
listeners: {
load: function (tree, node, records) {
node.eachChild(function (childNode){
childNode.set('checked',false);
});
}
}
}),
border: false,
rootVisible: false,
useArrows: true,
hideHeaders: true,
height: window.MaxHeightWindows,
xtype: 'listTree',
columns: [
{
xtype: 'treecolumn',
text: 'Name2',
flex: 1,
sortable: true,
dataIndex: 'name'
},</code>
Want to add here!
{
xtype: 'customspinner',
fieldLabel: 'How Much Beer?',
step: 6
}
]
})
classes.on('itemdblclick', function() {
selectedNode = classes.getSelectionModel().getSelection()
if (selectedNode[0] && selectedNode[0].isLeaf()) {
selectedClass = selectedNode[0].data.id
selectWindow.close()
if((window.selectedNode[0].parentNode&&selectedNode[0].parentNode.data.name == 'Text1')||
(window.selectedNode[0].parentNode.parentNode&&selectedNode[0].parentNode.parentNode.data.name == 'Text1')||
(window.selectedNode[0].parentNode.parentNode.parentNode&&selectedNode[0].parentNode.parentNode.parentNode.data.name == 'Text1')){
selectReasonWindow()
}else{
Ext.Ajax.request({
url: '/defect/updateDeparture/'+rec.data.id,
params: {
class_id: selectedClass,
reason_id: 0
},
success: function(result,response) {
if (window.departureGrid) {
departureGrid.store.load()
}
if (window.departureFullList) {
departureFullList.store.load()
}
if(window.logs){
logs.setValue(result.responseText)
}
if (window.crashDepartureList) {
crashDepartureList.store.load()
}
}
})
}
}
})
emptyPanel = Ext.create('Ext.panel.Panel', {
border: false,
flex: 1,
items: [classes]
})
selectWindow = Ext.create('Ext.window.Window', {
title: 'Name3',
width: 750,
border: false,
layout: {
type: 'hbox',
},
resizable:false,
collapsible: false,
constrain: true,
modal:true,
plain:true,
items: [emptyPanel],
buttons: [{
text: 'Ok',
handler: function() {
selectedNode = classes.getSelectionModel().getSelection()
if (selectedNode[0] && selectedNode[0].isLeaf()) {
selectedClass = selectedNode[0].data.id
selectWindow.close()
if((window.selectedNode[0].parentNode&&selectedNode[0].parentNode.data.name == 'Text1')||
(window.selectedNode[0].parentNode.parentNode&&selectedNode[0].parentNode.parentNode.data.name == 'Text1')||
(window.selectedNode[0].parentNode.parentNode.parentNode&&selectedNode[0].parentNode.parentNode.parentNode.data.name == 'Text1')){
selectReasonWindow()
}else{
Ext.Ajax.request({
url: '/defect/updateDeparture/'+rec.data.id,
params: {
class_id: selectedClass,
reason_id: 0
},
success: function(result,response) {
if (window.departureGrid) {
departureGrid.store.load()
}
if (window.departureFullList) {
departureFullList.store.load()
}
if(window.logs){
logs.setValue(result.responseText)
}
if (window.crashDepartureList) {
crashDepartureList.store.load()
}
}
})
}
}
}
},{
text: 'Close',
handler: function() {selectWindow.close()}
}]
}).show();
}
and i want add column "customspinner" to Ext.tree.Panel, but i get Uncaught TypeError: Object [object Object] has no method 'setSortState'. What's wrong?
In finally need something like this

There are a couple of things that are getting in your way:
grids do not support components in the cells (yet), they will soon.
For now you can use http://skirtlesden.com/ux/component-column
Tree already has a loading mask that is triggered by default on node load.
If you just want to add a spinner somewhere in your page just follow the Loading Mask component docs. Essentially any dom element can be targeted with mask/unmask calls.

Related

Ext js 7 modern panel.Resizer Splitter Config

I have a panel.Resizer Layout like this:
https://examples.sencha.com/extjs/7.3.0/examples/kitchensink/?modern#panel-splitresize
Now I'm trien to config the splitter, I found this classic docs:
https://docs.sencha.com/extjs/7.0.0/classic/Ext.resizer.Splitter.html#cfg-collapseOnDblClick
But I can't find collapseOnDblClick nor collapsible on modern docs. Is there a way to achive a similar behaviour so resizer and collapser is combined?
And how do I change resizer size (width)?
You can override the 'Ext.panel.Resizer' to add this feature. Something like:
Ext.define('override.panel.Resizer', {
override: 'Ext.panel.Resizer',
privates: {
onTargetCollapse: function () {
var me = this,
map = me.edgeMap,
key;
me.disabled = true;
me.dragListeners = Ext.destroy(me.dragListeners);
me.setupCollapsedDragListeners();
for (key in map) {
map[key].addCls(me.disabledCls);
}
},
onTargetExpand: function () {
var me = this,
map = me.edgeMap,
key;
me.disabled = false;
me.setupDragListeners();
for (key in map) {
map[key].removeCls(me.disabledCls);
}
},
setupDragListeners: function () {
var me = this,
delegate = me.edgeDelegateSelector;
me.dragListeners = me.getTarget().element.on({
scope: me,
destroyable: true,
delegate: delegate,
dragstart: {
// Higher priority so that we run before any draggable component handlers.
priority: 1000,
delegate: delegate,
fn: 'handleDragStart'
},
drag: 'handleDrag',
dragend: 'handleDragEnd',
dragcancel: 'handleDragCancel',
touchstart: 'handleTouchStart',
doubletap: 'handleDoubleTap'
});
},
setupCollapsedDragListeners: function () {
var me = this,
delegate = me.edgeDelegateSelector;
me.dragListeners = me.getTarget().element.on({
scope: me,
destroyable: true,
delegate: delegate,
doubletap: 'handleDoubleTap'
});
}
},
handleDoubleTap: function () {
if (!this.getTarget()._collapsible) {
return;
}
if (this.getTarget().collapsed) {
this.getTarget().expand();
} else {
this.getTarget().collapse();
}
}
});
Ext.define('KitchenSink.view.panels.SplitResizable', {
extend: 'Ext.container.Container',
xtype: 'panel-splitresize',
requires: [
'Ext.panel.Resizer',
'Ext.Toolbar'
],
layout: {
type: 'vbox',
align: 'stretch'
},
defaultType: 'panel',
items: [{
title: 'Dock Left',
docked: 'left',
minWidth: 200,
collapsible: 'left',
resizable: {
split: true,
edges: 'east'
},
html: "Content"
}, {
title: 'Dock Right',
docked: 'right',
minWidth: 200,
resizable: {
split: true,
edges: 'west'
}
}, {
title: 'Dock Top',
docked: 'top',
minHeight: 150,
resizable: {
split: true,
edges: 'south'
}
}, {
title: 'Unresizable region',
flex: 1
}, {
title: 'Dock Bottom',
docked: 'bottom',
minHeight: 150,
resizable: {
split: true,
edges: 'north'
}
}]
});
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.create('KitchenSink.view.panels.SplitResizable', {
renderTo: Ext.getBody(),
fullscreen: true
})
}
});

Deleting the row is not updating the grid? Sencha Extjs Application

When I delete any current row, the next row and pagination has to get updated in the empty row. But it is not updating the pagination but the url is passing in network correctly. When I refresh the page, the empty row is replaced by the next row.
List.js:
/**
* This view is an example list of people.
*/
Ext.define('CRUD.view.main.List', {
extend: 'Ext.grid.Panel',
xtype: 'home',
requires: [
'CRUD.store.Personnel',
'CRUD.view.main.MainController',
'Ext.toolbar.Paging',
],
title: 'Heroes',
plugins: [
Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1
})
],
layout: 'fit',
fullscreen: true,
store: {
type: 'personnel',
},
selModel: {
pruneRemoved: false
},
selType: 'cellmodel',
columns: [{
text: 'Name',
align: 'center',
dataIndex: 'name',
sortable: true,
flex: 1,
editor: {
xtype: 'textfield',
selectOnFocus: true,
allowBlank: false
}
},
{
text: 'Email',
align: 'center',
dataIndex: 'email',
sortable: true,
flex: 1,
editor: {
xtype: 'textfield',
selectOnFocus: true,
allowBlank: false
}
},
{
text: 'Phone',
align: 'center',
dataIndex: 'phone',
sortable: true,
flex: 1,
editor: {
xtype: 'textfield',
selectOnFocus: true,
allowBlank: false
}
},
{
text: 'Save',
align: 'center',
xtype: 'actioncolumn',
items: [{
icon: 'http://icons.iconarchive.com/icons/oxygen-icons.org/oxygen/128/Actions-document-edit-icon.png',
xtype: 'submit',
handler: function(grid, rowIndex, colIndex, item, e, record) {
Ext.Msg.confirm("Confirmation", "Do you want to Save?", function(btnText) {
if (btnText === "yes") {
Ext.Ajax.request({
url: 'http://localhost:8080/edit?id=' + record.data.id + '&name=' + record.data.name + '&email=' + record.data.email + '&phone=' + record.data.phone,
method: 'POST', //this is the url where the form gets submitted
useDefaultXhrHeader: false,
success: function(response) {
store.load()
},
failure: function(form, action) {
Ext.Msg.alert('Failed', action);
}
});
}
});
}
}],
}, {
text: 'Delete',
xtype: 'actioncolumn',
align: 'center',
items: [{
icon: 'http://www.freeiconspng.com/uploads/delete-button-png-27.png',
xtype: 'submit',
// handler: function(grid, rowIndex, colIndex, item, e, record) {
// console.log(record.data.id)
// // Ext.Msg.confirm('Confirmation', 'Are you sure?', function(btnText) {
// // if (btnText === 'yes') {
// // Ext.Ajax.request({
// // url: 'http://localhost:8080/del/' + record.data.id,
// // method: 'DELETE', //this is the url where the form gets submitted
// // useDefaultXhrHeader: false,
// // cors: true,
// // success: function(form, action) {
// // store.load()
// // },
// // failure: function(form, action) {
// // Ext.Msg.alert('Failed', action);
// // }
// // });
// // }
// // })
// }
}],
listeners: {
click: 'onDeleteClick'
}
}
],
bbar: Ext.create('Ext.PagingToolbar', {
xtype: 'pagingtoolbar',
displayInfo: true,
doRefresh: function() {
this.doLoad(this.cursor);
},
}),
// columns: [
// { text: 'Name', dataIndex: 'name', flex: 1 },
// { text: 'Email', dataIndex: 'email', flex: 1 },
// { text: 'Phone', dataIndex: 'phone', flex: 1 }
// ],
// listeners: {
// select: 'onItemSelected',
// },
});
Store:
Ext.define('CRUD.store.Personnel', {
extend: 'Ext.data.Store',
alias: 'store.personnel',
model: 'CRUD.model.User',
fields: [
'name', 'email', 'phone'
],
// data: [
// { name: 'Jean Luc', email: "jeanluc.picard#enterprise.com", phone: "555-111-1111" },
// { name: 'Worf', email: "worf.moghsson#enterprise.com", phone: "555-222-2222" },
// { name: 'Deanna', email: "deanna.troi#enterprise.com", phone: "555-333-3333" },
// { name: 'Data', email: "mr.data#enterprise.com", phone: "555-444-4444" }
// ],
autoLoad: { offset: 0, limit: 5 },
pageSize: 5,
proxy: {
type: 'ajax', //cross domain calls - json parser
enablePaging: true,
url: 'http://localhost:8080/list',
useDefaultXhrHeader: false,
startParam: 'offset',
limitParam: 'limit',
reader: {
totalProperty: 'total',
rootProperty: 'items'
},
listeners: {
//this is used to construct the proxy url before the load is done
// beforeload: {
// fn: function() {
// var me = this;
// me.updateProxyURL(); //write this function yourself
// }
// }
}
},
// proxy: {
// type: 'memory',
// reader: {
// type: 'json',
// }
// },
});
Controller.js
/**
* This class is the controller for the main view for the application. It is specified as
* the "controller" of the Main view class.
*
* TODO - Replace this content of this view to suite the needs of your application.
*/
Ext.define('CRUD.view.main.MainController', {
extend: 'Ext.app.ViewController',
alias: 'controller.main',
store: {
type: 'personnel',
},
onClick: function(grid) {
Ext.Msg.alert("tesdt")
},
onDeleteClick: function(selModel, record, index, options, grid, store) {
//Ext.Msg.confirm('Confirm', 'Are you sure?', 'onConfirm', this);
Ext.Msg.confirm({
title: 'Confirm',
msg: 'Are you sure?',
buttons: Ext.Msg.OKCANCEL,
fn: this.onConfirm,
icon: Ext.MessageBox.QUESTION,
config: {
grid: grid,
action: 'del',
store: store
}
});
},
onConfirm: function(btn, text, opt) {
console.log(opt.config.action)
if (btn === 'ok') {
//
opt.config.grid.item.remove();
Ext.Ajax.request({
url: 'http://localhost:8080/' + opt.config.action + '/' + opt.config.grid.record.data.id,
// method: 'DELETE', //this is the url where the form gets submitted
useDefaultXhrHeader: false,
success: function(form, action) {
opt.config.store.load({
start: 0,
limit: 5
})
},
failure: function(form, action) {
},
listeners: {
doRefresh: function() {
this.doLoad(this.cursor);
},
}
});
}
}
});
Please find the screenshot here
Doing grid.getStore().reload() should be sufficient.
BTW. The doRefresh listener is weird. Are you sure you wanted this as Ext.Ajax.request config? This doesn't make sense to me.

Routing Extjs deeper navigation

I'm writing a Extjs app in the 6.2.0 version, I’ve got a routing situation.
My problem is when we enter on the NavigateDeep if I enter the Url ok it catches but it doesn’t render.
I define the routes on the main Controller like:
Ext.define('App.view.main.MainController', {
extend: 'Ext.app.ViewController',
alias: 'controller.main',
listen : {
controller : {
'*' : {
unmatchedroute : 'onRouteChange1',
changeroute: 'changeRoute'
}
}
},
routes: {
':node': 'onNavigate',
':node/:id' : 'onNavigateDeep',
':node/:id/:tabid' : 'onNavigateDeepTab'
},
lastView: null,
onRouteChange1: function(){
console.log("hier unmatched route");
},
setCurrentView: function(hashTag) {
hashTag = (hashTag || '').toLowerCase();
console.log("hash:" + hashTag);
var me = this,
refs = me.getReferences(),
mainCard = refs.mainCardPanel,
mainLayout = mainCard.getLayout(),
navigationList = refs.navigationTreeList,
store = navigationList.getStore(),
node = store.findNode('routeId', hashTag) ||
store.findNode('viewType', hashTag),
view = (node && node.get('viewType')) || 'page404',
lastView = me.lastView,
existingItem = mainCard.child('component[routeId=' + hashTag + ']'),
newView;
// Kill any previously routed window
if (lastView && lastView.isWindow) {
lastView.destroy();
}
lastView = mainLayout.getActiveItem();
if (!existingItem) {
newView = Ext.create({
xtype: view,
routeId: hashTag, // for existingItem search later
hideMode: 'offsets'
});
}
if (!newView || !newView.isWindow) {
// !newView means we have an existing view, but if the newView isWindow
// we don't add it to the card layout.
if (existingItem) {
// We don't have a newView, so activate the existing view.
if (existingItem !== lastView) {
mainLayout.setActiveItem(existingItem);
}
newView = existingItem;
}
else {
// newView is set (did not exist already), so add it and make it the
// activeItem.
Ext.suspendLayouts();
mainLayout.setActiveItem(mainCard.add(newView));
Ext.resumeLayouts(true);
}
}
navigationList.setSelection(node);
if (newView.isFocusable(true)) {
newView.focus();
}
me.lastView = newView;
},
onNavigationTreeSelectionChange: function (tree, node) {
var to = node && (node.get('routeId') || node.get('viewType'));
if (to) {
console.log("to;:" + to);
this.redirectTo(to);
}
},
onToggleNavigationSize: function () {
var me = this,
refs = me.getReferences(),
navigationList = refs.navigationTreeList,
wrapContainer = refs.mainContainerWrap,
collapsing = !navigationList.getMicro(),
new_width = collapsing ? 64 : 250;
if (Ext.isIE9m || !Ext.os.is.Desktop) {
Ext.suspendLayouts();
refs.logo.setWidth(new_width);
navigationList.setWidth(new_width);
navigationList.setMicro(collapsing);
Ext.resumeLayouts(); // do not flush the layout here...
// No animation for IE9 or lower...
wrapContainer.layout.animatePolicy = wrapContainer.layout.animate = null;
wrapContainer.updateLayout(); // ... since this will flush them
}
else {
if (!collapsing) {
// If we are leaving micro mode (expanding), we do that first so that the
// text of the items in the navlist will be revealed by the animation.
navigationList.setMicro(false);
}
// Start this layout first since it does not require a layout
refs.logo.animate({dynamic: true, to: {width: new_width}});
// Directly adjust the width config and then run the main wrap container layout
// as the root layout (it and its chidren). This will cause the adjusted size to
// be flushed to the element and animate to that new size.
navigationList.width = new_width;
wrapContainer.updateLayout({isRoot: true});
navigationList.el.addCls('nav-tree-animating');
// We need to switch to micro mode on the navlist *after* the animation (this
// allows the "sweep" to leave the item text in place until it is no longer
// visible.
if (collapsing) {
navigationList.on({
afterlayoutanimation: function () {
navigationList.setMicro(true);
navigationList.el.removeCls('nav-tree-animating');
},
single: true
});
}
}
},
onMainViewRender:function() {
if (!window.location.hash) {
this.redirectTo("dashboard");
}
},
changeRoute: function(controller,route){
this.redirectTo(route,true);
console.log("change route fired");
},
onClickLogoutButton: function () {
// Remove the localStorage key/value
localStorage.removeItem('LoggedIn');
// Remove Main View
this.getView().destroy();
// Add the Login Window
Ext.create({
xtype: 'login'
});
},
onClickShareButton: function(){
var text = window.location;
window.prompt("Copy to clipboard:", text);
},
onNavigate:function(node){
console.log("on route change");
this.setCurrentView(node);
},
onNavigateDeep: function (node, id) {
console.log("Tab");
console.log(node + '/' + id);
var route = node+'/'+id;
this.setCurrentView(route);
},
onNavigateDeepTab: function (node, id, tabid) {
console.log("navigate Tab");
}
});
My main view is:
Ext.define('App.view.main.Main', {
extend: 'Ext.container.Viewport',
xtype: 'app-main',
requires: [
'App.view.Dashboard',
'App.view.immo.List',
'App.view.settings.Settings',
'App.view.news.News',
'App.view.help.Help'
],
controller: 'main',
viewModel: 'main',
cls: 'sencha-dash-viewport',
itemId: 'mainView',
layout: {
type: 'vbox',
align: 'stretch'
},
listeners: {
render: 'onMainViewRender'
},
items: [{
xtype: 'toolbar',
cls: 'dash-dash-headerbar shadow',
height: 64,
itemId: 'headerBar',
items: [{
xtype: 'component',
reference: 'logo',
cls: 'logo',
html: '<div class="main-logo"><img src="resources/images/logo.png">App</div>',
width: 250
}, {
margin: '0 0 0 8',
ui: 'header',
iconCls:'x-fa fa-navicon',
id: 'main-navigation-btn',
handler: 'onToggleNavigationSize',
tooltip: 'Navigation umschalten'
},
'->',
{
xtype: 'button',
ui: 'header',
iconCls: 'x-fa fa-share-alt',
handler: 'onClickShareButton',
tooltip: 'Share'
},
{
iconCls:'x-fa fa-question',
ui: 'header',
href: '#help',
hrefTarget: '_self',
tooltip: 'Hilfe'
}, {
iconCls:'x-fa fa-th-large',
ui: 'header',
href: '#Dashboard',
hrefTarget: '_self',
tooltip: 'Zum Dashboard'
}, {
xtype: 'button',
ui: 'header',
iconCls: 'x-fa fa-power-off',
handler: 'onClickLogoutButton',
tooltip: 'Logout'
}]
}, {
xtype: 'maincontainerwrap',
id: 'main-view-detail-wrap',
reference: 'mainContainerWrap',
flex: 1,
items: [{
xtype: 'treelist',
reference: 'navigationTreeList',
itemId: 'navigationTreeList',
ui: 'navigation',
store: 'NavigationTree',
width: 250,
expanderFirst: false,
expanderOnly: false,
listeners: {
selectionchange: 'onNavigationTreeSelectionChange'
}
}, {
xtype: 'container',
flex: 1,
reference: 'mainCardPanel',
cls: 'sencha-dash-right-main-container',
itemId: 'contentPanel',
layout: {
type: 'card',
anchor: '100%'
}
}]
}]
});
When we click on the tree I change the container but one of them has the route if the :id where I have a Tab:
Ext.define('App.view.settings.Settings',{
extend: 'Ext.tab.Panel',
xtype: 'settings',
itemId:'settings',
requires: [
'App.view.settings.SettingsController',
'App.view.settings.SettingsModel',
'App.view.settings.property.Property',
'App.view.settings.user.User'
],
controller: 'settings-settings',
viewModel: {
type: 'settings-settings'
},
reference: 'tab',
tabPosition: 'left',
tabBar:{
flex: 1,
tabRotation: 0,
tabStretchMax: true,
cls: 'immoNavi'
},
layout: 'Container',
defaults: {
padding: 0,
textAlign: 'left'
},
listeners: {
tabchange: 'onTabChange'
},
items: [{
xtype: 'component',
tabConfig:{
hidden: true
}
},{
title: 'Property',
itemId: 'property',
xtype: 'property',
cls: 'container'
},{
title: 'User',
itemId: 'user',
xtype: 'user'
}]
});
I went through the documentation but didn't find any tip that might help me with it. What am I missing here? Should I take care the rendering on the tab controller? Or How?
Thanks in advance for the help

filtering cards based on PortfolioItem selected for CardBoard

I am creating a rally sdk2 app, which shows Rally.ui.dialog.ChooserDialog of PortfolioItems like MMF, Epic and Program
When multiple MMFs or Epics or Programs are selected, show the features based on those filters, but cards are not getting. Something I am not able to figure out.
below is my some of the code
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
items:[{ xtype: 'container', itemId: 'filter_box', padding: 5},{xtype:'container',itemId:'button_box',layout:{type:'hbox'}, padding: 10}],
logger: new Rally.technicalservices.logger(),
launch: function() {
this.down('#button_box').add({
xtype: 'rallybutton',
text: 'Filter',
itemId: 'run-button',
scope: this,
handler: this._run,
margin: '0 10 0 95'
});
},
_drawCardBoard: function(records){
var filters = null;
alert("hi there");
console.log("context");
var me = this;
if (records[0].data.PortfolioItemTypeName == "MMF") {
console.log("context name", records[0].data.FormattedID);
filters = Ext.create('Rally.data.QueryFilter',{
property: 'Parent.FormattedID',
operator: '=',
value: records[0].data.FormattedID
});
} else if (records[0].data.PortfolioItemTypeName == "Epic") {
filters = Ext.create('Rally.data.QueryFilter',{
property: 'Parent.Parent.FormattedID',
operator: '=',
value: records[0].data.FormattedID
});
} else if (records[0].data.PortfolioItemTypeName == "Program") {
filters = Ext.create('Rally.data.QueryFilter',{
property: 'Parent.Parent.Parent.FormattedID',
operator: '=',
value: records[0].data.FormattedID
});
}
if (records.length > 1) {
for ( var i=1;i<records.length;i++ ) {
if (records[i].data.PortfolioItemTypeName == "MMF") {
console.log("context name 2", records[i].data.FormattedID);
filters = filters.or(Ext.create('Rally.data.QueryFilter',{
property: 'Parent.FormattedID',
operator: '=',
value: records[i].data.FormattedID
}));
} else if (records[i].data.PortfolioItemTypeName == "Epic") {
filters = filters.or(Ext.create('Rally.data.QueryFilter',{
property: 'Parent.Parent.FormattedID',
operator: '=',
value: records[i].data.FormattedID
}));
} else if (records[i].data.PortfolioItemTypeName == "Program") {
filters = filters.or(Ext.create('Rally.data.QueryFilter',{
property: 'Parent.Parent.Parent.FormattedID',
operator: '=',
value: records[i].data.FormattedID
}));
}
}
}
console.log("filters values", filters.toString());
this.cardboard = Ext.create('Rally.ui.cardboard.CardBoard',{
types: ['PortfolioItem/Feature'],
attribute: 'Release',
columnConfig: {
xtype: 'rallycardboardcolumn',
displayField: 'Name',
valueField: '_ref',
plugins: [
{ptype:'rallycolumndropcontroller'},
{ptype:'rallycardboardcardrecordprocessor'},
{ptype:'tscolumnheaderupdater'} /*,
{ptype:'tscolumnheaderupdater', field_to_aggregate: 'LeafStoryPlanEstimateTotal'}*/
],
},
storeConfig: {
filters: filters,
context: this.getContext().getDataContext()
},
cardConfig: {
showIconsAndHighlightBorder: false,
fields: [
'FormattedID',
'Name',
'Parent',
'ReleaseDate',
'ReleaseStartDate',
{ name: 'Project', renderer: me._renderProject },
{ name: 'PercentDoneByStoryPlanEstimate' },
{ name: 'c_FeatureEstimate', fetch: ['c_FeatureEstimate'] }
],
listeners: {
added: function(card,container){
me.logger.log(this,card,container);
},
fieldClick: function(eOpts) {
me.logger.log(this,eOpts);
if ( eOpts == "PercentDoneByStoryPlanEstimate" ) {
me._showDoneTooltip(eOpts,this);
}
}
}
}
});
_run: function() {
this._parents = {};
var me = this;
Ext.create('Rally.ui.dialog.ChooserDialog', {
width: 470,
autoScroll: true,
height: 500,
title: 'Select to Filter',
pageSize: 100,
closable: false,
selectionButtonText: 'Filter',
multiple: true,
artifactTypes: ['PortfolioItem/MMF','PortfolioItem/Epic', 'PortfolioItem/Program'],
autoShow: true,
storeConfig:{
fetch: ['Name','PortfolioItemTypeName', 'Parent']
},
listeners: {
scope: me,
artifactChosen: function(selectedRecord) {
console.log("selectedRecord", selectedRecord);
me._drawCardBoard(selectedRecord);
}
}
});
},

why my combo's store does not delete record

I have a tree panel. Each node in the tree has a check box. When users check a node, I add the text of the node as an option to a combo box. This much works like a charm.
When users uncheck a node, I want to remove the corresponding option from the combo box. Sometimes it removes, and sometimes it does not. I have been pulling my hair out for days now. What am I doing wrong? Thanks.
Here is my the init function in my controller:
init: function () {
this.control({
"#problemsTree": {
load: this.selectFirstProblem,
select: this.showProblemDetail,
checkchange: this.handleCheckChange
},
"#run-problems-button": { click: this.runSelectedProblems },
"#stop-problems-button": { click: this.stopSelectedProblems }
});
}
Here is handleCheckChange function in the same controler:
toggleLogOption: function(record, isChecked) {
var logStore = Ext.StoreManager.lookup("logs-store");
if(isChecked && logStore.find("text", record.data.text) == -1) {
logStore.add(record)
} else if(!isChecked) {
logStore.remove(record)
}
logStore.sync();
},
handleCheckChange: function(node, isChecked) {
if(node.isLeaf()) {
var record = Ext.create("GiipIq.model.Log", {id: node.data.id, text: node.data.text});
this.toggleLogOption(record, isChecked);
} else {
node.cascadeBy(function(nd) {
nd.set("checked", isChecked);
if(nd.isLeaf()) {
var record = Ext.create("GiipIq.model.Log", {id: nd.data.id, text: nd.data.text});
this.toggleLogOption(record, isChecked);
}
},
this
);
}
},
Here is my Log combo:
Ext.define("GiipIq.view.Log", {
extend: "Ext.window.Window",
alias: "widget.logwindow",
titleAlign: "center",
closable: false,
maximizable: true,
draggable: false,
resizable: false,
overflowX: "hidden",
border: false,
layout: 'fit',
x: (Ext.getBody().getViewSize().width/2) + 2,
y: 0,
width: (Ext.getBody().getViewSize().width/2) - 5,
height: Ext.getBody().getViewSize().height/2,
initComponent: function () {
this.items = [{
xtype: "panel",
itemId: "logPanel",
title: "Live Logs ",
tools:[{
xtype:"combo",
width: 250,
emptyText: "Filter logs",
id: "logFilter",
store: Ext.create("GiipIq.store.Logs"),
queryMode: "local",
displayField: "text",
valueField: "id"
}]
}];
this.callParent(arguments);
}
});
Here is my Log store:
Ext.define("GiipIq.store.Logs", {
extend: "Ext.data.Store",
storeId:"logs-store",
model: "GiipIq.model.Log",
sorters: [{ property: "text", direction: "ASC" }]
});
Here is my Log model:
Ext.define("GiipIq.model.Log", {
extend: "Ext.data.Model",
idProperty: "text",
fields: [
{ name: "id", type: "string"},
{ name: "text", type: "string" }
],
proxy: {
type: "localstorage",
id: "proxy-key",
listeners: {
exception: function(proxy, response, operation, opts) {
if(typeof(operation.error) == "string") {
Ext.Msg.alert("Error", "Connection to server interrupted" + operation.error);
}
}
}
}
});
You always create new record even if you are trying to remove. The logic should rely on ids, they seem to be same in tree and combo, and when removing, you should try to find the record in combo by id and remove that. Create new record only if adding.

Resources