Learn how to dynamically alter the background of an ExtJS button when it is hovered over or pressed

Greetings,

I am looking to dynamically change the background-color for different states (normal, hover, pressed) of a button. Here is what I have come up with so far: http://jsfiddle.net/suamikim/c3eHh/

Ext.onReady(function() {
    function updateBackground() {
        var theWin = win || this,
            btn = theWin.down('#btnTest'),
            bckgr = theWin.down('#btnBckgr').getValue(),
            bckgrHover = theWin.down('#btnBckgrHover').getValue(),
            bckgrPressed = theWin.down('#btnBckgrPressed').getValue();

        $('#' + btn.id).css('background', bckgr);

        $('#' + btn.id).hover(function() {
                $('#' + btn.id).css('background', bckgrHover);
            }, function() {
                $('#' + btn.id).css('background', bckgr);
            }
        );

        $('<style type="text/css"> #' + btn.id + '.x-btn-pressed { background: ' + bckgrPressed + ' !important } </style>').appendTo('head');
    };

    var win = Ext.create('Ext.window.Window', {
        width: 800,
        height: 200,
        layout: 'fit',
        
        // Additional code omitted for brevity

        listeners: {
            'afterrender': updateBackground
        }
    }).show();
});

This approach works but raises some questions:

1)

Is it necessary or safe to call the hover function in jQuery every time updateBackground is called?

According to the jQuery documentation (http://api.jquery.com/hover/), this function binds functions to mouse events. Does it create new bindings each time, update existing ones, or handle disposal automatically?

2)

Setting styles as document-level for the pressed state can clutter the document header if updateBackground is called frequently. Is there a better approach or a way to remove previously set styles before adding new ones?

3)

The hover state's background does not show when the button is pressed due to the !important flag. Removing it causes issues with displaying the pressed background correctly. Any solutions?

Please provide suggestions that are generic and adaptable to other Ext controls beyond buttons like panels, checkboxes, etc. Thank you.

Answer №1

By using more specific CSS selectors, you can utilize Ext's pressedCls and overCls configurations. Check out these links for more information: Link 1 | Link 2

.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(),
})

Here's an edited version for a more dynamic and generic solution:


Ext.define('DynamicStyleState', {
    alias : 'plugin.dynamicStyleState',
    extend : Ext.AbstractPlugin,
    
    elementProperty : 'el',

    pressed : false,

    init : function(component) {
        this.component = component;
        this.component.on('afterrender', this._onAfterrender, this);
    },

    clearStyle : function() {
        this.el.setStyle({
            background : ''
        });
    },
    
    getHoverStyle : function() {
        return {
            background : 'blue'
        };
    },
    
    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 {
            if(e.within(this.el)) {
                this.el.setStyle(this.getHoverStyle());
            }
        }
    }
});

This solution extends beyond buttons and can be used on any component.

Below is an example of how it can be implemented:


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'
});

Answer №2

After careful consideration, I have devised a solution that effectively addresses the issues previously outlined:

The approach involves adding both the pressed and hovered styles directly to the header.

To ensure the cleanliness of the header, I dynamically remove existing style elements using jQuery's detach-function before appending new ones.

Here is a working example

Below is the code snippet for dynamically changing the background:

function updateBackground() {
    var theWin = win || this, // necessary due to 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');
};

This method seems effective to me, but I am open to any suggestions or improvements!

Thank you.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Conceal the ::before pseudo-element when the active item is hovered over

Here is the code snippet I am working with: <nav> <ul> <li><a href="javascript:void(0)" class="menuitem active">see all projects</a></li> <li><a href="javascript:void(0)" class="menuitem"> ...

Navigate to the bottom of a Vue modal window by scrolling down

I am facing an issue with implementing a Vue calendar inside a modal. When the calendar appears, I want the window to automatically scroll to the bottom, but I am having trouble making it work. Unfortunately, I can't provide the code for the whole mod ...

Tips for simulating next/router in vitest for unit testing?

Struggling with creating basic tests for our Next.js application that utilizes the useRouter() hook, encountering errors when using vitest. In search of solutions to mock next/router for unit testing in conjunction with vitest. ...

Experience choppy scrolling in Internet Explorer

Check out my click and drag scrolling Image Viewer here. While it functions perfectly in Firefox and Chrome, Internet Explorer is giving me some trouble. The movement seems jerky, especially when scrolling diagonally. It's like the scroll is sluggish ...

Styling with CSS: I am looking to display images beneath text

I am facing a challenge with displaying an image within a container. The container has a background image with the position set to relative and contains some text. I would like to display another image within this container, with the position set to absolu ...

Automated email formatting for a polished presentation

Aspiring to create automated emails upon user registration on my website, the aesthetic appeal of these emails is crucial to me. I have meticulously crafted an email template using HTML. You can view a snapshot here: https://i.sstatic.net/MpjfP.png Howev ...

Retrieve the information from a website and display it on the current webpage using an ajax request

Is there a way to insert parsed HTML content into my webpage using just a link from another page? I'm attempting to use an AJAX call, but I keep receiving an error. Below is the code I've written, and the browser doesn't seem to be the issue ...

What is the best way to fill a "multiselect" element with information from a JSON object?

I'm struggling to populate the multiselect field with data from a JSON object. No matter which multiselect I use, the data shows in inspect mode but not on the frontend. It was supposed to look like this. https://i.sstatic.net/FVz2H.png but it comes ...

Navigate to the end of a container

Is there a method to automatically scroll to the bottom of a div when the page is loaded? I have attempted several solutions without success. If you have any insights, please share them. Thank you! ...

Is there a way to determine my position in the cycle of WebGL/THREE radians that range from 0 to 1.57, then back to 0, and down to -1.57?

Hey, I've noticed that the radians seem to fluctuate when looking at a camera and trying to animate a flyover. I'm getting repetitive numbers when the camera rotates more than 90 degrees on either side. What could I be overlooking? function calc ...

Is it possible for Typescript to encounter an error when using console.log() with a variable of type "any"?

When using console.log(variable: any) in Typescript, I am concerned about potential errors and avoiding the need for try{}catch blocks throughout my code. Will console.log(any) trigger any errors or will it successfully print any input provided? public ...

The Google Maps API functions flawlessly on Chrome and Firefox, however, Internet Explorer seems to be having trouble running it

When using the Google Maps API, everything works fine on Chrome and Firefox but Internet Explorer encounters an issue. I am loading the API with jQuery and calling initialize(); The error message in IE6 states: error 'google' undefined function ...

Using data attributes in Material UI: A comprehensive guide

Recently, I started integrating Material Design React into my project. However, I encountered an issue where the data-someField does not pass the value to the dataset map. For example: <Input data-role=‘someValue’ onChange={this.onChange} /> o ...

Is it considered a bad practice to use the record ID on a <tr> element for an editable row within a table?

I am in the process of using jQuery to create a feature that allows users to edit a HTML table containing category names. Currently, I have successfully populated my table using PHP/MySQL. While researching on jQuery - Edit a table row inline, I came acr ...

Nested Tab Generation on the Fly

My goal is to create dynamically nested tabs based on my data set. While I have successfully achieved the parent tabs, I am encountering an issue with the child tabs. Code $(document).ready(function() { var data1 = [["FINANCE"],["SALE"],["SALE3"]]; var da ...

Tips for steering clear of getting caught in the initial focus trap

I have implemented Focus-trap (https://www.npmjs.com/package/focus-trap) in my modal to enhance keyboard accessibility. Here is a snippet of my code: <FocusTrap focusTrapOptions={{onDeactivate: onClose}} > <div> ... </div> <Focu ...

Getting the value of a JSON object in CodeIgniter can be easily achieved by using the appropriate

My current project involves using the codeigniter framework to build a website. I am making an AJAX request with jQuery to retrieve data from the server. I have experimented with two different methods of receiving the data: one in a PHP associative array a ...

retrieving data entered in an HTML form using PHP script

Just dipping my toes into the world of php/html and I'm facing an issue where I need to extract a value from an html form and assign it as a variable in an external php script. This variable is essential for running a SQL query in a postgres database ...

Is there a way for my app to ask for Facebook permissions when the like button is clicked?

My website has Facebook integration, with Like buttons on the homepage that are popular and a login button that is not. I want to make the Like buttons also function as login buttons by requesting extended permissions for my app when they are clicked. I h ...

Receiving a Javascript Promise from a $.ajax request

Trying to convert a $.ajax() statement into an es6 Promise and return it as an es6 promise. The goal is to have an application layer with Create, Update, Delete calls to the Microsoft Dynamics Web API that return an es6 Promise for reuse across multiple pa ...