Amini
Amini

Reputation: 1792

Is it possible to change the class of an element if the class of another elements equals to sth?

I want to remove/add the classList of some element if the classList of another element is equal to "sth". But there is a little problem that it only runs the command once, I mean the condition doesn't check the classList of the first element every second so it runs it without any problem. If the if is true then it runs the if condition and then it won't check else if and so reverse.

Here is my code:

const dToggle = () => {
  const firstElm = document.querySelector('.firstElm');
  
  firstElm.classList.toggle('red-border');
};

document.querySelector('button').addEventListener('click', dToggle);

const orangeOrRed = () => {
    const firstElm = document.querySelector('.firstElm');
    const secondElm = document.querySelector('.secondElm');

    firstElm.classList === 'red-border' ? secondElm.classList.add('red') : secondElm.classList.add('orange');
    
    // if (firstElm.classList === 'red-border') {
    //        secondElm.classList.remove('orange');
    //        secondElm.classList.add('red');
    // } else if (firstElm.classList === 'orange-border' {
    //        secondElm.classList.remove('red');
    //        secondElm.classList.add('orange');
    // };
};

// Maybe the exact problem is right here.
window.addEventListener('load', orangeOrRed);

console.log(document.querySelector('.secondElm').classList.value);
.d-none {
  display: none !important;
}

.firstElm {
  margin-top: 10px;
  width: 200px;
  height: 100px;
  background-color: blue;
 }
 
.orange-border {
  border: orange 3px solid;
}
 
.red-border {
  border: red 3px solid;
}
 
.secondElm {
  margin-top: 10px;
  width: 200px;
  height: 100px;
  background-color: green;
}

.orange {
  background-color: orange !important;
}

.red {
  background-color: red !important;
}
<button type="button" style="cursor: pointer;">Click here.</button>
<p>It should run the conditional statement whenever I click on the button to apply the border.</p>
<p> First Elm Border Color (MUST BE) Second Elm Background Color</p>
<div class='firstElm orange-border'></div>
<div class='secondElm'></div>
<p style="padding-bottom: 10px;">Remember that I only want to do this with(conditioal statements), It's possible either with classList.toggle() but I don't want to.</p>

Upvotes: 1

Views: 66

Answers (2)

Abbas Hosseini
Abbas Hosseini

Reputation: 1643

Here we have three problems:

1. Checking for the wrong condition

classList is a DOMTokenList that has a contains method which returns true if the element has the desired className or vice versa

2. Adding the same className multiple times without removing the old one

you need to remove the orange className if you want to add the red className and vice versa

3. The orangeOrRed function runs only once

The orangeOrRed function runs only once on window's load event

You need to add the same event listener to the button's click event

const dToggle = () => {
  const firstElm = document.querySelector('.firstElm');
  firstElm.classList.toggle('red-border');
};

document.querySelector('button').addEventListener('click', dToggle);

const orangeOrRed = () => {
    const firstElm = document.querySelector('.firstElm');
    const secondElm = document.querySelector('.secondElm');

    if (firstElm.classList.contains('red-border')) {
            secondElm.classList.remove('orange');
            secondElm.classList.add('red');
    } else if (firstElm.classList.contains('orange-border')) {
            secondElm.classList.remove('red');
            secondElm.classList.add('orange');
    };
};

// You're right, the exact problem is right here.
window.addEventListener('load', orangeOrRed);
document.querySelector('button').addEventListener('click', orangeOrRed);

console.log(document.querySelector('.secondElm').classList.value);
.d-none {
  display: none !important;
}

.firstElm {
  margin-top: 10px;
  width: 200px;
  height: 100px;
  background-color: blue;
 }
 
.orange-border {
  border: orange 3px solid;
}
 
.red-border {
  border: red 3px solid;
}
 
.secondElm {
  margin-top: 10px;
  width: 200px;
  height: 100px;
  background-color: green;
}

.orange {
  background-color: orange !important;
}

.red {
  background-color: red !important;
}
<button type="button" style="cursor: pointer;">Click here.</button>
<p>It should run the conditional statement whenever I click on the button to apply the border.</p>
<p> First Elm Border Color (MUST BE) Second Elm Background Color</p>
<div class='firstElm orange-border'></div>
<div class='secondElm'></div>
<p style="padding-bottom: 10px;">Remember that I only want to do this with(conditioal statements), It's possible either with classList.toggle() but I don't want to.</p>

Achieving the same results using the MutationObserver API.

It's useful when you have no toggle button or when you're not in control of when the class name of the element changes.

const firstElm = document.querySelector('.firstElm');
const secondElm = document.querySelector('.secondElm');

const orangeOrRed = () => {
    if (firstElm.classList.contains('red-border')) {
            secondElm.classList.remove('orange');
            secondElm.classList.add('red');
    } else if (firstElm.classList.contains('orange-border')) {
            secondElm.classList.remove('red');
            secondElm.classList.add('orange');
    };
}

// Callback function to execute when mutations are observed
const callback = (mutationsList) => {  
  // check to see if the changed attribute that caused the mutationObserver callback to be called is the class attribute and run the desired code
  if (mutationsList[0].attributeName === 'class') orangeOrRed();
};

// Create an observer instance linked to the callback function
const observer = new MutationObserver(callback);

// Options for the observer (which mutations to observe)
// Here the MutationObserver will call the specified callback just if attributes of the target node have changed
const config = { attributes: true, childList: false, subtree: false };

// Start observing the target node (firstElm) for configured mutations
observer.observe(firstElm, config);

const dToggle = () => {
  firstElm.classList.toggle('red-border');
};

document.querySelector('button').addEventListener('click', dToggle);

// You're right, the exact problem is right here.
window.addEventListener('load', orangeOrRed);
.d-none {
  display: none !important;
}

.firstElm {
  margin-top: 10px;
  width: 200px;
  height: 100px;
  background-color: blue;
 }
 
.orange-border {
  border: orange 3px solid;
}
 
.red-border {
  border: red 3px solid;
}
 
.secondElm {
  margin-top: 10px;
  width: 200px;
  height: 100px;
  background-color: green;
}

.orange {
  background-color: orange !important;
}

.red {
  background-color: red !important;
}
<button type="button" style="cursor: pointer;">Click here.</button>
<div class='firstElm orange-border'></div>
<div class='secondElm'></div>
<p style="padding-bottom: 10px;">Remember that I only want to do this with(conditioal statements), It's possible either with classList.toggle() but I don't want to.</p>

Upvotes: 2

Daniel Beck
Daniel Beck

Reputation: 21485

You've misinterpreted what the problem is here; it's not that the conditional isn't running, it's that it's checking the wrong thing.

You're looking to see if a DOM element's classList === 'orange-border' but this will never be true; classList isn't a simple string. What you want is to see if the classList includes orange-border.

const dToggle = () => {
  const firstElm = document.querySelector('.firstElm');

  firstElm.classList.toggle('red-border');
};

document.querySelector('button').addEventListener('click', dToggle);

const orangeOrRed = () => {
    const firstElm = document.querySelector('.firstElm');
    const secondElm = document.querySelector('.secondElm');

    // I'm not sure why you have both this ternary and the similar if:else below, but I've fixed both to at least be checking the classList correctly:
    firstElm.classList.contains('red-border') ? secondElm.classList.add('red') : secondElm.classList.add('orange');


    if (firstElm.classList.contains('red-border')) {
      secondElm.classList.remove('orange');
      secondElm.classList.add('red');
    } else if (firstElm.classList.contains('orange-border')) {
        secondElm.classList.remove('red');
        secondElm.classList.add('orange');
      };
    };

    window.addEventListener('load', orangeOrRed);

console.log(document.querySelector('.secondElm').classList.value);
.d-none {
  display: none !important;
}

.firstElm {
  margin-top: 10px;
  width: 200px;
  height: 100px;
  background-color: blue;
}

.orange-border {
  border: orange 3px solid;
}

.red-border {
  border: red 3px solid;
}

.secondElm {
  margin-top: 10px;
  width: 200px;
  height: 100px;
  background-color: green;
}

.orange {
  background-color: orange !important;
}

.red {
  background-color: red !important;
}
<button type="button" style="cursor: pointer;">Click here.</button>
<p>It should run the conditional statement whenever I click on the button to apply the border.</p>
<p> First Elm Border Color (MUST BE) Second Elm Background Color</p>
<div class='firstElm orange-border'></div>
<div class='secondElm'></div>
<p style="padding-bottom: 10px;">Remember that I only want to do this with(conditioal statements), It's possible either with classList.toggle() but I don't want to.</p>

Upvotes: 1

Related Questions