extjs - How to define a window as unique ? - extjs

Is there a way to define a window as unique ?
What I mean exactly is: when the window is already open, I want it to get focus, instead of opening it again.
For now my menu click event just does:
onMenuItemClick: function(){
Ext.create('Mb.view.UniqueWindow').show()
},

Give it a unique id, then verify if it already exists before creating it, otherwise just show it, something like
function onMenuItemClick() {
var wnd = Ext.getCmp('myUniqueWindow');
if (!wnd) {
wnd = Ext.create('Ext.window.Window', {
id: 'myUniqueWindow',
title: 'Unique Window',
height: 200,
width: 400,
layout: 'fit',
closeAction: 'hide', // This is really important otherwise closing it will destroy the window!
items: { // Let's put an empty grid in just to illustrate fit layout
xtype: 'grid',
border: false,
columns: [{
header: 'Hello World'
}], // One header just for show. There's no data,
store: Ext.create('Ext.data.ArrayStore', {}) // A dummy empty data store
}
});
} else {
wnd.getEl().highlight()
}
wnd.show();
}
You can see a working sample here

Save a reference to it:
if (!MyApp.someWin) {
MyApp.someWin = new Ext.window.Window();
}
MyApp.someWin.show();

Related

Dispalying more than one message box one after other

I have requirement to show multiple info/alert messages one after other.
Here is my sample code
var messageQueueStore = Ext.create('Ext.data.Store', {
fields: ['type','Title','text','buttonConfig','callback'],
storeId: 'messageQueueStore'
});
function displayMessage(type, Title, Text, buttonConfig, callback){
messageQueueStore.loadData([{type: type, Title : Title, Text: Text, buttonConfig:buttonConfig, callback:callback}], true);
if(!Ext.MessageBox.isVisible()){
displayEachMessage();
}
}
function displayEachMessage(){
var firstRecord = messageQueueStore.getAt(0);
//We are currently handling only alert messages. If needed this method can be extended to hande other type of messages
if(firstRecord.get('type') == 'alert'){
Ext.MessageBox.show({
title : firstRecord.get('Title'),
msg : firstRecord.get('Text'),
buttons: Ext.Msg.OK,
listeners: {
beforeclose : function(){console.log("Before close");},
close : function(){console.log("close");},
hide : function(){console.log("hide");},
beforehide : function(){console.log("beforehide");},
},
fn : messageClosed
})
}
}
function messageClosed(){
// before close event needs to be handled as well
messageQueueStore.removeAt(0);
if(messageQueueStore.count() != 0){
displayEachMessage();
}
}
// And this is how i use this functionality
displayMessage('alert','first',"You are now seeing the first message");
displayMessage('alert','second',"This is the second message");
displayMessage('alert','third',"Here comes the third");
displayMessage('alert','fourth',"And this is the last");
This works perfectly fine when user clicks on the OK button. However when user clicks on the (x) button on the message box top right corner none of the events i am trying to listen are triggered.
And hence the subsequent messages are not displayed.
Any pointers on how to handle the close event on message box will be very helpful
Here is working sample: http://jsfiddle.net/kTpct/2/
function myAlert(title, message){
Ext.create('Ext.window.Window', {
width: 300,
height: 120,
autoDestroy: true,
title: title,
modal: true,
layout: 'fit',
bodyStyle: 'border:none; background-color: transparent;',
buttonAlign: 'center',
items: [{
xtype: 'container',
html: message
}],
buttons: [{
text: 'Ok',
listeners: {
click: {
fn: function (item, e) {
this.up('window').close();
}
}
}
}]
}).show();
}
for(i = 1; i <= 3; i++ ) myAlert('message ' + i, 'content of message ' + i);
You cannot achieve this with the Ext.MessageBox because it is a singleton and there is no way to guarantee that the previous alert was reset before you are updating the properties for the next alert. Only one can be visible at a time and back to back alerts with no blocking will cause you timing issues.
"Busy-Blocking" is also bad anyway because there is no "Await-Callback" in javascript.

change the background color of panels in extjs

In my project, I am trying to change the background color of all the panels inside a container. The code which I am trying is as follows:
container --> panel (don't change) --> panel (Change)
//Generated dynamically using for loop.
listeners: {
'render': function(panel) {
panel.body.on('click', function() {
//here change the background color of all the panels inside the container>panel.
});
}
}
What should I write to change the background color of the only panels which are present inside the parent panels of a main container?
I tried:
Ext.each('panel',function(){this.body.setStyle('background','white')}),
But the above approach is giving me the following error:
Uncaught TypeError: Cannot call method 'setStyle' of undefined
EDIT:
Here, I am looking for a method of extjs which quite do the same work as jQuery's children().
$('#containerID').children('panel').children('panel').css(change background color);
Based on your requirements you will always have a sum of 9 components you are looking at -1 the you start from. The shortest way is to use the each() method of the MixedCollection (at runtime all items are within a MixedCollection)
'render': function(panel) {
panel.body.on('click', function() {
panel.items.each(function(p){ p.body.setStyle('background','white'); }, this)
},this);
}
This may not be the variant with the best performance but knowing your requirement from the last question I can say that this is the easiest. And in addition it will be easy to maintain. And read the article about delegates that I posted in the comments of the last question!
I hope there is now typo, cause it is untested
Update
Well, you are looking for the ownerCt property here (at least that is the easiest way). But there are some mightier navigation methods up() / down() both can be feeded with a ComponentQuery string. Leave the up() arguments empty will return the immediate owner/activater (basically the same as ownerCt).
Following a working example:
var childItems = [], items = [];
for (i = 0; i < 9; ++i) {
childItems.push({
xtype: 'container',
width: 50,
height: 50,
html: i + '',
style: {borderColor:'#000000', borderStyle:'solid', borderWidth:'1px'},
listeners: {
'afterrender': function(panel) {
panel.el.on('click', function(e,t) {
panel.el.on('click', function(e,t) {
panel.el.setStyle('background','red');
panel.ownerCt.items.each(function(p){ if(panel.el.id != p.id) p.el.setStyle('background','white'); })
});
}
}
});
}
for (i = 0; i < 9; ++i) {
items.push({
xtype: 'container',
layout: {
type: 'table',
columns: 3
},
style: {borderColor:'#000000', borderStyle:'solid', borderWidth:'1px'},
items: childItems
});
}
Ext.create('Ext.container.Container', {
layout: {
type: 'table',
// The total column count must be specified here
columns: 3
},
renderTo: Ext.getBody(),
style: {borderColor:'#000000', borderStyle:'solid', borderWidth:'1px', margin: '30px'},
items: items
});
Update 2
To reset all try this (untested)
'afterrender': function(panel) {
panel.el.on('click', function(e,t) {
panel.el.setStyle('background','red');
panel.ownerCt.ownerCt.items.each(function(op){
op.items.each(function(p){
if(panel.el.id != p.id)
p.el.setStyle('background','white');
})
}, this)
});
}
JSFiddle

ExtJs - How to remove all floating components

Using ExtJs 4.1
Is there a way to query all floating components (windows, message boxes, etc.)?
My aim is to remove (destroy) all floating objects. It would be sufficient to "get" them on the first hand.
Well simply do it by using the Ext.WindowManager which is responsible for all floating components by default.
Following should work:
Ext.WindowManager.each(function(cmp) { cmp.destroy(); });
Here's a example JSFiddle:
Ext.create('Ext.window.Window', {
title: 'Hello',
height: 200,
width: 400,
layout: 'fit',
items: { // Let's put an empty grid in just to illustrate fit layout
xtype: 'grid',
border: false,
columns: [{header: 'World'}], // One header just for show. There's no data,
store: Ext.create('Ext.data.ArrayStore', {}) // A dummy empty data store
}
}).show();
Ext.Function.defer(function(){Ext.WindowManager.each(function(cmp) { cmp.destroy(); })}, 5000);
For further reading on DOM-Query
Edit destroy only defined types
For that case go with the xtype of the component and check it.
Ext.WindowManager.each(function(cmp) { if (cmp.xtype === 'window') cmp.destroy(); });

ExtJS Pop-up Window Form data loading

I use Grid panel. When I select the row in the grid I get the following results:
If I render the Form in 'document.body' everything is OK, and form
fields are filled.
If I, same Form start in Window panel, Form fields are empty.
When I use both, Form which is rendered in the 'document.body' is
closed, and Form fields in Window are filled.
Where I make mistake.
// Grip panel part
sm: new Ext.grid.RowSelectionModel({
singleSelect: true,
listeners: {
rowselect: function(sm, index, record) {deleteWindow.show();}
}
})
// End Grid panel part
var myForm = new Ext.form.FormPanel({
title:"Basic Form",
width:425,
frame:true,
items: [
new Ext.form.TextField({
id:"to",
fieldLabel:"To",
width:275,
allowBlank:false,
blankText:"Please enter a to address",
readOnly: true
}),
new Ext.form.TextField({
id:"subject",
fieldLabel:"Subject",
width:275,
allowBlank:false,
blankText:"Please enter a subject address",
readOnly: true
}),
],
buttons: [
{text:"Cancel"},
{text:"Save"}
]
});
var deleteWindow = new Ext.Window({
id: 'id_deleteWindow',
title: 'Delete',
closable:true,
width: 750,
height: 380,
plain:true,
layout: 'fit',
items: myForm
});
var id_test = 2; // This is only for this problem
//myForm.render(document.body); // When using this code everything is ok, and form fields are filled
myForm.getForm().load({
url:'ggg.php',
params:{
id: id_test
}
});
JSON data
{success:true,results:[{"id_test":"1","to":"a","subject":"aa"}]}
I would suggest the following changes to the code:
In place of using the id property on the TextField (say, id: 'subject'), use name property (name: 'subject')
Just curious....since you are handling the rowselect event on the grid, you might want to load the selected record in the form panel rather than loading it again. If this is the case, then you may call the loadRecord() method on the form panel and pass the record object to it and then call the show() method on the window
I figured out that when load is called on form, ExtJS tries to access form dom element to determine form method. I've found 2 solutions:
Add method to the form config
Load data to form after window is showed
Here is code for second solution:
var deleteWindow = new Ext.Window({
id: 'id_deleteWindow',
title: 'Delete',
closable:true,
width: 750,
height: 380,
plain:true,
layout: 'fit',
items: myForm,
listeners: {
show: function() {
var form = this.items.get(0);
form.getForm().load({
url:'ggg.php',
params:{
id: id_test
}
});
}
}
});
deleteWindow.show();

Building a TriggerField with PopUp Window

I built a triggerField and when i press at it, i want to have a popup, that is appended to the button in the triggerfield(so when i click anywhere else it shall disappear and it shall pop out up to the button when i click at the button just like a datepicker-popup)
I somehow managed to do something like that with an Ext.window but the offset and postion doesnt match.
This all should be contained in a row editor.
my Code:
new Ext.grid.GridPanel({
store: Store,
region:'center',
height:150,
//minWidth:700,
autoScroll:true,
listeners:{},
plugins:[new Ext.ux.grid.RowEditor()],
tbar: [{
iconCls: 'icon-user-add',
text: ' hinzufügen',
handler: function(){
alert("abc");
}
},{
ref: '../removeBtn',
iconCls: 'icon-user-delete',
text: 'löschen',
disabled: true,
handler: function(){
editor.stopEditing();
var s = grid.getSelectionModel().getSelections();
for(var i = 0, r; r = s[i]; i++){
store.remove(r);
}
}
}],
columns: [{
header: 'Monate',
dataIndex: 'MONAT',
width: 50,
sortable: true,
editor:
new Ext.form.TriggerField({"id":"EditorMonate",items:[],
"onTriggerClick":function(thiss){
if(!Ext.getCmp("autoWMonate")){
var monate=new Ext.Window({"x":Ext.getCmp("EditorMonate").x,closeAction:"hide",width:275,id:"autoWMonate",layout:"table",layoutConfig: {columns: 10}});
var text;
for(var mon=1;mon<13;mon++){
text=mon;
mon?mon:text="0";
if(mon<10)
text="0"+mon;
monate.items.add(
new Ext.Button({cls:"x-btn",value:parseInt(text),selected:true,"text":text,id:text
}}}));}
} Ext.getCmp("autoWMonate").hidden?Ext.getCmp("autoWMonate").show():Ext.getCmp("autoWMonate").hide();
}})
}
}]
})
Problem sovled with:
{
header: 'WochenTage',
dataIndex: 'WOCHE',
width: 100,
sortable: true,
editor: new Ext.form.TriggerField({
onTriggerClick: function(e) {
if (!this.menu) {
this.menu = new Ext.menu.Menu({
items:[{xtype:"label",text:"1"},{xtype:"label",text:"2"}]
// the items should have event listeners that set the field value accordingly
});
}
// here you would want to sync the items in the menu with the field value (this.getValue())
// before you show the menu -- keep in mind that the menu and its children might not be rendered yet
this.menu.showAt(e.getXY()); // or this.menu.show(this.getEl(), 'tl-bl?');
}
})
}
I did something like this by looking at the code of the date picker and generalizing the idea there - use a menu component for the popup behavior, and put whatever you like as a single component contained by the menu.

Resources