I've implemented an EXTJS 4.0 tabpanel containing two grids.
This all runs fine when i first load it. But when i go to another panel( not a child of the tabpanel) and then reload the tabpanel in the viewport OR resize my browser window, the HTML child homeclients (my grid) dissappears ( and it's HTML element is removed from the tabpanel).
Anybody have any idea why this is happening ?
Tabpanel:
Ext.define('EY.view.center.home.container.Panel', {
extend: 'Ext.tab.Panel',
alias: 'widget.containerhome',
id: 'containerhome',
activeTab: 1,
border: false,
resizeTabs:true,
items: [{
title: 'Most Used clients',
iconCls: 'tabIcon',
xtype: 'mostUsedClients',
id: 'mostUsedClients',
scale: 'large'
},{
title: 'All Clients',
xtype: 'homeclients',
id: 'homeclients',
scale: 'large'
}
],
requires: [
'EY.view.center.home.client.Grid',
'EY.view.center.home.client.mostUsedClients.mostUsedClients'
],
initComponent: function () {
Ext.apply(this, {
})
this.callParent(arguments);
}
});
Grid:
Ext.define('EY.view.center.home.client.Grid', {
extend: 'Ext.grid.Panel',
alias: 'widget.homeclients',
id: 'homeclients',
baseCls: 'homeclients',
//frame:true,
store: 'Clients', //Ext.data.StoreManager.lookup('serviceStore'),
contextMenu: undefined,
border: false,
//flex: 1,
padding: 3,
hideHeaders: true,
columns: [
{ header: 'CLIENTS', field: 'textfield', flex: 1 }
],
features: [
Ext.create('Ext.grid.feature.RowBody', {
getAdditionalData: function (data, rowIndex, rec, orig) {
var headerCt = this.view.headerCt;
var colspan = headerCt.getColumnCount();
return {
rowBody: createHtml(rec),
rowBodyCls: this.rowBodyCls,
rowBodyColspan: colspan
};
}
}),
{
ftype: 'rowwrap'
}
],
viewConfig: {
listeners: {
itemclick: function (list, index, target, record, event) {
if (event.target.id == 'grandAccess') {
var windowIsClosed = Ext.getCmp('ConfirmationWindow');
if (!windowIsClosed) {
var clientId = index.data.id;
var clientVat = index.data.rn;
eDocsUser.currentClientName = index.data.n;
eDocsUser.currentClientId = clientId;
eDocsUser.currentClientRegisterNummer = clientVat;
showGrantAccesWindow(index);
}
} else {
if (Ext.getCmp('ConfirmationWindow')) {
Ext.getCmp('ConfirmationWindow').hide();
}
loadDataOfSelectedClient(index);
}
}
}
},
initComponent: function () {
this.callParent(arguments);
}
});
We solved this by changing the grid to a dataview for the resizing problem (grids rly cause a lot of problems for me tbh).
And then we fixed the other problem by changing :
layout.setActiveItem(Ext.getCmp('containerhome'), {
type: 'slide',
direction: 'left',
duration: 5000
});
to
layout.setActiveItem(0);
We (but not me ... :D ) created a new item instead of calling the old one in the card panel.
Related
In create and update forms, it is sometimes necessary to give the user the ability to dynamically add fields to values of the same type (more than one phone, more than one address, etc.).
I'm exploring several possibilities to do this.
One of them is to use a grid as a form field.
However, I have doubts about how best to implement this idea, especially on how to send all the form field values (textfield and grid) to the server (and then how to load them later in the form to edit).
Fiddles with some ideas:
One with cellediting plugin https://fiddle.sencha.com/#view/editor&fiddle/2ftp
Another one with roweditin gplugin a https://fiddle.sencha.com/#view/editor&fiddle/2fto
Not sure about the "best to implement", but I have seen so many requirements for multivalue input, that for reusability I have in my toolbox a gridfield similar to the following one:
Ext.define('Ext.ux.GridField', {
extend: 'Ext.form.FieldContainer',
alias: 'widget.gridfield',
initComponent: function () {
var me = this;
if(!me.columns) me.columns = {
dataIndex: 'field1'
};
if(!me.mapFn) me.mapFn = function(value) {
if(Ext.isObject(value)) return value;
return {
field1: value
};
};
if(!me.unmapFn) me.unmapFn = function(record) {
return record.get('field1');
};
me.grid = Ext.widget(Ext.apply({
xtype: 'grid',
viewConfig: {
markDirty: false
},
store: me.store || Ext.create('Ext.data.Store', {
fields: me.columns.map(function(column) {
return {
name: column.dataIndex,
type: column.dataType || 'auto',
defaultValue: column.defaultValue
};
}),
listeners: {
update: me.updateValue,
datachanged: me.updateValue,
scope: me
}
}),
columns: [{
xtype: 'actioncolumn',
getClass: function () {
return 'x-fa fa-times'
},
handler: function(grid, rowIndex, colIndex, item, e, record) {
grid.getStore().remove(record);
},
width: 35
}].concat(me.columns),
bbar: [{
xtype: 'button',
iconCls: 'x-fa fa-pencil',
text: 'Add',
handler: function(btn) {
var grid = btn.up('grid'),
store = grid.getStore(),
record = store.add(Ext.clone(me.emptyRecord) || {})[0];
grid.getPlugin('editor').startEditByPosition({
row: store.indexOf(record),
column: 1
});
}
}],
plugins: [
Ext.create('Ext.grid.plugin.CellEditing', {
pluginId: 'editor',
clicksToEdit: 1
})
]
}, me.gridConfig)); // "gridConfig" config can override everything on each instance.
me.hiddenField = Ext.widget({
xtype: 'hiddenfield',
name: me.name,
value: '',
allowNull: false,
rawToValue: function (raw) {
return raw;
},
valueToRaw: function (value) {
return value;
},
getRawValue: function () {
return Ext.valueFrom(this.rawValue, '')
},
isEqual: function (a, b) {
return Ext.encode(a) == Ext.encode(b)
},
listeners: {
change: function(field, nV, oV) {
if(!Ext.isArray(nV)) nV = [nV];
var store = me.grid.getStore();
store.removeAll();
store.add(nV.map(me.mapFn));
}
}
});
Ext.apply(me, {
layout: 'fit',
items: [{
xtype:'container',
border: 1,
style: {
borderColor: '#d0d0d0',
borderStyle: 'solid'
},
items: [me.grid]
}, me.hiddenField]
});
me.callParent(arguments);
},
updateValue: function() {
var me = this,
grid = me.grid,
hiddenField = me.hiddenField,
nV = grid.getStore().getRange().map(me.unmapFn, me),
oV = me.hiddenField.getValue();
if(!oV || Ext.isArray(oV) && Ext.encode(nV) != Ext.encode(oV)) {
hiddenField.suspendCheckChange++;
hiddenField.setValue(nV);
hiddenField.suspendCheckChange--;
me.fireEvent('change', me, nV, oV);
}
}
});
which can then be used like this:
},{
xtype: 'gridfield',
fieldLabel: 'Contacts',
name: 'contacts',
columns: [{
text: 'Type',
dataIndex: 'type',
editor:{
xtype: 'combobox',
name: 'type',
valueField: 'name',
displayField: 'name',
store: combostore,
queryMode: 'local'
},
flex: 0.7
},{
text: 'Description',
dataIndex: 'description',
editor:{
xtype: 'textfield',
name: 'description'
},
flex: 1
}],
mapFn: function(value) {
return value;
},
unmapFn: function(record) {
return record.getData();
}
}, {
I have made a fiddle for you based on your fiddle, including working load and save operations on the form, but in ExtJS 6.x. And I have checked that it works with ExtJS 5 as well, although you have to add working icons.
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
In ExtJS, on a menu toolbar button, I am trying to remove the current panel in my center window, then recreate it with the new selection. I do not understand the proper way to do this. So far when I click the menu item, it removes whatever is currently there successfully, then it will add the new panel successfully. The problem is the 2nd time I hit the button I get the following error:
REGISTERING DUPLICATE COMPONENT ID 'mainportalID'.
I realize its telling me I already used this ID, but then what would be the correct way to remove the current panel, and replace with a new one?
Here is my view controller:
selectMenuButton: function (button, e) {
console.log('select menu button section was hit')
console.log(button);
console.log(e);
var optionString = button.text;
var myDetailsPanel = Ext.getCmp('navview');
console.log(myDetailsPanel);
var count = myDetailsPanel.items.items.length;
if (count > 0) {
myDetailsPanel.items.each(function (item, index, len) {
myDetailsPanel.remove(item, false);
});
}
myDetailsPanel.add({
xtype: optionString
});
}
var myStore = Ext.create('ExtApplication1.store.PositionsStore');
var gridSummary = Ext.create('Ext.grid.Panel', {
store: myStore,
width: 600,
title: 'my first grid',
columns: [
{
text: 'AcctNum',
dataIndex: 'AcctNum',
width: 100
},
{
text: 'AcctShortCode',
dataIndex: 'AcctShortCode',
flex: 1
},
{
text: 'Exchange',
dataIndex: 'Exchange',
width: 200
}
]
});
This is my view
Ext.define('ExtApplication1.view.main.MainPortal', {
extend: 'Ext.panel.Panel',
xtype: 'mainportal',
alias: 'widget.mainportal',
id: 'mainportalID',
html: 'user... this is the main portal window',
autoScroll: true,
bodyPadding: 10,
items: [
gridSummary
]
});
adjusted panel
Ext.define('ExtApplication1.view.main.MainPortal', {
extend: 'Ext.panel.Panel',
xtype: 'mainportal',
alias: 'widget.mainportalAlias',
reference: 'gridtextfield',
//id: 'mainportalID',
html: 'user... this is the main portal window',
autoScroll: true,
bodyPadding: 10,
items: [
gridSummary
]
});
adjusted view controller
onComboboxSelect: function (combo, record, eOpts) {
console.log('new listener was hit');
//return selected Item
var selectedValue = record.get('ClientName');
var selectedCID = record.get('ClientID');
//find the grid that was created
var me = this;
console.log(me);
var xxx = this.lookupReference('gridtextfield');
debugger;
//debugger;
var mainPortalView = Ext.getCmp('mainportalID');
var targetGrid = mainPortalView.down('grid');
//find the store associated with that grid
var targetStore = targetGrid.getStore();
//load store
targetStore.load({
params: {
user: 'stephen',
pw: 'forero',
cid: selectedCID
}
//callback: function (records) {
// Ext.each(records, function (record) {
// console.log(record);
// });
// console.log(targetStore);
//}
});
},
added listeners to MainPortal.js
var myStore = Ext.create('ExtApplication1.store.PositionsStore');
var gridSummary = Ext.create('Ext.grid.Panel', {
store: myStore,
width: 600,
title: 'my first grid',
columns: [
{
text: 'AcctNum',
dataIndex: 'AcctNum',
width: 100
},
{
text: 'AcctShortCode',
dataIndex: 'AcctShortCode',
flex: 1
},
{
text: 'Exchange',
dataIndex: 'Exchange',
width: 200
}
],
listeners: {
destroy: function () {
debugger;
}
}
});
Ext.define('ExtApplication1.view.main.MainPortal', {
extend: 'Ext.panel.Panel',
xtype: 'mainportal',
alias: 'widget.mainportalAlias',
//id: 'mainportalID',
itemId: 'mainportalID',
html: 'user... this is the main portal window',
autoScroll: true,
bodyPadding: 10,
items: [
gridSummary
],
listeners: {
destroy: function () {
debugger;
}
}
});
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.
I am working on extjs4, my case is:
Extjs mvc is used to build my application, viewport is the toppest container of my application, west region is a tree, center region is a tabpage container, when click the tree item, a new page with certain content will be created. then in this page, I popup a model window, this model window just mask the page, not the whole viewport, so that I can still click the tree item to open another new page.
I have achieved this, but there is a problem, if I have already open a model window in a tab, and I switch to a another tab then return back, the model window is hidden, but I still want that window to show if I haven't closed it. Can anyone help me, is there a better way except using ifram in tabpage?
app.js:
Ext.application({
name: 'SysOpv',
appFolder: '/Js/AppSysOpv/app',
autoCreateViewport: true,
controllers: [
'Category',
'Band'
]
});
Viewport:
Ext.define('SysOpv.view.Viewport', {
extend: 'Ext.container.Viewport',
layout: 'fit',
initComponent: function() {
this.items = {
dockedItems: [{
dock: 'top',
xtype: 'toolbar',
height: 80,
items: [
{ xtype: 'component', html: 'setup' }
]
}],
layout: {
type: 'hbox',
align: 'stretch'
},
items: [{
width: 250,
xtype: 'categorytree'
}, {
id: 'maintabpanel',
flex: 1,
xtype: 'tabpanel'
}]
};
this.callParent(arguments);
}
});
Tree View:
Ext.define('SysOpv.view.category.Tree', {
extend: 'Ext.tree.Panel',
alias: 'widget.categorytree',
title: 'setup',
rootVisible: false,
useArrows: true,
hideHeaders: true,
columns: [{
flex: 1,
xtype: 'treecolumn',
text: 'Name',
dataIndex: 'name'
}],
store: 'Category',
initComponent: function() {
this.callParent(arguments);
}
});
Window View:
Ext.define('SysOpv.view.edit.Band', {
extend: 'Ext.window.Window',
alias: 'widget.editband',
title: 'Setup',
layout: 'fit',
constrain: true,
modal: true,
initComponent: function() {
this.items = [{
xtype: 'form',
bodyPadding: 10,
items: [{
xtype: 'textfield',
name: 'name',
fieldLabel: 'Name'
}]
}];
this.buttons = [{
text: 'Save',
action: 'save'
}, {
text: 'Cancel',
scope: this,
handler: this.close
}];
this.callParent(arguments);
}
});
Tree Controller:
Ext.define('SysOpv.controller.Category', {
extend: 'Ext.app.Controller',
models: [ 'Category' ],
stores: [ 'Category' ],
views: [ 'category.Tree' ],
init: function() {
this.control({
'categorytree': {
itemdblclick: this.onTreeItemdblclick
}
});
},
onTreeItemdblclick: function (tree, record, item, index, e, eOpts) {
var mainTabs = Ext.getCmp('maintabpanel');
var tabId = record.get('id');
if (mainTabs) {
var checkTab = mainTabs.getComponent(tabId);
if (checkTab) {
mainTabs.setActiveTab(checkTab);
} else {
var controller;
var list;
switch (tabId) {
case '0101':
list = Ext.widget('listband');
break;
}
if (list)
{
var tabPage = mainTabs.add({
id: record.get('id'),
title: record.get('name'),
closable: true,
layout: 'fit',
items: [ list ]
});
mainTabs.setActiveTab(tabPage);
}
}
}
}
});
Module Controller:
Ext.define('SysOpv.controller.Band', {
extend: 'Ext.app.Controller',
models: [ 'Band' ],
stores: [ 'Band' ],
views: [ 'list.Band', 'edit.Band' ],
init: function() {
this.control({
'listband button[action=edit]': {
click: this.onEdit
}
});
},
onEdit: function(button, e, eOpts) {
var edit = Ext.widget('editband');
var list = button.up('gridpanel');
if (list.getSelectionModel().hasSelection()) {
var record = list.getSelectionModel().getLastSelected();
// I use renderTo here but have no effect,
// so I search in the google find a way to show the window in tab,
// and not mask all the viewport.
button.up('#0101').add(edit);
edit.down('form').loadRecord(record);
edit.show();
} else {
console.log('Not selected');
}
}
});
Below is example solution:
Ext.create('Ext.TabPanel', {
renderTo: 'container',
items: [
{
title: 'Tab 1',
itemId: 'tab1',
items: [
{ xtype: 'button', text: 'Show window', handler: function(){
var tab = this.up('#tab1'); // Find tab
var win = Ext.widget('editband'); // Find window
this.up('tabpanel').showWindow(tab, win);
} }
]
},
],
showWindow: function(tab, w){
tab.add(w);
tab.popup = w;
w.on('close', function() { // clean up after window close
delete this.popup;
}, tab, { single: true });
w.show();
},
listeners: {
tabchange: function(panel, tab) {
if (tab.popup !== undefined) { // show window after tab change
tab.popup.show();
}
}
}
});
Basically I've created event handler for tabchange event in which I re-show window.
Working sample: http://jsfiddle.net/aCxYU/1/