jQuery is great at adding a class, but struggles to remove it

When you click on an anchor with the class .extra, it adds the "extra-active" class and removes the "extra" class. However, when you click on an anchor with the extra-active class, it does not remove the extra-active class and replace it with extra.

Here is the HTML code:

$("a.extra").click(function(e){
$(this).addClass("extra-active").removeClass("extra");
e.preventDefault();
})

$("a.extra-active").click(function(e){
$(this).removeClass("extra-active").addClass("extra");
e.preventDefault();
})
.extra{
display:inline-block;
height: 128px;
width: 128px;

background-color:grey;
padding:12px;
border-radius:8px;
}

.extra-group{
p {
text-align:center;
}
}


.extra:hover{
background-color:blue;
}

.extra-active{
display:inline-block;
height: 128px;
width: 128px;

background-color:red !important;
padding:12px;
border-radius:8px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span style="display:inline-block;">
<span class="extra-group">
<a class="extra" href="" title = "An hour of Ironing" id="extra-ironing" style = "background-image: url('{{ url_for('static', filename='book-icons/iron-icon.png') }}'); background-size: 80% 80%; background-repeat: no-repeat; background-position: center center;"></a>
<p>An Hours Ironing</p>
</span>
<span class="extra-group">
<a class="extra" href="" title = "Inside the Fridge" id="extra-fridge"  style = "background-image: url('{{ url_for('static', filename='book-icons/fridge-icon.png') }}'); background-size: 80% 80%; background-repeat: no-repeat; background-position: center center;"></a>
<p>Inside the Fridge</p>
</span>
<span class="extra-group">
<a class="extra" href="" title = "Inside the Oven" id="extra-oven"  style = "background-image: url('{{ url_for('static', filename='book-icons/oven-icon.png') }}'); background-size: 80% 80%;; background-repeat: no-repeat; background-position: center center;"></a>
<p>Inside the Oven</p>
</span>
<span class="extra-group">
<a class="extra" href="" title = "A load of Washing" id="extra-washing" style = "background-image: url('{{ url_for('static', filename='book-icons/washer-icon.png') }}'); background-size: 80% 80%; background-repeat: no-repeat; background-position: center center;"></a>
<p>A load of Washing</p>
</span>
<span class="extra-group">
<a class="extra " href="" title = "Interior Windows" id="extra-windows" style = "background-image: url('{{ url_for('static', filename='book-icons/window-icon.png') }}'); background-size: 80% 80%; background-repeat: no-repeat; background-position: center center;"></a>
<p>Interior Windows</p>
</span>
</span>

Answer №1

Building upon @xandercoded's input, I incorporated a listener to the body element and then modified the target of the on function.

$("body").on('click','.extra',function(e){
$(e.target).addClass("extra-active").removeClass("extra");
e.preventDefault();
})

$("body").on('click','.extra-active',function(e){
$(e.target).removeClass("extra-active").addClass("extra");
e.preventDefault();
})
.extra{
display:inline-block;
height: 128px;
width: 128px;

background-color:grey;
padding:12px;
border-radius:8px;
}

.extra-group{
p {
text-align:center;
}
}


.extra:hover{
background-color:blue;
}

.extra-active{
display:inline-block;
height: 128px;
width: 128px;

background-color:red !important;
padding:12px;
border-radius:8px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span style="display:inline-block;">
<span class="extra-group">
<a class="extra" href="" title = "An hour of Ironing" id="extra-ironing" style = "background-image: url('{{ url_for('static', filename='book-icons/iron-icon.png') }}'); background-size: 80% 80%; background-repeat: no-repeat; background-position: center center;"></a>
<p>An Hours Ironing</p>
</span>
<span class="extra-group">
<a class="extra" href="" title = "Inside the Fridge" id="extra-fridge"  style = "background-image: url('{{ url_for('static', filename='book-icons/fridge-icon.png') }}'); background-size: 80% 80%; background-repeat: no-repeat; background-position: center center;"></a>
<p>Inside the Fridge</p>
</span>
<span class="extra-group">
<a class="extra" href="" title = "Inside the Oven" id="extra-oven"  style = "background-image: url('{{ url_for('static', filename='book-icons/oven-icon.png') }}'); background-size: 80% 80%;; background-repeat: no-repeat; background-position: center center;"></a>
<p>Inside the Oven</p>
</span>
<span class="extra-group">
<a class="extra" href="" title = "A load of Washing" id="extra-washing" style = "background-image: url('{{ url_for('static', filename='book-icons/washer-icon.png') }}'); background-size: 80% 80%; background-repeat: no-repeat; background-position: center center;"></a>
<p>A load of Washing</p>
</span>
<span class="extra-group">
<a class="extra " href="" title = "Interior Windows" id="extra-windows" style = "background-image: url('{{ url_for('static', filename='book-icons/window-icon.png') }}'); background-size: 80% 80%; background-repeat: no-repeat; background-position: center center;"></a>
<p>Interior Windows</p>
</span>
</span>

Answer №2

When the initial html is lacking the extra-active class, any attempt to bind a click event using jQuery on that class will result in nothing happening. To resolve this issue, you can either utilize the on method to bind the event or re-bind the event after adding the class.

$(document.body).on('click', 'a.extra', function(e){
    $(this).addClass("extra-active").removeClass("extra");
    e.preventDefault();
})

$(document.body).on('click', 'a.extra-active', function(e){
   $(this).removeClass("extra-active").addClass("extra");
   e.preventDefault();
})

Answer №3

When the code is executed, only elements with the class "a.extra" will be found and have their onclick function triggered.

The function associated with $("a.extra-active").click will never run because it does not locate any elements with that class during execution.

To simply switch classes, you can utilize the toggle method within your $("a.extra").onclick event:

$(this).toggleClass("extra-active");
$(this).toggleClass("extra");

Answer №4

When you make a reference to $("a.extra-active"), no handlers are attached because there are none to begin with. This means that even if you create them later on, your javascript code has already executed.

A solution to this issue is to utilize event propagation.

$(document.body).on('click', '.extra-active', function() {
    // Do some work here
});

With this approach, when you click anywhere on the document, it will check if the clicked element matches the criteria of ".extra-active". If it does, then the specified function will be executed.

For further reading, refer to this link.

Answer №5

Experiment with toggling the two classes. Explore this JSFiddle

$("a.extra").click(function(e){

    e.preventDefault();
$(this).toggleClass('extra');
$(this).toggleClass('extra-active');


});

$("a.extra-active").click(function(e){
   e.preventDefault();
$(this).toggleClass('extra');
$(this).toggleClass('extra-active');
})

Answer №6

It has been brought to light by others that there are no instances of .extra-active when the code initially loads.

Here is a solution that will work:

var extraActiveClickFunction = function(e) {
    $(this).removeClass("extra-active").addClass("extra");
    e.preventDefault();
}
var extraClickFunction = function(e) {
    $(this).removeClass("extra-active").addClass("extra");
    e.preventDefault();
    // This ensures that our newly created extra-active class 
    // has the correct function bound
    $("a.extra-active").click(extraActiveClickFunction)
}

// Original page load binding
$("a.extra").click(extraClickFunction)

The advantages of assigning functions to variables is evident here as well, making it much easier to handle this type of situation.

Answer №7

It's puzzling why one would want to swap out classes when a simpler option like toggleClass(); exists.

For the CSS:

.extra{
    display:inline-block;
    height: 128px;
    width: 128px;

    background-color:grey !important;
    padding:12px;
    border-radius:8px;
}

.extra-group > p {
        text-align:center;
}


.extra:hover{
    background-color:blue;
}

.extra-active{
    background-color:red !important;
}

In JavaScript:

$("a.extra").click(function(e){
        $(this).toggleClass("extra-active");
        e.preventDefault();
    })

DEMO

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

How can the first paragraph value of a div be found using jQuery in Next.js?

How can I retrieve the value of the first <p> tag within my div when a button inside the same div is clicked? Despite attempting to use $(this), it doesn't appear to be functioning as expected. Take a look at the code snippet below: <div cla ...

How to center a container in HTML using Bootstrap techniques

Here is the code I have been working on: <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet"/> <div class="span4 offset4 centered"> <div class="container overflow-hidden"> < ...

Why am I getting the error "TypeError: Object(...) is not a function" when attempting to integrate Vanilla Tilt with React?

Looking for assistance on implementing Vanilla Tilt in my React application, I have referenced the following example: https://codesandbox.io/s/vanilla-tilt-with-react-n5ptm The code snippet I am working with is as follows: import React, { Component, useEf ...

What's the best way to position the <li> element beneath the hamburger icon?

Is there a way to place the list element 'Home' below the hamburger icon and logo in Bootstrap 4 in mobile mode? I attempted to display the logo as style="display: block" with no success. <div class="container"> <nav class="navbar nav ...

I encountered a permission denied error when trying to enter DEBUG=app ./bin/www in Node.js

After renaming 'my-application' to just 'app', I encountered an issue when running the DEBUG command in the terminal: I used DEBUG=app ./bin/www Originally, it was named 'my-application' as created by express. However, after ...

Creating a two-dimensional canvas within a div element using the console

I have some code that currently generates an image in the console when I hit F12. However, I would like to display this image inside a more user-friendly area such as a div on the webpage. I attempted to create a <div class = "mylog"> to place the i ...

Angular 4 incorporating a customized Bootstrap 4 accordion menu for seamless navigation

I am trying to implement a nested menu using a JSON object in Angular 4. Below is the code I have written. <div id="panel-group"> <div class="panel panel-default" *ngFor="let mainItem of objectKeys(my_menu); let i = index"> <div class ...

Processing two Array Objects can be achieved without resorting to the EVAL function

I have two objects that I need to process. obj1 contains an array of objects with formulas. obj2 holds the values needed for the calculations. I am looking for a way to process and calculate both objects in order to obtain a result where the keys present ...

What is the best way to delete a CSS class from a specific element in a list using React?

I need to implement a functionality in React that removes a specific CSS class from an item when clicking on that item's button, triggering the appearance of a menu. Here is my code snippet. import "./Homepage.css" import React, { useState, ...

iOS Webkit is causing an override of the CSS property text-align for the submit button

Here is the CSS code I used for styling a form's submit button: .submit { -webkit-appearance: none !important; text-align: center !important; border-radius: 0rem; color: rgb(63, 42, 86); display: inline-block; float: right; ...

Issue with Redirecting in React: REST requests are not successful

There's a text input that triggers a submission when the [Enter Key] is pressed. const [ query, setQuery ] = React.useState('') ... <TextField label="Search Codebase" id="queryField" onChange={ event => setQuery( ...

When Vue detects a change in declared parameters from an empty string, it automatically sends a

Within my application, I am making a request to the backend app and receiving a response with an ID such as { 'id': '12345'}. This ID is then saved as loadId within the data object: export default { name: 'SyncProducts', d ...

Confirming the username's accuracy through an external API as part of the registration procedure

My latest project involves creating a web application specifically for Fortnite players looking to connect with other gamers. The concept is simple: users can register, log in, post, and comment within the platform. I have successfully designed the fronten ...

Add a new variable to the data in a jQuery ajax request for each request with any updates

I've encountered an issue with the code below, which is meant to add additional data to any ajax request made by my app. It works fine when the page first loads, but because my application is single-page and ajax-based, I need the updated variable val ...

`Turn nested JSON into a formatted list using jquery`

I am currently facing two challenges: I am having trouble with the HTML structure, as shown in the image below Current HTML structure: https://i.stack.imgur.com/GH46J.png Desired HTML structure: https://i.stack.imgur.com/Dq3Gn.png How can I create d ...

Console log is not displaying the JSON output

I am currently working on implementing a notification button feature for inactive articles on my blog. I want to ensure that the admin does not have to reload the page to see any new submitted inactive articles. To achieve this, I am looking to use Ajax, a ...

Obtaining a date and time in PHP from a JavaScript array

I am currently working on implementing a JQuery datetime picker and my goal is to save the selected date and time into a PHP variable for storage in a MySQL database. Despite browsing through various examples, none of them seem to be effective in achieving ...

Tips on expanding the space between words in a scrolling "marquee" text

Looking for some assistance with my jQuery project involving a horizontal scrolling "marquee" text. I am currently trying to adjust the size of the gap between the phrases in the marquee. Here is an example with the phrase "HEY THERE". jQuery(document ...

When utilizing a wrapped v-text-field, it triggers warning messages and fails to update the data properly

Recently delving into the world of vue.js, I've been experimenting with creating a form using Vue, vuetify, and vuelidate. Oddly enough, when I don't wrap the v-text-field there are no issues, but as soon as I try to encapsulate it within compone ...

Unsynchronized Request Sequencing

Seeking advice on enhancing a previously accepted answer related to chained ajax requests can lead to some interesting solutions. One proposed solution involves sequencing 3 ajax requests in an asynchronous chain: var step_3 = function() { c.finish() ...