ExtJs open a view from the same view - extjs

I am opening a view using the following code
var reader = Ext.create('Ext.view.ReaderWindow', {});
reader.show();
Inside the ReaderWindow view on clicking an a tag element,i am opening the same view (using the code above) again but with different content.
Once i close the ReaderWindow which i opened second. I could not able to see the ReaderWindow which i opened first.
My question is how to use the same view twice. In other words how to open the same view from the view itself.
Ext.define('Ext.view.ReaderWindow', {
extend: 'Ext.window.Window',
alias: 'widget.reader',
id: 0,
file_path: '',
file_title: '',
file_type: '',
id: 'reader',
itemId: 'reader',
maxHeight: 800,
maxWidth: 900,
minHeight: 300,
minWidth: 500,
layout: {
type: 'anchor'
},
title: 'File Reader',
modal: true,
initComponent: function() {
var me = this;
Ext.applyIf(me, {
items: [
{
xtype: 'form',
anchor: '100% 100%',
id: 'reader_form',
itemId: 'reader_form',
maxHeight: 800,
maxWidth: 900,
minHeight: 300,
minWidth: 500,
autoScroll: true,
bodyPadding: 10,
items: [
{
xtype: 'displayfield',
anchor: '100%',
id: 'file_contents',
itemId: 'file_contents',
maxWidth: 900,
minWidth: 50,
hideLabel: true,
name: 'file_contents'
}
]
}
],
dockedItems: [
{
xtype: 'toolbar',
anchor: '100% 5%',
dock: 'bottom',
id: 'reader_toolbar',
itemId: 'reader_toolbar',
items: [
{
xtype: 'tbfill'
},
{
xtype: 'button',
handler: function(button, event) {
me.destroy();
},
id: 'close_btn',
itemId: 'close_btn',
text: 'Close',
tooltip: 'Close the file reader window.'
}
]
}
],
listeners: {
beforerender: {
fn: me.reader_windowBeforeRender,
scope: me
}
}
});
me.callParent(arguments);
},
reader_windowBeforeRender: function(component, eOpts) {
this.setTitle(this.file_title + ' for ID ' + this.id);
this.setFormTitle(this.file_path);
Ext.model.FileReaderModel.load(this.id, {
params: {
'file': this.file_path,
'file_type': this.file_type
},
success: function(file_reader) {
var contents_field = Ext.ComponentQuery.query('[name=file_contents]')[0];
var contents = file_reader.get('file_contents');
var pattern = /(\/.*?\.\S*)/gi;
contents = contents.replace(pattern, "<a href='#' class='samplefile'>$1</a>");
contents_field.setValue('<pre>' + contents + '</pre>');
Ext.select('.samplefile').on('click', function() {
var sample_file_path = this.innerHTML;
var Id = this.id;
var reader = Ext.create('Ext.view.ReaderWindow', {
id: Id,
file_path: sample_file_path,
file_title: 'Sample File',
file_type: 'output'
});
reader.show();
});
},
failure: function(file_reader, response) {
}
});
},
setFormTitle: function(file_path) {
var form_panel = Ext.ComponentQuery.query('#reader_form');
form_panel[0].setTitle('File is: ' + file_path);
}
});

One big problem I see is that you are giving some of your components a non-unique id property. When an id is specified, ExtJS uses it as the ID of the underlying DOM element instead of generating a unique one. This is almost certainly not what you want on a reusable component given that IDs need to be unique within the DOM.
Even if you are generating a unique id when you construct the top-level Window object, its child components (reader_form, file_contents, etc) are not getting a unique id.
In other words, when your second window is shown, you now have multiple DOM elements with the same ID and that breaks the DOM. In my ExtJS application, I've yet to find a valid use case for overriding the id property, but that doesn't mean there isn't one. It would most likely be for global scaffolding elements or something where your application guarantees only one instance of a particular component will ever be instantiated.
You can use itemId because that's an ExtJS construct that doesn't get translated into the DOM. It gives you similar features to having an ID on a DOM element, except that it behaves more intuitively in the context of the ExtJS component hierarchy and selector APIs.
My recommendation is to remove the id property from your components and let ExtJS generate unique ones for you and leverage itemId only where you absolutely must have a known identifier on your component.

Related

Getting undefined on textarea

I am getting undefined on textareafield.. I have se the id to: msgArea, but extjs changes the id to: msgArea-inputEl on runtime. I have tried using both these ids, but getting undefined on both.
isoNS.PanelQDisableInfoMsg = Ext.create("Ext.window.Window", {
title: 'Improtant information',
width: $(document).width() / 2,
height: $(document).height() / 3,
modal: true,
resizable: false,
style: 'position: absolute; top: 100px;',
id: 'infoWindow',
layout: {
align: 'stretch',
type: 'vbox'
},
dockedItems: [
{
xtype: 'textareafield',
fieldStyle: 'background-color: #DFE9F6; background-image: none;',
readOnly: true,
height: ($(document).height() / 3) - 80,
inputId: 'msgArea',
},
{
xtype: 'button',
text: 'Ok',
id: 'OkButton',
docked: 'bottom',
handler: function() {
var win = Ext.getCmp("infoWindow");
win.close();
}
},
{
xtype: 'button',
text: 'Test',
handler: function() {
var textArea = Ext.getCmp("msgArea");
textArea.setValue("Text changed");
}
}
]
}).show();
The code that gives the undefined is this part:
{
xtype: 'button',
text: 'Test',
handler: function() {
var textArea = Ext.getCmp("msgArea-inputEl");
textArea.setValue("Text changed");
}
}
what am I doing wrong?
Also. How do I make extjs NOT to change the id on runtime from msgArea to: msgArea-inputEl?
I don't know the exact version of your Extjs. The api on http://docs.sencha.com/extjs/4.0.7/ says:
inputId : String
The id that will be given to the generated input DOM element. Defaults
to an automatically generated id. If you configure this manually, you
must make sure it is unique in the document.
Available since: 4.0.0
If you uses an older version of Extjs, the api offers the object property id:. According these descriptions if you use this, the framework won't assign an automatic generated object id to this element.

Cannot get the object of a tabpanel

I have a grid in the center region of a border layout. When a specific item is clicked in the grid, I need to change the center region to display a tab panel. I am having trouble getting the tabpanel object.
In the ctrlpanel file, on the grid listener, I am using componentQuery to get the tabpanel('ccmain') object. It returns undefined.
I was using componentQuery to get 'ccmain' in the centerpanel file(lays out center region) successfully, but when I moved this code to the ctrlpanel file(one of the items in centerpanel) it fails. ComponentQuery no longer returns the tabpanel 'ccmain'. ComponentQuery does return the centerpanel or the viewport. I attemped to do centerpanel or viewport.down to find 'ccmain', but that also returns undefined. If you can tell me how to get the tabpanel or what I am doing wrong, I would appreciate it. Thanks for your time.
ctrlPanel.js
Ext.define('ServcSol.view.CtrlPanel',{
extend: 'Ext.Panel',
alias: 'widget.ctrlPanel',
xtype: 'ctrlPanel',
itemId: 'ctrlPanel',
requires:[
'ServcSol.store.FacilityStore'
],
initComponent: function () {
var me = this;
Ext.applyIf(me, {
items: [
{
xtype: 'panel',
height: 750,
title: 'Control Panel',
items: [
{
xtype: 'gridpanel',
padding: '20 20 5 20',
store: 'WorkHistoryStore',
height: 590,
width: '100%',
border: true,
columns: [
{
width: 110,
dataIndex: 'wrkhistDate',
text: 'Due Date'
},
{
width: 100,
dataIndex: 'wrkType',
text: 'Work Type'
}
],
listeners : {
itemclick: function(dv, record, item, index, e)
{
if(record.get('wrkType') == 'Test')
{
var tabPanel = Ext.ComponentQuery.query('ccmain')[0];
console.log('tabPanel is: ', tabPanel);
var tabIndex = tabPanel.items.findIndex('id', 'hazard');
var center = Ext.ComponentQuery.query('centerpanel')[0];
center.getLayout().setActiveTab(tabIndex);
}
ccmain.js
Ext.define('ServcSol.view.ccMain', {
extend: 'Ext.tab.Panel',
itemId: 'ccmain',
alias: 'widget.ccmain',
xtype: 'ccmain',
initComponent: function () {
var me = this;
Ext.applyIf(me, {
items: [
{
xtype: 'facility'
},
{
xtype: 'hazListing'
},
{
xtype: 'hazard'
},
{
xtype: 'testFormRP'
},
{
xtype: 'testFormDC'
}
]
});
this.callParent(arguments);
}
});
One of the reasons can be that ccmain is not instantiated as only instantiated components can be found by ComponentQuery.query. Then, even if ccmain would be found you cannot set its active item that way. Easiest is to assign tabs itemIds and then call setActiveTab:
tabPanel.setActiveTab(itemIdOfTheTab)

ExtJs on click fires number of times the window is opened

In the before render event of the window. i have this code
Ext.define('Ext.view.ReaderWindow', {
extend: 'Ext.window.Window',
alias: 'widget.reader',
id1: 0,
file_path: '',
id: 'reader',
itemId: 'reader',
maxHeight: 800,
maxWidth: 900,
minHeight: 300,
minWidth: 500,
layout: {
type: 'anchor'
},
title: 'File Reader',
modal: true,
initComponent: function() {
var me = this;
Ext.applyIf(me, {
items: [{
xtype: 'form',
anchor: '100% 100%',
itemId: 'reader_form',
maxHeight: 800,
maxWidth: 900,
minHeight: 300,
minWidth: 500,
autoScroll: true,
bodyPadding: 10,
items: [{
xtype: 'displayfield',
anchor: '100%',
itemId: 'file_contents',
maxWidth: 900,
minWidth: 50,
hideLabel: true,
name: 'file_contents'
}]
}],
listeners: {
beforerender: {
fn: me.reader_windowBeforeRender,
scope: me
}
}
});
me.callParent(arguments);
},
reader_windowBeforeRender: function(component, eOpts) {
Ext.model.FileReaderModel.load(this.id1, {
params: {
'file': this.file_path
},
success: function(file_reader) {
var form_panel = current.query('#reader_form');
var contents_field = form_panel[0].getComponent('file_contents');
var contents = file_reader.get('file_contents');
var pattern = /(\/.*?\.\S*)/gi;
contents = contents.replace(pattern, "<a href='#' class='sample'>$1</a>");
contents_field.setValue('<pre>' + contents + '</pre>');
Ext.select('.sample').on('click', function() {
var path = this.innerHTML;
var Id1 = this.id1;
var reader = Ext.create('Ext.view.ReaderWindow', {
id1: Id1,
file_path: path
});
reader.show();
});
},
failure: function(file_reader, response) {
}
});
},
});
for "a tag" i have assigned "sample" class. When a link is clicked, it opens a new window (but the same window is used to show the content).
The problem is if i click the a tag first time, then on click is called once. Then after i close the window and click a tag again..this time it fires twice. So depending on number of times i open and close..the click event is called so many times.
It looks like every time i open the window same event is registered multiple times. But i want to register the event only once.Any time i click a link, only once it should call the click event.

Extjs: Reuse the same grid in TabPanel

in a Extjs application I have a Grid and a Tabs line over it. Content of the Grid depends on the selected Tab.
Say tabs has Jan-Feb-Mar-... values. Clicking of the Tab I would reload grid's store
Question: is it possible to avoid duplicating of the 12 grid components in favor to have one shared instance?
Thanks
Disclaimer: searching at the sencha's forum, google, stackoverflow was not successful :(
It is, but it would require more effort than it is worth. Just create a prototype for your component, so that you can create new instances really quickly.
I haven't tried this myself, but I imagine that you could create a TabPanel with empty tabs and size the TabPanel so that only the tab strip is visible. Under that (using the appropriate layout, border, vbox, etc.) create your GridPanel and use the TabPanel's activate event to reload the grid based on the currently-active tab.
Hope the following implementation meet your needs
1. Create your custom grid and register it
2. place it tab panel
As the grid is created using xtype, it would not create 12 instances when you change tabs.
Application.PersonnelGrid = Ext.extend(Ext.grid.GridPanel, {
border:false
,initComponent:function() {
Ext.apply(this, {
store:new Ext.data.Store({...})
,columns:[{...}, {...}]
,plugins:[...]
,viewConfig:{forceFit:true}
,tbar:[...]
,bbar:[...]
});
Application.PersonnelGrid.superclass.initComponent.apply(this, arguments);
} // eo function initComponent
,onRender:function() {
this.store.load();
Application.PersonnelGrid.superclass.onRender.apply(this, arguments);
} // eo function onRender
});
Ext.reg('personnelgrid', Application.PersonnelGrid);
var panel = new Ext.TabPanel({
items:[{
title:'Jan',
items: [{xtype:'personnelgrid'}]
}, {
title: 'Feb',
items: [{xtype:'personnelgrid'}]
}
....
{
title: 'Dec',
items: [{xtype:'personnelgrid'}]
}]
})
Since this is the only place discussed about this until now, I share what I just found.
The trick is use dockedItems in ExtJs 4 (Not sure either grid can be added into tbar in ExtJs 3)
When changing the active tab, only body will be change but not the docked item. Just set the grid height equal to the body during boxready and resize so that we can't see the body anymore.
This is the code for ExtJs 4.2 MVC that also make use of refs.
Ext.define('app.controller.Notification', {
extend: 'Ext.app.Controller',
views: ['notification.List'],
stores: ['Notification'],
models: ['Notification'],
refs: [{
ref: 'pnlNotif',
selector: 'pnlNotif'
}, {
ref: 'notifList',
selector: 'notifList'
}],
init: function () {
this.control({
'dbPnlNotif': {
added: this.pnlNotifAdded,
boxready: this.calcNotifListSize,
resize: this.calcNotifListSize,
tabchange: this.pnlNotifTabChange
}
});
},
pnlNotifAdded: function (pnlNotif) {
pnlNotif.add({ title: '1', html: '1' });
pnlNotif.add({ title: '2', html: '2' });
pnlNotif.add({ title: '3', html: '3' });
},
calcNotifListSize: function (pnlNotif) {
// calc the notification list height to make sure it use the whole body
// This way we can use only one instance of list to display for each tabs
// because the list is rendered as dockedItems
var height = pnlNotif.getHeight();
var headerHeight = pnlNotif.getDockedItems()[0].getHeight();
var tabBarHeight = pnlNotif.getDockedItems()[1].getHeight();
height = height - headerHeight - tabBarHeight;
if (this.getNotifList().getHeight() !== height) {
this.getNotifList().setHeight(height - 1);// - 1 to include border bottom
}
},
pnlNotifTabChange: function (pnlNotif, newTab) {
// do something to filter the list based on selected tab.
}
});
Ext.define('ML.view.Notification', {
extend: 'Ext.tab.Panel',
alias: ['widget.pnlNotif'],
title: 'Notification',
dockedItems: [{
xtype: 'notifList'
}]
});
Ext.define('ML.view.notification.List', {
extend: 'Ext.grid.Panel',
alias: 'widget.notifList',
dock: 'top',
store: 'Notification',
initComponent: function () {
this.columns = [
...
];
this.callParent(arguments);
}
});
Try this
var gridJanName = Ext.create('Ext.grid.Panel', {
enableColumnHide: false,
autoScroll:true,
store: storeJanNameGroup,
border:true,
stripeRows: true,
columnLines:false,
loadMask: true,
tbar:tbgridTools,
margin: '1 1 1 1',
pageSize: 100,
maxWidth:700,
features: [groupFeature],
selModel: {
mode: 'MULTI'
},
columns: [
{xtype:'rownumberer',width:50},
{dataIndex:'id', hidden:true},
//etc
]
});
var gridFebName = Ext.create('Ext.grid.Panel', {
enableColumnHide: false,
autoScroll:true,
store: storeJanNameGroup,
border:true,
stripeRows: true,
columnLines:false,
loadMask: true,
tbar:tbgridTools,
margin: '1 1 1 1',
pageSize: 100,
maxWidth:700,
features: [groupFeature],
selModel: {
mode: 'MULTI'
},
columns: [
{xtype:'rownumberer',width:50},
{dataIndex:'id', hidden:true},
//etc
]
});
//
//etc grid
//
var JanPanel = Ext.create('Ext.panel.Panel', {
title:'Jan',
bodyPadding: 5,
Width:780,
layout: {
type: 'hbox',
align: 'stretch'
},
items: [gridJanName]
});
var FebPanel = Ext.create('Ext.panel.Panel', {
title:'Feb',
bodyPadding: 5,
Width:780,
layout: {
type: 'hbox',
align: 'stretch'
}
//,items: [gridFebName]
});
var MarPanel = Ext.create('Ext.panel.Panel', {
title:'Mar',
bodyPadding: 5,
Width:780,
layout: {
type: 'hbox',
align: 'stretch'
}
//,items: [gridMarName]
});
//etc
var eachMonthstabs = Ext.create('Ext.tab.Panel', {
minTabWidth: 130,
tabWidth:150,
//Width:750,
scroll:false,
autoHeight: true,
id:'timestabs',
enableTabScroll:true,
items: [
{
xtype:JanPanel
},
{
xtype:FebPanel
},
{
xtype:MarPanel
}
///etc
]
});
For me good solution was to use a left toolbar called lbar with list of buttons and a single grid instead of tabpanel

Resetting event handlers in ExtJS

I have a page where there are multiple records. Each record has a button to open a dialog box to create a name. The name then creates a related record in the database and updates the source record.
There is a single dialog box instantiated and I want to show the dialog box, get the result and return it to the correct record.
The code below works once but doesn't work the second time. I can see the the Create button gets clicked but the event doesn't got caught.
Many thanks for your help.
TrailNamePresenter.prototype.onCreateTrailClick = function (trailSegment, combo, personalRouteId) {
if (!this.createTrailWindow) {
this.createTrailWindowPanel = new CreateTrailFormPanel();
this.createTrailWindow = new Ext.Window({
title: 'Create Trail',
closable: true,
closeAction: 'hide',
plain: true,
items: [this.createTrailWindowPanel],
id: 'createtrailwindow'
});
}
this.createTrailWindowPanel.on('createTrail', this.getCreateTrailHandler(personalRouteId, trailSegment, combo), null, {single:true});
this.createTrailWindow.show();
};
TrailNamePresenter.prototype.getCreateTrailHandler = function(personalRouteId, trailSegment, currentTrailCombo) {
var thisPersonalRouteId = personalRouteId;
var thisPresenter = this;
var thisCurrentTrailCombo = currentTrailCombo;
var thisTrailSegment = trailSegment;
return function(newTrailName) {
thisPresenter.mapEditorService.createPersonalTrail(newTrailName, thisPersonalRouteId, thisPresenter.getCreateTrailServiceHandler(thisCurrentTrailCombo, thisTrailSegment));
};
};
CreateTrailFormPanel = Ext.extend(Ext.form.FormPanel, {
initComponent: function() {
Ext.apply(this, {
id: 'createtrailpanel',
width: 500,
frame: true,
bodyStyle: 'padding: 10px 10px 0 10px;',
labelWidth: 50,
defaults: {
anchor: '95%',
msgTarget: 'side'
},
items: [
{
id: 'crt_trailnamefield',
xtype: 'textfield',
fieldLabel: 'Trail Name'
}
],
buttons: [{
text: 'Create',
handler: this.getCreateClickHandler()
},{
text: 'Cancel',
handler: function(b, e){
Ext.getCmp('createtrailwindow').hide();
}
}]
});
this.addEvents('createTrail');
CreateTrailFormPanel.superclass.initComponent.apply(this, new Array());
}
});
CreateTrailFormPanel.prototype.getCreateClickHandler = function() {
var thisPanel = this;
return function() {
var trailNameField = Ext.getCmp('crt_trailnamefield');
alert('click');
thisPanel.fireEvent('createTrail', trailNameField.getValue());
};
};
In ExtJS, when you have components that will belong to a parent. I would suggest using itemID, otherwise the ability of reuse of the component across your web application is reduced because id acts similarly to a singleton. Also on the action, you have {single:true} which will remove the listener after the first trigger. IF you remove that, it may solve your issue

Resources