ExtJs 4.1: Destroy components on closing a dynamically created tab - extjs

I am creating new ExtJs tabpanels and rendering panels inside it programmatically.
The panels (rendered inside tabs) are all written in separate JS files.
Opening, rendering and closing of the tabs is working completely fine.
But when I debug the code I see that the previous components of the closed tabs are still active in the memory. As a result of which the functioning of the components gets affected when the tab is reopened.
I want to destroy all the components inside the tab panels (if ExtJs, for some reasons, is not able to do it).
How can I do this?
Below is a sample code which I am trying:
Main Tab:
var tabs = new Ext.TabPanel({
id : 'screensTabPanel',
layout : 'fit',
enableTabScroll : true,
height : Ext.getBody().getStyleSize().height - 60,
activeTab : 0,
//enableTabScroll : true,
autoScroll : true,
autoRender : true,
border : false,
plugins : [ {
ptype : 'tabscrollermenu',
maxText : 30,
pageSize : 5
} ]
});
Dynamic Tab object:
var tabConfig = {
title : text,
bodyPadding : 3,
closeAction:'destroy',
autoScroll : true,
id : 'tab' + id,
closable : closable,
loader : {
loadMask : 'loading...',
autoLoad : true,
url : url,
scripts : true,
params : {
userId : 1
},
border : false,
appId : appIdx,
screenId : screenId,
gridType : gridType,
listeners : {
beforeclose : function(tab) {
debugger;
tab.removeAll(); //I tried doing this
tab.destroy(); //I tried doing this as well
return true;
}
}
};
Internal Panel code:
Ext.define('Ext.ux.window.VisualSQLQueryBuilder', {
extend: 'Ext.panel.Panel',
itemId: 'qb-VisualSQLQueryBuilderId',
renderTo: Ext.Element.get('divQueryBuilder'),
layout: {
type: 'border'
},
listeners:{
beforerender: function(thisa, eOpts ){
debugger;
/*if(Ext.ComponentQuery.query("#qb-VisualSQLQueryBuilderId").length > 1){
Ext.ComponentQuery.query("#qb-VisualSQLQueryBuilderId")[0].destroy();
}*/
Tab.MainTab = Ext.ComponentQuery.query("#qb-VisualSQLQueryBuilderId")[Ext.ComponentQuery.query("#qb-VisualSQLQueryBuilderId").length - 1];
}
},
items: [ .... screen components ... ]
});
Add Panel object to tab:
addedTab = ExtCont.add(tabConfig);
addedTab.show();
ExtCont.setActiveTab(addedTab);
Now this is what happens:
Open Tab (Name - Query Builder)
Code reaches the beforerender listener.
Ext.ComponentQuery.query("#qb-VisualSQLQueryBuilderId") has only one object inside it.
Everything works fine.
Now the problem starts
Close the tab
Code reaches beforeclose listener. Trying tab.removeAll() and tab.destroy()
Reopen tab - Query Builder
Code reaches beforerender listener.
Now Ext.ComponentQuery.query("#qb-VisualSQLQueryBuilderId") has two objects inside it. So it is retaining the object of the tab opened first time. And the second one is that of the tab opened just now.
How do I ensure whenever a tab is closed all its components get smoothly destroyed?

from TabPanel:
Note: By default, a tab's close tool destroys the child tab Component and all its descendants. This makes the child tab Component, and all its descendants unusable. To enable re-use of a tab, configure the TabPanel with autoDestroy: false.
so it could really be an ExtJS Bug cause autoDestroy: true is default. maybe you could open a ticket.

Related

Extjs - override collapse function

i'm new of Extjs; i have a panel with the item "collapsible: true" and it works fine but...
when my specific condition is true, i want to collapse the panel, and i want to disable the button used to expand it (therefore the panel doe not show anymore, even if the click is made).
It's possible do it?
I want a type of override method that doing other things, for example to show a div with few specific information in the page.
I use only javascript and Extjs.
thanks in advance and happy holidays
I added a bindable version
Fiddle
Using databinding to collapsible, you might also add the binding to the collapsed param
Please see my snippet. Can it resolve your issue ? Tell me if you have any question.
https://fiddle.sencha.com/fiddle/1fk9
Ext.application({
name : 'Fiddle',
launch : function() {
var parent = Ext.create('Ext.container.Container', {
title : 'Demo',
renderTo : Ext.getBody(),
layout : 'vbox',
items : [{
xtype : 'checkbox',
fieldLabel : 'Enable collapsible',
handler : function(self, v){
var panel = parent.down('panel');
panel.collapseTool.setVisible(v);
panel.getHeader().down('tool[type=up]').setVisible(!v);
},
checked : true
}, {
xtype : 'panel',
width : 500,
height : 400,
title : 'Collapsible demo',
collapsible : true,
tools : [{
type : 'up',
hidden : true
}]
}]
});
}
});

Way to render any component in extjs on fly

I am provided with built in extjs components classes.
I cannot change them as i am working on plugin.
I cannot override them as there are certain things which cannot be
predefined.
And also I want to change component for particular case, not all
cases.
Now If it will be possible that I pick that component from DOM,
change it any of property and render it there onwards. If it could
be done, then my work become lot easy.
Its completely a scenario. But still for ease in understanding, I am adding a sample code.
var tabPanel = Ext.create('Ext.tab.Panel', {
width : 300,
height : 200,
activeTab : 0,
items : [
{
title : 'Tab1',
bodyPadding : 10,
items : [
{
xtype : 'button',
text : 'B1'
}
]
},
{
title : 'Tab2',
items : [
{
xtype : 'button',
text : 'B2'
}
]
}
],
renderTo : Ext.getBody(),
autoRender : true
});
// Change title of tab panel
tabPanel.items.each(function(item) {
item.title = "text"+Math.random();
});
Now I want to remove this already rendered tab panel. And want to render it upon my choice wherever i want.
After lot of search, I find solution to problem. We can use doLayout() or update() function of component to fulfill purpose.

The right event to apply "scrollTo" to show a dynamically added nested panel

I have a panel in ExtJS6 modern (mobile) application that can scroll vertically only. Sub panels are added dynamically to it. I need to scroll the panel to its end after adding a new sub-panel in order to make it visible. This is done using this line:
Ext.getCmp('tabmainMessagesPanel').getScrollable().scrollTo(Infinity, Infinity, true);
I execute this line in a button click, and it works (but need to click the button manually). I tried to find the right event where I can add this line to do the scroll automatically, without success. I nearly tried all the possible relevant events of the sub-panel: show, add, added, activate, ... I also tried the events of the parent panel without success.
Apparently, these events happen before the scroller of the parent panel takes into account the added sub-panel, so it scrolls to the before-last one. I smell asynchronous behavior here. The proof is that I call the scrollTo method in a delayed task of 0.5 second and it works. But this solution is not reliable.
The question is: where (in which event of which component) this line of code should go in order to scroll the parent to its end correctly?
[EDIT]
Here is the part of the code concerning the question. First, the Message class:
Ext.define('MyApp.view.message.Message', {
extend : 'Ext.Panel',
xtype : 'message',
layout : 'hbox',
config : {
mBody : ''
},
listeners: {
added: function (element) {
MyApp.view.main.Global.scroller.delay(500); //start a delayed task to scroll parent panel
}
},
items: [
{
flex : 1
},
{
maxWidth: '80%',
width: 'auto',
html : '<div class="myClass">' + this.getMBody() + '</div>'
}
]
});
Here is the delayed task that scrolls the parent panel tabmainMessagesPanel to its end in order to show the newly-added message:
Ext.define('MyApp.view.main.Global', {
statics: {
scroller: Ext.create('Ext.util.DelayedTask', function() {
Ext.getCmp('tabmainMessagesPanel').getScrollable().scrollTo(Infinity, Infinity, true);
})
}
}
Now, the tab panel that contains the panel tabmainMessagesPanel that will contain the messages:
Ext.define('MyApp.view.main.TabMain', {
extend : 'Ext.tab.Panel',
mixins : [ 'Ext.mixin.Responsive' ],
xtype : 'tabmain',
responsiveConfig : {
portrait : {
items :
[
{
title : 'Messages',
layout : 'vbox',
items : [ {
xtype: 'panel',
layout : 'vbox',
height: '100%',
id: 'tabmainMessagesPanel',
scrollable : 'vertical',
style : 'background-color:#F0F0F0'
},
{
xtype : 'inputfield',
docked : 'bottom'
}]
},
{
title : 'Connect',
layout: 'vbox',
items : [
//some UI elements
]
}
]
},
//--------------------------------------------------
landscape : {
// same as portrait
}
},
//--------------------------------------------------
controller : 'tabmain',
viewModel : 'tabmain',
defaults : {
tab : {
iconAlign : 'top'
},
styleHtmlContent : true
}
});
Finally, this is an event in a controller that creates and adds a message to tabmainMessagesPanel whenever a new message arrives:
handle_message: function (mess) {
var p = Ext.create('MyApp.view.message.Message', {
mBody : mess.body
});
Ext.getCmp('tabmainMessagesPanel').add(p);
}
Here is the answer for this. I found it 6 months later. I post it here for the benefit of those who may have the same issue.
The solution is to define the event refresh of the scroller of the panel tabmainMessagesPanel, and scroll to the end in it. So, the definition of the panel tabmainMessagesPanel becomes:
{
xtype: 'panel',
layout : 'vbox',
height: '100%',
id: 'tabmainMessagesPanel',
scrollable : 'vertical',
listeners: {
initialize: function (me) {
me.getScrollable().on('refresh', function () {
me.getScrollable().scrollTo(Infinity, Infinity, true);
});
}
},
style : 'background-color:#F0F0F0'
}

Close Ext.Window from child html

I am new to ExtJS.
This is my window definition :
this.dialog = new Ext.Window({
title : "About us",
layout : 'anchor',
modal : true,
autoEl : {
tag : "iframe",
id: "myframe",
src : "../editor/actorseditor.html",
height: 500,
width : 600
} });
this.dialog.show();
I want to close my dialog window from "actorseditor.html".
How to achieve this. Also the opened window is not having close button.
Thanks in advance
This will only work if the html page in your iFrame is from the same application as your parent page. Or at least the protocol, subdomain, domain and port are all the same.
You will need to expose a global function in your parent page that will be called by the JavaScript running in the child page (iframe).
In your child page you call:
if (window.parent && window.parent.myGlobalFunction) {
window.parent.myGlobalFunction('hello!');
}
In your parent page you include the following global function (name it as you wish of course):
function myGlobalFunction(input){
console.log('message received:'+input);
MyApp.app.fireEvent('closeMyWindow',input);
}
This assumes that you are using MVC and you created property 'app' and set it to 'this' in the application launch function. And that you have a controller that is listening for aplication wide event like this:
Ext.define('MyApp.controller.Qnum', {
extend:'Ext.app.Controller',
init:function(){
this.control({
...
});
//listen for app wide event fired by : MyApp.app.fireEvent('closeMyWindow',input);
this.application.on({
closeMyWindow: this.closeWindowItsDrafty,
scope: this
});
},
closeWindowItsDrafty:function(){
//get reference to my window
//call myWindow.close();
}
I'll assume that in actorseditor.html, you must have a button
In this button you can set this listener:
listeners : {
click : function () {
Ext.getCmp('yourdialogid').close();
}
}
You also need to put an id to your dialog box.
Please try following inside your close button listener:
var parentDialogWindow = window.parent.Ext.cmp('ID_OF_DIALOG_WINDOW');
parentDialogWindow[parentDialogWindow.closeAction]();

Menu item in Ext-JS4

I am new to Ext-JS4. I am working on a project in which I am configuring a toolbar. I have added few buttons to the toolbar, one of which has a menu and the menu basically has a grid which is loaded from a JSON store. The grid is used within the menu due to such requirement in the project. The grid is loaded properly but I need access to the menu item being clicked within the menu. I want the text of the menu item which is clicked. The following code will better explain my question.
var store = Ext.create('Ext.data.Store', {
storeId : 'favStore',
model : favModel,
autoLoad : true,
groupField : 'group_header',
proxy : {
type : 'ajax',
url : '../../data/favorites.json',
reader : {
type : 'json',
root : 'favoritesMenu'
}
}
});
var favGrid = Ext.create('Ext.grid.Panel', {
store : store,
columns : [{
dataIndex : 'listItem',
width : 200
}],
features : [groupingFeature],
width : 200,
height : 275,
autoHeight : true,
border : false
});
var favMenu = Ext.create('Ext.menu.Menu', {
items : [favGrid],
listeners : {
'click' : function(store,item) {
alert('Item clicked= ');//tried item.text here but not working
}
}
});
In the alert method on the click event I want the text of the menu item clicked. I hope I am clear with the question. Can anyone give me some suggestions? Also can anyone suggest me some good blogs on Ext-JS4?
All these things are defined within the initComponent method of Ext.define() for toolbar.
You can use the documentation.
For me it was very usefull:
http://docs.sencha.com/ext-js/4-0/
I believe in your case you want the listener to be attributed to your grid, not the menu. Something like...
var favGrid = Ext.create('Ext.grid.Panel', {
store : store,
columns : [{
dataIndex : 'listItem',
width : 200
}],
features : [groupingFeature],
width : 200,
height : 275,
autoHeight : true,
border : false,
listeners: {
'itemclick': function(view, record, item, index, e, eOpts){
//Assuming 'name' is a fieldname in the record
alert('item clicked = ' + record.get('name'));
}
}
});
Check out the Ext.grid.Panel documentation here: http://docs.sencha.com/ext-js/4-0/#!/api/Ext.grid.Panel . Click on "events" at the top and find "itemclick".
or you can have your menu listen to the grid's event by relaying the events.
favMenu.relayEvents(favGrid, ['itemclick']);
favMenu.on('itemclick', me.onFavFunction, me);

Resources