Add a Key Event Listener to a programmatically generated MessageBox using ExtJS4 - extjs

I am building an ExtJS4 web application and there's a part there where I show a confirmation dialog to a user to confirm if the user wants to push through with the action. I use a programmatically generated MessageBox to ask the user and the user can click Yes or No.
Here is my code:
Ext.MessageBox.show({
title: alertHeader,
msg: alertMessage,
buttons: Ext.MessageBox.YESNO,
icon: Ext.MessageBox.WARNING,
cls: 'msgbox',
fn: function(btn){
//if user clicks yes, ask for override button
console.log('btn value = ' + btn);
if(btn ==='yes'){
//more code here
}
});
This works as intended, the program follows through with the appropriate actions based on the user selection (Yes or No). However, I want to add functionality wherein the user can simply press Y or N in the keyboard and the program will still execute as if Yes or No was actually pressed in the dialog.
However, I don't know how to go about adding a KeyEvent Listener to a MessageBox and the documentation is of little help.

Check Ext.util.KeyMap (and Ext.EventObject for key constants), also we have to set focus on our window to listen keyup events on it.
I create simple fiddle to illustrate how it works - Key map with message window.
Its not complete solution, but I guess rest you can do on your own.
As simple example you can do your logic directly on keypress and destroy myConfWindow or myConfWindow.down() to certain button and "click" it. But I guess that you want to use this message box in multiple places in your app, so its better to extend Ext.MessageWindow and add keymap there.

Attach this getKeyMapForKeyPressSubmit() method to your message box
'afterrender' : function() {
var map = this.getKeyMapForKeyPressSubmit();
}
And Method
getKeyMapForKeyPressSubmit : function (target, scope) {
var me = this;
return new Ext.util.KeyMap({
target : target,
binding : [{
key : 89, //Key for Y button - Ext.EventObject.Y
fn : function (key, e) {
//your logic for Yes button
}
}, {
key : 78, //Key for N button - Ext.EventObject.N
fn : function (key, e) {
//your logic for NO button
}
}
],
scope : scope
});
},

You can get a key map of MessageBox through getKeyMap. Add a new key listener to it in afterrender listener.
var myMsg = Ext.create('Ext.window.MessageBox', {
closeAction: 'destroy',
listeners: {
afterrender: function() {
this.getKeyMap().on(Ext.event.Event.Y, function() {
console.log("Yes");
}, this);
this.getKeyMap().on(Ext.event.Event.N, function() {
console.log("No");
}, this);
}
}
}).show({
title: 'Custom MessageBox Instance',
message: 'I can exist along with Ext.Msg'
});

Related

override messagebox and add icons to the default buttons

Does anyone know here how to override the messagebox to put icons for the buttons? i.e: check icon for YES/OK, cross button for NO, etc.
I've tried to override the makeButton function of Ext.window.MessageBox but it doesn't seem to work and doesn't even hit the debugger:
Ext.override(Ext.window.MessageBox, {
makeButton: function (btnIdx) {
debugger;
var btnId = this.buttonIds[btnIdx];
return new Ext.button.Button({
handler: this.btnCallback,
itemId: btnId,
scope: this,
text: this.buttonText[btnId],
minWidth: 75,
iconCls: ['check', 'no', 'cancel', 'blah'][btnId]
});
}
});
As #scebotari66 have stated, Ext.Msg and Ext.MessageBox are singletons of Ext.window.MessageBox. So when you override Ext.window.MessageBox.makeButton, this will have no effect if you are using the singletons for this class.
However, there is a way to apply your overrides to Ext.window.MessageBox to the singleton. Guess how.
(drumroll)
tantantanan!
Ext.MessageBox = Ext.Msg = new Ext.window.MessageBox();
Yep, that's correct. You just need to re-assign the singleton after your override.
So:
Ext.override(Ext.window.MessageBox, {
makeButton: function (btnIdx) {
var btnId = this.buttonIds[btnIdx];
return new Ext.button.Button({
handler: this.btnCallback,
itemId: btnId,
scope: this,
text: this.buttonText[btnId],
iconCls: ['okbutton', 'yesbutton', 'closebutton', 'cancelbutton'][btnIdx],
minWidth: 75 //or you can also remove this to make the icons close to the label
});
}
});
//re-assign singleton to apply overrides
Ext.MessageBox = Ext.Msg = new Ext.window.MessageBox();
Next time you call Ext.Msg.alert(), your icons are now showing too.
I hope you find this helpful.
NOTE: The iconCls config should be in the order [ok, yes, no, cancel]
As you can see from the source code, the makeButton method is called from initComponent of Ext.window.MessageBox.
I assume that you are using the Ext.MessageBox (or Ext.Msg) singleton instance for displaying message boxes. This instance is created in the callback function immediately after the Ext.window.MessageBox is created (check the third argument from Ext.define). This also means that it happens before your override.
So you can directly override the buttons of the singleton instance like so:
Ext.Msg.msgButtons.ok.setIconCls(okBtnCls);
Ext.Msg.msgButtons.yes.setIconCls(yesBtnCls);
Ext.Msg.msgButtons.no.setIconCls(noBtnCls);
Ext.Msg.msgButtons.cancel.setIconCls(cancelBtnCls);
You can also rely on your makeButton override if you will show message boxes by creating a new instance of the class:
var myMsg = Ext.create('Ext.window.MessageBox', {
closeAction: 'destroy'
}).show({
title: 'Custom MessageBox Instance',
message: 'I can exist along with Ext.Msg'
});

Need to set class/id values on buttons in Extjs MessageBox

Our testing team require IDs or class values to be set on the HTML elements in our message popup boxes. This is for their automated tests.
I can pass in a class value for the dialog panel by passing in a cls value like so:
Ext.Msg.show({
title:'Reset Grid Layout',
msg: 'Are you sure that you want to reset the grid layout?',
cls:'Reset-Grid-Layout-Message',
buttons: Ext.Msg.YESNO,
fn: function (response) {
if (response == 'yes') {
}
},
icon: Ext.window.MessageBox.QUESTION
});
Now we also need it on the buttons, and also on the text being displayed. Is there some way of getting a cls value onto the buttons?
I was thinking it may be possible to expand the button parameter into something like :
buttons : [{name:'but1', cls:'asdf'}, {name:'but2', cls:'asdf2'}]
But google is not giving me back anything useful.
If your testing team uses Selenium for their automated test, adding ids/classes in every component could be difficult for both of you.
Overriding components in Ext is a good solution, but I don't recommend this because it will affect all your components. Unless you know what you're doing.
I suggest, extend Ext.window.MessageBox and generate classes for your buttons based on your parent cls.
// Put this somewhere like /custom/messagebox.js
Ext.define('App.MyMessageBox', {
extend: 'Ext.window.MessageBox'
,initConfig: function(config) {
this.callParent(arguments);
}
,makeButton: function(btnIdx) {
var me = this;
var btnId = me.buttonIds[btnIdx];
return new Ext.button.Button({
handler: me.btnCallback
,cls: me.cls + '-' + btnId
,itemId: btnId
,scope: me
,text: me.buttonText[btnId]
,minWidth: 75
});
}
});
To use:
App.Box = new App.MyMessageBox({
cls:'reset-grid-layout'
}).show({
title:'Reset Grid Layout'
,msg: 'Are you sure that you want to reset the grid layout?'
,buttons: Ext.Msg.YESNO
,icon: Ext.window.MessageBox.QUESTION
});
Your buttons will have reset-grid-layout-yes and reset-grid-layout-no class.
You can do the same with other components you have. Check out the Fiddle. https://fiddle.sencha.com/#fiddle/7qb
You should refer to the API
cls : String A CSS class string to apply to the button's main element.
Overrides: Ext.AbstractComponent.cls
You can also use the filter on right side (not the one in the right top corner). Just type cls and you will see all properties, methods and events containing cls (note that you see by default just public members, use the menu on the right of this searchfield to extend this)
Edit
If you just need it for testing purpose I would recommend to override the responsible method. This should work (untested!)
Ext.window.MessageBox.override({
buttonClasses: [
'okCls', 'yesCls', 'noCls', 'cancelCls'
],
makeButton: function(btnIdx) {
var btnId = this.buttonIds[btnIdx];
var btnCls = this.buttonClasses[btnIdx];
return new Ext.button.Button({
handler: this.btnCallback,
cls: btnCls,
itemId: btnId,
scope: this,
text: this.buttonText[btnId],
minWidth: 75
});
}
});

ExtJS 2.3. 0 radio click event is firing twice

I am using Extjs 2.3.0
I have a radio control and in my requirement, I wanted to add a functionality where I can uncheck the radiobutton. (Usually we do not uncheck a radio) and I solved it as follows
{ boxLabel: 'Yes', name: 'Yes', inputValue: 'Yes', xtype: 'radio',
onClick: function (e) {
if (this.checked) {
this.setValue(false);
} else {
this.setValue(true);
}
}
}
This is working fine
Now, my problem is, above code works fine if I click on radiobutton, but the click event fires twice if I click on Radiobutton label. That is the boxlabel 'Yes'.
As the event fires twice and the radio is not able to check.
I dont understand why the event fires twice on label click and not on the radio click.
Can anyone have any solution or workaround?
Uhm, uncheckable radio boxes, sounds weird :)
Anyway, you are overriding the radio's onClick method (inherited from Ext.form.CheckBox) in your configuration, which looks like:
// private
onClick : function(e){
if (!this.disabled && !this.readOnly) {
this.toggleValue();
}
e.stopEvent();
},
So, you need to stop the event propagation as it is done in the original function. Also, I'd suggest using the toggleValue function as well, as this ensures that other radios with the name name will be unchecked correctly:
onClick: function(e) {
if (!this.disabled && !this.readOnly) {
if (!this.checked) {
this.toggleValue();
} else {
this.setValue(false);
}
}
e.stopEvent();
},
Btw, the best way is probably to create a new class which extends Ext.form.RadioBox. Check out this fiddle.

Form input field in Window header

I need to change the ordinary title part of window the be editable for a moment. I tried the following approach, but it seems to fail in several ways. Could someone suggest me a better approach?
var header = window.getHeader();
header.setTitle(''); // Get rid of the original for now
var field = Ext.create('Ext.form.field.Text', {
name: 'Title',
allowBlank: false,
cls: 'myInput',,
value: 'Meh, just some text for now',
listeners : {
el : {
delegate : 'input',
click : function() {
field.focus(false); // Focus but do not select the text
field.selectText(0,0); // The previous failed, try to deselect like this
}
}
}
});
header.insert(0, field); // First, before the tools (several buttons there)
My problems with this are the following;
Without the listener part it is impossible to select the input field at all, all that happens is triggering the moving of the window. With the listener implementation though the contents of the input field get still selected for some reason (without the selectText from 0 to 0). Also it is impossible to use mouse to select parts of the contents because dragging still applies to the whole window, AND the listener implementation's "click" probably also ruins that approach. It is also impossible to move the cursor to specific spot by using mouse click.
So, how should one really go around implementing a usable html input field that replaces window title?
I've tried the following strategy that seems to work: when the mouse cursor enters the input field, disable window drag & drop, and restore it when it leaves.
Here's what it would give with your code:
var killDrag = true;
// Found this by looking into the code: window.dd is an Ext.util.ComponentDragger
// Someone had the good idea to comment that, in there...
window.dd.on({
// Ext.util.ComponentDragger has a beforedragstart event that can cancel the drag.
// Apparently no one had the good idea to mention this event in the API doc.
beforedragstart: function(dd, e) {
if (killDrag) {
return false;
}
}
});
var header = window.getHeader();
header.setTitle(''); // Get rid of the original for now
var field = Ext.create('Ext.form.field.Text', {
name: 'Title',
allowBlank: false,
cls: 'myInput',
value: 'Meh, just some text for now',
listeners : {
el : {
delegate : 'input',
mouseout: function() {
killDrag = false;
},
mouseenter: function() {
killDrag = true;
}
}
}
});
header.insert(0, field); // First, before the tools (several buttons there)

Adding click event to radio boxes Ext.form.Radio in Ext JS

I have a simple radio button:
new Ext.form.Radio({
id: 'ptype',
boxLabel:'Yes',
name: 'price_type',
value: 1
})
However Im having trouble adding a on click event ot it.
I usually use:
listeners: {
click: function (a,e) {
//event
}
}
As a config parameter, however it does not seem to work in this case.
Any advice appreciated, thanks.
Radio and checkboxes do not have a click event -- I believe you want the check event instead. Your listener should look like:
listeners: {
check: function (ctl, val) {
// val is the new checked boolean value
}
}
Note that the handler config is a handy shortcut for this (also available on buttons). Instead of the listeners syntax you could just do this:
handler: function(ctl, val) {
// etc
}
Try this:
new Ext.form.Radio({
id: 'ptype',
boxLabel:'Yes',
name: 'price_type',
value: 1
onClick: function(e){
.....
.....
}
})
If you're using a CheckBoxGroup, you should do something like this to make sure you are firing on the correct Radio.
listeners: {
check: function(checkbox, checked) {
if(checked) {
// do whatever.
}
}
}

Resources