How to change background of hovered and pressed extjs-button dynamically
Solution 1
Using some more specific css selectors you can take advantage of Ext's pressedCls and overCls configs. http://docs.sencha.com/ext-js/4-1/#!/api/Ext.button.Button-cfg-pressedCls http://docs.sencha.com/ext-js/4-1/source/Button2.html#Ext-button-Button-cfg-overCls
.x-btn.my-over {
background: blue;
}
/*Ext is not consistent */
.x-btn.x-btn-my-pressed {
background: red;
}
new Ext.button.Button({
overCls : 'my-over',
pressedCls : 'my-pressed',
//needs to be true to have the pressed cls show
enableToggle : true,
text : 'My button',
renderTo : Ext.getBody(),
})
Edit for a more dynamic, generic solution
Ext.define('DynamicStyleState', {
alias : 'plugin.dynamicStyleState',
extend : Ext.AbstractPlugin,
/**
* @cfg
*/
elementProperty : 'el',
/**
* @property
*/
pressed : false,
init : function(component) {
this.component = component;
this.component.on('afterrender', this._onAfterrender, this);
},
/**
* @protected
*/
clearStyle : function() {
this.el.setStyle({
background : ''
});
},
/**
* @protected
* meant to be overriden
*/
getHoverStyle : function() {
return {
background : 'blue'
};
},
/**
* @protected
* meant to be overriden
*/
getPressedStyle : function() {
return {
background : 'red'
};
},
_onAfterrender : function() {
this.el = this.component[this.elementProperty];
this.el.hover(this._onElementMouseIn, this._onElementMouseOut, this);
this.el.on('click', this._onElementClick, this);
},
_onElementMouseIn : function() {
if(!this.pressed) {
this.el.setStyle(this.getHoverStyle());
}
},
_onElementMouseOut : function() {
if(!this.pressed) {
this.clearStyle();
}
},
_onElementClick : function(e) {
this.pressed = !this.pressed;
if(this.pressed) {
this.el.setStyle(this.getPressedStyle());
} else {
//mimic mouse in
if(e.within(this.el)) {
this.el.setStyle(this.getHoverStyle());
}
}
}
});
Since you want something that works on more than just button this should work on any component.
Here is an example usage:
var headerHoverColor = new Ext.form.field.Text({
fieldLabel : 'Header hover color',
value : 'orange',
renderTo : Ext.getBody()
});
var headerPressedColor = new Ext.form.field.Text({
fieldLabel : 'Header pressed color',
value : 'black',
renderTo : Ext.getBody()
})
new Ext.panel.Panel({
plugins : {
ptype : 'dynamicStyleState',
elementProperty : 'body'
},
header : {
plugins : {
ptype : 'dynamicStyleState',
getHoverStyle : function() {
return {
background : headerHoverColor.getValue()
}
},
getPressedStyle : function() {
return {
background : headerPressedColor.getValue()
}
}
}
},
height : 300,
width : 300,
renderTo : Ext.getBody(),
title : 'Panel'
});
Solution 2
Ok, i just found a solution which should cover all the problems described above:
I add both, the pressed
and hovered
style directly to the header.
To make sure that the header won't be polluted i just remove the style-elements dynamically with jQuery
's detach-function from the header before appending new ones.
And the code for the dynamic changing of the background:
function updateBackground() {
var theWin = win || this, // neccessary because of the call from the afterrender-event
btn = theWin.down('#btnTest'),
bckgr = theWin.down('#btnBckgr').getValue(),
bckgrHover = theWin.down('#btnBckgrHover').getValue(),
bckgrPressed = theWin.down('#btnBckgrPressed').getValue();
// Set normal background as button-style
// Should be ok
$('#' + btn.id).css('background', bckgr);
// Set the background for hovered and pressed button as document style
// Remove style-element if it already exists to not pollute the document-head
$('head style:contains("' + btn.id + ':hover")').detach();
$('<style type="text/css"> #' + btn.id + ':hover { background: ' + bckgrHover + ' !important } </style>').appendTo('head');
$('head style:contains("' + btn.id + '.x-btn-pressed")').detach();
$('<style type="text/css"> .x-body #' + btn.id + '.x-btn-pressed { background: ' + bckgrPressed + ' !important } </style>').appendTo('head');
};
Seems to work for me but I'm still open for any suggestions/improvements to this!
Thanks.
suamikim
Updated on July 29, 2022Comments
-
suamikim almost 2 years
Hy there,
i need the ability to change the background-color for the different states (normal, hover, pressed) of a button dynamically.
What i've came up with so far is the following: http://jsfiddle.net/suamikim/c3eHh/
Ext.onReady(function() { function updateBackground() { var theWin = win || this, // neccessary because of the call from the afterrender-event btn = theWin.down('#btnTest'), bckgr = theWin.down('#btnBckgr').getValue(), bckgrHover = theWin.down('#btnBckgrHover').getValue(), bckgrPressed = theWin.down('#btnBckgrPressed').getValue(); // Set normal background as button-style // Should be ok $('#' + btn.id).css('background', bckgr); // Toggle background when hover-state changes // Are there any downsides if this function gets called everytime the updateBackground-method is called? Do i have to dispose anything before binding the functions again? $('#' + btn.id).hover(function() { $('#' + btn.id).css('background', bckgrHover); }, function() { $('#' + btn.id).css('background', bckgr); } ); // Set the background for pressed button as document style // Problems: // - Pollutes the document-header if called multiple times... // - Background does not change anymore on hover for pressed button because of the !important, but without important it wouldn't show the pressed background at all... $('<style type="text/css"> #' + btn.id + '.x-btn-pressed { background: ' + bckgrPressed + ' !important } </style>').appendTo('head'); }; // Create a window with the propertygrid var win = Ext.create('Ext.window.Window', { width: 800, height: 200, layout: 'fit', tbar: { defaultType: 'textfield', defaults: { listeners: { blur: updateBackground } }, items: [ 'Background (CSS):', { itemId: 'btnBckgr', value: '#77ABD8' }, 'Background hover (CSS):', { itemId: 'btnBckgrHover', value: '#CC1C1C' }, 'Background pressed (CSS):', { itemId: 'btnBckgrPressed', value: '#7D4FC6' } ] }, items: [{ xtype: 'button', itemId: 'btnTest', text: 'test button', enableToggle: true }], listeners: { 'afterrender': updateBackground } }).show(); });
This works basically but there are some questions left to me:
1)
Is it ok to call the hover-function of jquery everytime the updateBackground-method is called?
According to the jquery-doc (http://api.jquery.com/hover/) this functions binds the 2 given functions to the mouse-enter- & mouse-leave-events of the given element.
Does this mean that it binds new functions everytime i call it or does it update the already bound ones or does it dispose the already bound ones automatically before binding the new ones...
In short: do i have to dispose anything before binding the new functions with $.hover?2)
I set the style for the pressed state as document-style which means that the document-header gets polluted if the updateBackground-function is called often (everytime one of the text-fields fires the blur-event in my test-case).
Is there any better way to achieve the same goal or can i remove the already set styles before adding new ones?
3)
The background for hover-state doesn't appear if the button is pressed because of the !important-flag in the pressed-style. I can't just remove this flag because the background of the pressed-state wouldn't show correctely without it... Any solutions?
In general i'd be open for every suggestion on how to solve this problem in a completely different way.
Thanks,
mik
Edit:
The code above is just an example. Actually i need to be able to change the background-attribute for other ext-controls than buttons too (panels, checkboxes, ...) but i think that i can adopt a working solution for buttons to those other controls myself.
Please keep this in mind and don't specify the answer too much on buttons. It should be as generic as possible...