1

For a HTML button:

<button type="button" id="100">100%</button>

I have a java script function, that swaps 2 background colors of that button:

const but1 = document.getElementById("100");

n=0;

but.addEventListener("click", function (){
    if (n==0) {
        but1.style.backgroundColor = "rgb(225, 165, 0)";
        n=1;
    } else {
        but1.style.backgroundColor = "rgb(225, 165, 0,0)";
        n=0;
    } 
});

Works fine. But i want to create more buttons, and don`t want to copy the same function every time. So to make it more simple, ive written a function that will take parameters , lets say "b" (for buttons),"c1" and "c2" (for colors), and "x" - that represents the "n" value (for every button). So my java script (for the HTML button) with example set of two buttons

const but1 = document.getElementById("button");

n=0;

function colorSwitch (b, c1, c2, x){
    if (x==0) {
        b.style.backgroundColor = c1;
        x=1;
    } else {
        b.style.backgroundColor = c2;
        x=0;
    }
}

// orange set

const cOrange = "rgb(225, 165, 0)";
const cOrangeT = "rgb(225, 165, 0,0)";

but1.addEventListener("click", function(){
    colorSwitch(but1, cOrange, cOrangeT, n);
});

The problem i have is with "x" parameter. It seems to grab the initial "0" value, then it is set to "1". But when i click the button again the initial value is again "0". So there is no loop and the color doesn't swap.

What am i not understanding in behavior of "x", and how to code it correctly?

bartc
  • 123
  • 9
  • you never change the value of `n`, which you send in as a parameter in colorSwitch. – Rickard Elimää Mar 08 '20 at 23:39
  • the value changes, but it doesn't "save" it - so instead of starting the value on "1" when second click, it starts with "0" again – bartc Mar 08 '20 at 23:41
  • 3
    Primitive values (like numbers) are passed _by value_ and not by reference. This means that when you call `colorSwitch`, `x` will be come _a copy_ of `n`. You are then changing `x` and not `n` which has no effect since `x` ceases to exist after your `colorSwitch` function returned. – CherryDT Mar 08 '20 at 23:42
  • @CherryDT exactly thank you. And thats what i`m trying to figure out. How to make "x" preserve its value? – bartc Mar 08 '20 at 23:48
  • You don't, reassign `n` instead. You don't need to save `x` since it will be passed with every function call. – El_Vanja Mar 08 '20 at 23:51
  • @El_Vanja but "n" has to be different for every button ("m" for second, "k" for third and so on). as it will cause conflict when two buttons are "on" at the same time – bartc Mar 08 '20 at 23:56
  • 2
    PS `rgb(225, 165, 0, 0)` is an invalid color, use the Alpha channel: `rgba(225, 165, 0, 0)` – Roko C. Buljan Mar 09 '20 at 00:18
  • 1
    PS `getElementById("button")` you have no such ID element. – Roko C. Buljan Mar 09 '20 at 00:24
  • @RokoC.Buljan - right, should be "100". nice catch. – bartc Mar 14 '20 at 00:50

2 Answers2

2

To compare an Element computed color towards a color string - see this answer

Toggle styles using CSS class and classList.toggle()

Use a common class (i.e: class="btnTog") as your selector for all your target buttons.
Use Element.classList.toggle() instead, to toggle a .is-active CSS class:

function colorwitch() {
  this.classList.toggle('is-active');
}

const btns = document.querySelectorAll(".btnTog");
btns.forEach(btn => btn.addEventListener('click', colorwitch));
.btnTog {
  border: 0;
  padding: 0.5em;
  background-color: rgba(225, 165, 0, 0.5);
}

.is-active {
  background-color: rgba(255, 180, 0, 1)
}
<button class="btnTog" type="button">100%</button>
<button class="btnTog" type="button">100%</button>

Toggle colors using data-* attribute to store a state (1/0)

If for some unknown reasons you want to store a state right inside an Element you can use the super handy data-* attribute or dataset property:

function colorSwitch () {
  this.style.backgroundColor = [
    "rgba(225, 165, 0, 0.5)",
    "rgba(255, 180, 0, 1)",
  ][this.dataset.tog ^= 1]; // Toggle 1, 0, 1, 0, ...
}

const btns = document.querySelectorAll(".btnTog");
btns.forEach(btn => btn.addEventListener('click', colorSwitch));
.btnTog {
  border: 0;
  padding: 0.5em;
  background-color: rgba(225, 165, 0, 0.5);
}
<button class="btnTog" type="button">100%</button>
<button class="btnTog" type="button">100%</button>
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
  • pro, thank you. The reason why actually toggling might be better than changing the background in java script is it doesn't change it permanently this way. So when i`m trying to set :hover state on a button - it want work when java script sets the background with .style property. – bartc Mar 09 '20 at 01:52
  • only problem , is that buttons colors are gonna be different (so the code has to be slightly modified) – bartc Mar 09 '20 at 06:04
  • @bartc why didn't you mentioned different colors in your Question? :) The only thing I could see was two colors in two variables. Are the buttons differently colored by default? – Roko C. Buljan Mar 09 '20 at 10:28
  • @bartc you accepted a wrong answer whatsoever, The answerer does not know that one should **never** rely on `if (El.style.backgroundColor === 'some color' )` because the returned value it totally up to the browser - and might accidentally not match your expected color value and format. – Roko C. Buljan Mar 09 '20 at 14:36
  • Roko with all respect to your anwser, very informative, pro. And which also was a nice school for me becouse of the concepts you used in your code and your skills, Vanjas anwser actually solved my puzzle (even if it had a flaw). But you are right your level of answer deserves to be accepted. Thank you again for your time bro – bartc Mar 14 '20 at 00:17
0

Please refer to the accurate and thorough answer provided by Roko C. Buljan. I was unaware browsers could return a different string from the one stored in an element.

You can do without the parameter altogether. Inside your switching function do a comparison of the current state of the button:

function colorSwitch (b, c1, c2){
    if (b.style.backgroundColor === c1) {
        b.style.backgroundColor = c2;
    } else {
        b.style.backgroundColor = c1;
    }
}

El_Vanja
  • 3,660
  • 4
  • 18
  • 21
  • **This is wrong from so many aspects**. The browser will return whatever string he wants. You cannot reliably use `===`, specially not on malformatted input strings. – Roko C. Buljan Mar 09 '20 at 14:38
  • @RokoC.Buljan - could you explain more please? why the browser will return whatever string? And why we cant rely on `===` ? – bartc Mar 14 '20 at 00:49
  • 1
    @bartc see this fiddle: https://jsfiddle.net/bzpx7cuo/ In Chrome for example, play with the `color` variable, you'll see that you'll always get a result translated in `rgb` unit, therefore it's not reliable to match that result using `===` on an expected input color string. – Roko C. Buljan Mar 14 '20 at 12:38
  • 1
    @bartc a solution would be to create a function that creates an inmemory Element, assigns to that element the String input color value, and only afterwards compares the two div colors - reliably, since now both values will be translated by the browser and eventually hold an exact match. – Roko C. Buljan Mar 14 '20 at 12:42
  • @RokoC.Buljan indeed, it consol.logs it in rgb always, no matter how the color is expressed before. so - as i understand - variables for that function expressed in `rgb` should be safe then? – bartc Mar 15 '20 at 01:48
  • @RokoC.Buljan i found it kinda strange than even `rgba` - which expresses transparency also - is rendered to `rgb`. To be honest i dont understand it. what is happening to that last value, it gets omitted? – bartc Mar 15 '20 at 01:52
  • 1
    @bartc It's up to the browser. And there are many. Yes, `rgba` with Alpha set to `1` will be translated to `rgb` since alpha it at max opacity `1` - But that's Chrome (and luckily most modern browsers). But open the fiddle above in te older Edge or run the code in IE 11 to see even weirder results. And even in modern browsers, can one guarantee that Alpha will always be ignored? Can we be guaranteed that spaces will always be used? – Roko C. Buljan Mar 15 '20 at 02:02
  • @bartc I posted an answer and a solution to another (older) question https://stackoverflow.com/a/60689673/383904 Hope will be useful. – Roko C. Buljan Mar 15 '20 at 04:14