PDA

View Full Version : [FIXED] Help with Button aligned to Field



primolan
12 Apr 2010, 11:19 AM
Hello!

I saw a lot of people asking about a field with a button by its side. I actually followed the idea from fileuploadfield and I did some code here.

It works fine with TextField but it fails at onResize method with Trigger fields. I really don't know why! Please, help me! Thanks in advance!

Here is the code:



Ext.form.Field.prototype.onRender = Ext.form.Field.prototype.onRender.createSequence(function(thisContainer, thisPosition){
if (this.buttonConfig) {
this.wrap = this.el.wrap({
style: 'clear: both;'
});
this.el.applyStyles('float: left;');
this.button = new Ext.Button(Ext.apply(this.buttonConfig, {
renderTo: this.wrap,
style: 'float: right;'
}));
}
});

Ext.form.Field.prototype.onResize = Ext.form.Field.prototype.onResize.createSequence(function(adjWidth, adjHeight, rawWidth, rawHeight){
if (this.buttonConfig) {
this.wrap.setSize(adjWidth, adjHeight);
var elWidth = this.wrap.getWidth() - this.button.getEl().getWidth() - (this.defaultTriggerWidth ? this.defaultTriggerWidth : 0) - this.buttonConfig.buttonOffset;
this.el.setSize(elWidth, adjHeight);
}
});

//var field = new Ext.form.TextField({
var field = new Ext.form.ComboBox({
renderTo: Ext.getBody(),
buttonConfig: {
buttonOffset: 3,
iconCls: 'icon-add',
handler: function(thisButton) {
alert('button handler');
}
},
store: ['Rodrigo', 'Primolan'],
width: 300
});

primolan
13 Apr 2010, 10:22 AM
I spent a whole day! But now its working!

I missed onResize method on TriggerField (plus trigger width count). Now its working! :D

I hope you all enjoy!



// onRender method
Ext.form.Field.prototype.onRender = Ext.form.Field.prototype.onRender.createSequence(function(thisContainer, thisPosition){
if (this.buttonConfig) {
this.wrapper = this.el.wrap({
style: 'clear: both;'
});
this.el.applyStyles('float: left;');
this.button = new Ext.Button(Ext.apply(this.buttonConfig, {
renderTo: this.wrapper,
style: 'float: right;'
}));
}
});

// onResize method
Ext.form.Field.prototype.onResize = Ext.form.TriggerField.prototype.onResize = Ext.form.Field.prototype.onResize.createSequence(function(adjWidth, adjHeight, rawWidth, rawHeight){
if (this.buttonConfig) {
this.wrapper.setSize(adjWidth, adjHeight);
if (!this.wrap) { // textfield
var elWidth = this.wrapper.getWidth() - (this.button.getEl().getWidth() + this.buttonConfig.buttonOffset);

} else { // triggerfield
var elWidth = this.wrapper.getWidth() - (this.button.el.getWidth() + this.trigger.getWidth() + this.buttonConfig.buttonOffset);
}
this.el.setSize(elWidth, adjHeight);
}
});

//var field = new Ext.form.TextField({
var field = new Ext.form.DateField({
renderTo: Ext.getBody(),
width: 200,
store: ['Rodrigo', 'Primolan'],
buttonConfig: {
buttonOffset: 3,
iconCls: 'icon-add',
handler: function(thisButton) {
alert('field plus button working!');
}
}
});

primolan
13 Apr 2010, 10:31 AM
Fixed guys! Now its working fine! I missed onResize method on Trigger Field (and trigger width sum). Hope you enjoy it!



// onRender method
Ext.form.Field.prototype.onRender = Ext.form.Field.prototype.onRender.createSequence(function(thisContainer, thisPosition){
if (this.buttonConfig) {
this.wrapper = this.el.wrap({
style: 'clear: both;'
});
this.el.applyStyles('float: left;');
this.button = new Ext.Button(Ext.apply(this.buttonConfig, {
renderTo: this.wrapper,
style: 'float: right;'
}));
}
});

// onResize method
Ext.form.Field.prototype.onResize = Ext.form.TriggerField.prototype.onResize = Ext.form.Field.prototype.onResize.createSequence(function(adjWidth, adjHeight, rawWidth, rawHeight){
if (this.buttonConfig) {
this.wrapper.setSize(adjWidth, adjHeight);
if (!this.wrap) { // textfield
var elWidth = this.wrapper.getWidth() - (this.button.getEl().getWidth() + this.buttonConfig.buttonOffset);

} else { // triggerfield
var elWidth = this.wrapper.getWidth() - (this.button.el.getWidth() + this.trigger.getWidth() + this.buttonConfig.buttonOffset);
}
this.el.setSize(elWidth, adjHeight);
}
});

//var field = new Ext.form.TextField({
var field = new Ext.form.DateField({
renderTo: Ext.getBody(),
width: 200,
store: ['Rodrigo', 'Primolan'],
buttonConfig: {
buttonOffset: 3,
iconCls: 'icon-add',
handler: function(thisButton) {
alert('field plus button working!');
}
}
});

primolan
19 Apr 2010, 4:48 AM
Fixed methods. Now it works with ux.FileUploadField and allows multiple buttons.

Just use property buttons on your field configuration.

Eg:



return new Ext.form.TriggerField({
buttons: [{
iconCls: 'icon-add',
id: 'button'
},{
iconCls: 'icon-delete'
},{
iconCls: 'icon-zoom',
handler: function(b, e) {
var b = Ext.getCmp('button');
b.setDisabled(!b.disabled);
},
scope: this
}],
fieldLabel: 'User',
hiddenName: 'user',
name: 'user',
renderTo: Ext.getBody(),
width: 300
});


Just write this code into a file (I called buttonsField.js) and include it, very simple. I hope you all enjoy!



// Field onRender method
Ext.form.Field.prototype.onRender = Ext.form.Field.prototype.onRender.createSequence(function(thisContainer, thisPosition){
if (this.buttons) {
this.wrapper = this.el.wrap({
style: 'clear: both;'
});
this.el.applyStyles('float: left;');
var button = {};
this.buttonsWidth = 0;
this.buttons.reverse();
for(var b = 0, length = this.buttons.length; b < length; b++) {
button[b] = new Ext.Button(Ext.apply(this.buttons[b], {
renderTo: this.wrapper,
style: 'float: right; padding: 0px 0px 0px 2px'
}));
this.buttonsWidth += button[b].el.getWidth();
}
this.wrapper.setWidth(this.el.getWidth());
this.el.setWidth(this.el.getWidth() - this.buttonsWidth);
}
});

// Field onResize method
Ext.form.Field.prototype.onResize = Ext.form.Field.prototype.onResize.createSequence(function(adjWidth, adjHeight, rawWidth, rawHeight){
if (this.buttons) {
this.wrapper.setSize(adjWidth, adjHeight);
this.el.setSize((this.el.getWidth() - this.buttonsWidth), adjHeight);
}
});

// TriggerField onResize method
Ext.form.TriggerField.prototype.onResize = Ext.form.TriggerField.prototype.onResize.createSequence(function(adjWidth, adjHeight, rawWidth, rawHeight){
if (this.buttons) {
this.wrapper.setSize(adjWidth, adjHeight);
this.el.setSize((this.el.getWidth() - this.buttonsWidth), adjHeight);
}
});

// ux.FileUploadField onResize method
Ext.ux.form.FileUploadField.prototype.onResize = Ext.ux.form.FileUploadField.prototype.onResize.createSequence(function(adjWidth, adjHeight, rawWidth, rawHeight){
if (this.buttons) {
this.wrapper.setSize(adjWidth, adjHeight);
var wrapWidth = adjWidth - this.buttonsWidth;
this.wrap.applyStyles('float: left;');
this.wrap.setSize(wrapWidth, adjHeight);
var width = (this.wrap.getWidth() - this.button.el.getWidth());
var elWidth = this.wrapper.getWidth() - (this.buttonsWidth + this.button.el.getWidth() + 2);
this.el.setSize(elWidth, adjHeight);
}
});

burn
22 Apr 2010, 6:03 AM
Very nice stuff, I integrated it in my system and it almost works (I render forms in windows and they can contain a mix of tabpanels/fieldsets/columns):

1) Had to remove the clear:both; style from:

this.wrapper = this.el.wrap({
style: 'clear: both;'
});otherwise the label, the field and the buttons would end up in different lines.

2) For some reason when a field is inside a tabpanel it doesn't get resized, making the buttons end up below the input field while correctly floating to the right (see attached screenshot).

P.S. never-mind the two floating buttons without a field, they're rendered beside a hidden field.

20088

primolan
22 Apr 2010, 1:45 PM
Hi Burn!

I also use that inside tabpanels as well. On window beforeshow event, I call doLayout on each Panel (forcing render on hidden elements). I suppose that should works with you. At least, you could try :)

Cya!

primolan
30 Apr 2010, 3:54 AM
Hello!

Fixed again! Now the handler function receveis a third parameter: field. [ function(button, field, event) ].

I hope you all enjoy!

fieldButtons.js


/**
* Gives possibility to any field to have any buttons beside.
*
* @cfg buttons : object/array Ext.Button
* @cfg button.handler now reveives a third parameter, the field. Eg.: handler: function(button, field, event)
*
* new Ext.form.TextField({
* buttons: {
* handler: function(b, f, e) {
* alert(b); alert(f); alert(e);
* }
* text: 'here!'
* },
* fieldLabel: 'Nome',
* name: 'name'
* });
*
* author: Rodrigo Novelo Primolan (primolan@interair.com.br)
*/

Ext.prototype = {
isObject: function(v) {
return (typeof(v) == 'object' && v.length == undefined);
},
isArray: function(v) {
return (typeof(v) == 'object' && v.length != undefined);
}
};

// Field onRender method
Ext.form.Field.prototype.onRender = Ext.form.Field.prototype.onRender.createSequence(function(thisContainer, thisPosition){
if (this.buttons) {
this.wrapper = this.el.wrap({
style: 'clear: both;'
});
this.el.applyStyles('float: left;');
var button = {};
this.buttonsWidth = 0;
if (Ext.isObject(this.buttons)) {
this.buttons = [this.buttons];
} else {
this.buttons.reverse();
}
for(var b = 0, length = this.buttons.length; b < length; b++) {
button[b] = new Ext.Button(Ext.apply(this.buttons[b], {
field: this,
renderTo: this.wrapper,
style: 'float: right; padding: 0px 0px 0px 2px',
onClick: function(e) {
if (e) {
e.preventDefault();
}
if (e.button !== 0){
return;
}
if (!this.disabled) {
if (this.enableToggle && (this.allowDepress !== false || !this.pressed)) {
this.toggle();
}
if (this.menu && !this.hasVisibleMenu() && !this.ignoreNextClick) {
this.showMenu();
}
this.fireEvent('click', this, this.field, e);
if (this.handler) {
this.handler.call(this.scope || this, this, this.field, e);
}
}
}
}));
this.buttonsWidth += button[b].el.getWidth();
}
this.wrapper.setWidth(this.el.getWidth());
this.el.setWidth(this.el.getWidth() - this.buttonsWidth);
}
});

// Field onResize method
Ext.form.Field.prototype.onResize = Ext.form.Field.prototype.onResize.createSequence(function(adjWidth, adjHeight, rawWidth, rawHeight){
if (this.buttons) {
this.wrapper.setSize(adjWidth, adjHeight);
this.el.setSize((this.el.getWidth() - this.buttonsWidth), adjHeight);
}
});

// TriggerField onResize method
Ext.form.TriggerField.prototype.onResize = Ext.form.TriggerField.prototype.onResize.createSequence(function(adjWidth, adjHeight, rawWidth, rawHeight){
if (this.buttons) {
this.wrapper.setSize(adjWidth, adjHeight);
this.el.setSize((this.el.getWidth() - this.buttonsWidth), adjHeight);
}
});

// ux.FileUploadField onResize method
Ext.ux.form.FileUploadField.prototype.onResize = Ext.ux.form.FileUploadField.prototype.onResize.createSequence(function(adjWidth, adjHeight, rawWidth, rawHeight){
if (this.buttons) {
this.wrapper.setSize(adjWidth, adjHeight);
var wrapWidth = adjWidth - this.buttonsWidth;
this.wrap.applyStyles('float: left;');
this.wrap.setSize(wrapWidth, adjHeight);
var width = (this.wrap.getWidth() - this.button.el.getWidth());
var elWidth = this.wrapper.getWidth() - (this.buttonsWidth + this.button.el.getWidth() + 2);
this.el.setSize(elWidth, adjHeight);
}
});

Urkman
9 Nov 2010, 12:58 AM
Hello primolan,

this is a great extension. I would vote for it to go to the core...

But we have a small problem here:
If the field we need buttons for is on a not visible tabpanel it is not shown correct...

Perhaps you already have a fix for this.

Thanks and greetings,
Urkman

primolan
10 Nov 2010, 12:38 PM
Hi everyone!

For those people that are not getting this ux working under TabPanel, should try these configs:

deferredRender: true,
forceLayout: true,
layoutOnTabChange: true

These should work!

Now, theres a new version of this ux !!! :D:D .. Here it is!!



Ext.form.Field.prototype.onRender = Ext.form.Field.prototype.onRender.createSequence(function(ct, position) {

var me = this;

if (me.buttons) {

// Buttons config.
me.buttonsCfg = {

/* A shortcut for setting a padding style on the buttons elements. The value can either be a number to be applied to
* all sides, or a normal css string describing padding. Defaults to undefined. Defaults to '0px 0px 0px 2px'. */
padding: me.buttonsCfg.padding || '0px 0px 0px 2px',

// Defaults to true. Specify true to have the field widths re-proportioned at all times when buttons are hidden or shown.
forceFit: me.buttonsCfg.forceFit ? true : false
};

me.buttonsWidth = 0;

// Element that wraps field and buttons.
me.wrapper = me.el.wrap();

// Applying float:left to field element.
me.el.applyStyles({
float: 'left'
});

// Array containing hidden buttons.
me.hiddenButtons = [];

// onClick new method.
var onClickFn = function(e){
if(e){
e.preventDefault();
}
if(e.button !== 0){
return;
}
if(!this.disabled){
this.doToggle();
if(this.menu && !this.hasVisibleMenu() && !this.ignoreNextClick){
this.showMenu();
}
this.fireEvent('click', this, this.field, e);
if(this.handler){
this.handler.call(this.scope || this, this, this.field, e);
}
}
};

// Checks configured buttons and reorganize them.
if (Ext.type(me.buttons) == 'object') me.buttons = [me.buttons];
if (Ext.type(me.buttons) == 'array') me.buttons.reverse();

// Iterates buttons.
var buttons = me.buttons;
for(var b = 0, length = buttons.length; b < length; b++) {

// Render buttons according the way they were created: rendered or not.
if (buttons[b].initialConfig) {
me.buttons[b].field = me;
me.buttons[b].onClick = onClickFn;
me.buttons[b] = me.buttons[b].render(me.wrapper);
} else {
me.buttons[b] = new Ext.Button(Ext.apply(buttons[b], {
field: me,
onClick: onClickFn,
renderTo: me.wrapper
}));
}

// Apply style to arrange buttons inside wrapper.
me.buttons[b].el.applyStyles({
float: 'right',
padding: me.buttonsCfg.padding
});

// onHide method to use with forceFit.
me.buttons[b].onHide = me.buttons[b].onHide.createSequence(function() {
if (me.buttonsCfg.forceFit && !me.hiddenButtons[this.getId()]) {
me.hiddenButtons[this.getId()] = true;
me.el.setWidth(me.el.getWidth() + this.width);
}
});

// onShow method to use with forceFit.
me.buttons[b].onShow = me.buttons[b].onShow.createSequence(function() {
if (me.buttonsCfg.forceFit && me.hiddenButtons[this.getId()]) {
me.hiddenButtons[this.getId()] = false;
me.el.setWidth(me.el.getWidth() - this.width);
}
});

// Total width of buttons.
me.buttonsWidth += me.buttons[b].width ? me.buttons[b].width : me.buttons[b].getWidth();
}

// Fixes wrapper width.
me.wrapper.setWidth(me.el.getWidth());
}
});

// Field onResize method.
Ext.form.Field.prototype.onResize = Ext.form.Field.prototype.onResize.createSequence(function(adjWidth, adjHeight, rawWidth, rawHeight){
var me = this;
if (me.buttons) {
me.wrapper.setSize(adjWidth, adjHeight);
me.el.setSize((me.el.getWidth() - me.buttonsWidth), adjHeight);
me.initialWidth = me.el.getWidth();
}
});

// TriggerField onResize method.
Ext.form.TriggerField.prototype.onResize = Ext.form.TriggerField.prototype.onResize.createSequence(function(adjWidth, adjHeight, rawWidth, rawHeight){
var me = this;
if (me.buttons) {
me.wrapper.setSize(adjWidth, adjHeight);
me.el.setSize((me.el.getWidth() - me.buttonsWidth), adjHeight);
me.initialWidth = me.el.getWidth();
}
});
Example:




button = new Ext.Button({
text: 'button',
listeners: {
click: function(button, field, event) {
alert(field.fieldLabel);
}
},
width: 50
});

combo= new Ext.form.ComboBox({
buttons: [button, {
text: 'other button',
handler: function(b, f, e) {
alert(f.fieldLabel);
}
}],
buttonsCfg: {
forceFit: true
},
fieldLabel: 'add',
width: 200
});

primolan
11 Nov 2010, 4:13 AM
Hello friends!

Yesterday I sent a new version and today moderator still didn't accept it. So I'm posting a new version: this fix the bug when a button is rendered hidden.

Remembering:

Any field accept 2 new config options:



buttons = obj|array
buttonsCfg = {
forceFit: true|false
padding: int|str
}
Here's the code:



Ext.form.Field.prototype.onRender = Ext.form.Field.prototype.onRender.createSequence(function(ct, position) {

var me = this;

me.getButtonsWidth = function() {
buttonsWidth = 0;
Ext.each(me.buttons, function(button){
if (me.buttonsCfg.forceFit) {
if (!button.hidden) {
buttonsWidth += button.getWidth();
}
} else {
buttonsWidth += (button.width ? button.width : button.getWidth());
}
});
return buttonsWidth;
}

if (me.buttons) {

// Buttons config.
me.buttonsCfg = {

/* A shortcut for setting a padding style on the buttons elements. The value can either be a number to be applied to
* all sides, or a normal css string describing padding. Defaults to undefined. Defaults to '0px 0px 0px 2px'. */
padding: me.buttonsCfg.padding || '0px 0px 0px 2px',

// Defaults to true. Specify true to have the field widths re-proportioned at all times when buttons are hidden or shown.
forceFit: me.buttonsCfg.forceFit ? true : false
};

me.buttonsWidth = 0;

// Element that wraps field and buttons.
me.wrapper = me.el.wrap();

// Applying float:left to field element.
me.el.applyStyles({
float: 'left'
});

// Array containing hidden buttons.
me.hiddenButtons = [];

// onClick new method.
var onClickFn = function(e){
if(e){
e.preventDefault();
}
if(e.button !== 0){
return;
}
if(!this.disabled){
this.doToggle();
if(this.menu && !this.hasVisibleMenu() && !this.ignoreNextClick){
this.showMenu();
}
this.fireEvent('click', this, this.field, e);
if(this.handler){
this.handler.call(this.scope || this, this, this.field, e);
}
}
};

// Checks configured buttons and reorganize them.
if (Ext.type(me.buttons) == 'object') me.buttons = [me.buttons];
if (Ext.type(me.buttons) == 'array') me.buttons.reverse();

// Iterates buttons.
var buttons = me.buttons;
for(var b = 0, length = buttons.length; b < length; b++) {

// Render buttons according the way they were created: rendered or not.
if (buttons[b].initialConfig) {
me.buttons[b].field = me;
me.buttons[b].onClick = onClickFn;
me.buttons[b] = me.buttons[b].render(me.wrapper);
} else {
me.buttons[b] = new Ext.Button(Ext.apply(buttons[b], {
field: me,
onClick: onClickFn,
renderTo: me.wrapper
}));
}

if (me.buttons[b].hidden) {
me.hiddenButtons[me.buttons[b].getId()] = true;
}

// Apply style to arrange buttons inside wrapper.
me.buttons[b].el.applyStyles({
float: 'right',
padding: me.buttonsCfg.padding
});

// onHide method to use with forceFit.
me.buttons[b].onHide = me.buttons[b].onHide.createSequence(function() {
if (me.buttonsCfg.forceFit && !me.hiddenButtons[this.getId()]) {
me.hiddenButtons[this.getId()] = true;
me.el.setWidth(me.el.getWidth() + this.width);
}
});

// onShow method to use with forceFit.
me.buttons[b].onShow = me.buttons[b].onShow.createSequence(function() {
if (me.buttonsCfg.forceFit && me.hiddenButtons[this.getId()]) {
me.hiddenButtons[this.getId()] = false;
me.el.setWidth(me.el.getWidth() - this.width);
}
});

// Total width of buttons.
me.buttonsWidth += me.buttons[b].width ? me.buttons[b].width : me.buttons[b].getWidth();
}

// Fixes wrapper width.
me.wrapper.setWidth(me.el.getWidth());
}
});

// Field onResize method.
Ext.form.Field.prototype.onResize = Ext.form.Field.prototype.onResize.createSequence(function(adjWidth, adjHeight, rawWidth, rawHeight){
var me = this;
if (me.buttons) {
me.wrapper.setSize(adjWidth, adjHeight);
me.el.setSize((me.el.getWidth() - me.getButtonsWidth()), adjHeight);
me.initialWidth = me.el.getWidth();
}
});

// TriggerField onResize method.
Ext.form.TriggerField.prototype.onResize = Ext.form.TriggerField.prototype.onResize.createSequence(function(adjWidth, adjHeight, rawWidth, rawHeight){
var me = this;
if (me.buttons) {
me.wrapper.setSize(adjWidth, adjHeight);
me.el.setSize((me.el.getWidth() - me.getButtonsWidth()), adjHeight);
me.initialWidth = me.el.getWidth();
}
});
A simple (and ugly :P) example:



oi = new Ext.Button({
text: 'oi',
hidden: true,
listeners: {
click: function(b, f, e) {
alert(this.field);
alert(f.fieldLabel);
}
},
width: 50
});

tchau = new Ext.Button({
text: 'tchau',
listeners: {
click: function() {
oi.hide();
}
},
width: 50
});

add = new Ext.form.ComboBox({
buttons: [oi, tchau, {
text: 'novo',
handler: function(b, f, e) {
alert(f.fieldLabel);
}
}],
buttonsCfg: {
forceFit: true
},
fieldLabel: 'add',
width: 200
});

del = new Ext.form.ComboBox({
fieldLabel: 'del',
width: 200
});

return new Ext.form.FormPanel({
buttons: [{
text: 'show',
handler: function() {
oi.show();
}
},{
text: 'hide tchau',
handler: function() {
tchau.hide();
}
}],
items: [add, del],
renderTo: Ext.getBody()
});
});
Thanks everyone for helping and using it! I hope you all enjoy!!!

WixSL
26 Dec 2010, 3:22 PM
Hi, this is great, but i'm having trouble adding a Ext.CycleButton as one of the buttons in the buttons config.
It only shows one button without the glitch.
Could you take a look at it.

Thanks you.