-1

this is my problem: I've wrote this code for a bigger project

document.getElementById("swt").onclick = function() {
    if (this.innerText === "Off") {
        this.innerText = "On";
        document.getElementById("light-status").src="assets/img/lighting_filled.svg";
    } else {
        this.innerText = "Off";
        document.getElementById("light-status").src="assets/img/lighting_outline.svg";
    }

    document.getElementById("light-status").classList.toggle("light-on");
    document.getElementById("card-button").classList.toggle("card-on");
}
body {
    margin: 0;
    height: 100%;
    width: 100%;
    background-color: dimgray;
    font-family: 'Josefin Sans', sans-serif;
}

.grid-container {
    display: grid;
    grid-template-columns: minmax(256px, 20%) auto;
    grid-template-rows: auto 64px;
    height: 100vh;
}

.main-space-container {
    grid-column: 2;
    grid-row: 1;
    background-color: rgba(0,0,0,0.7);
    overflow-x: auto;
    overflow-y: hidden;
}

.floor-container, .system-container {
    display: flex;
    justify-content: flex-start;
    padding: 10px;
}

.card-container {
    margin: 10px;
    padding: 10px;
    max-width: 256px;
    max-height: 256px;
}

.card-title {
    font-size: 24px;
    font-weight: 400;
    padding-left: 5px;
    margin-top: 4px;
    margin-bottom: 2px;
    color: rgba(255,255,255,0.87);
}

.button-container {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(2, 1fr);
}

.card-button {
    margin: 5px;
    height: 96px;
    width: 96px;
    background-color: rgba(50,50,50,0.7);
    border-radius: 8px;
    transition: linear 0.2s;
    cursor: pointer;
}

.card-on {
    background-color: rgba(255,255,255,0.7);
    transition: linear 0.2s;
}

/* .card-button:hover {
    background-color: rgba(255,255,255,0.7);
    transition: linear 0.2s;
} */

.feed-container {
    padding-top: 20px;
}

.feed-text  {
    padding-top: 10px;
    padding-bottom: 10px;
    color: rgba(255,255,255,0.87);
}

/* alternative classes */

.large {
    height: 202px;
    width: 202px;
    border-radius: 8px;
    grid-column: 1 / span 2;
    grid-row: 1 / span 2;
}

.four-tile {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(2, 1fr);
}

.card-icon {
    grid-column: 1;
    grid-row: 1;
    filter: opacity(0.7);
    width: 75%;
    margin: auto;
}

.percentage {
    grid-column: 2;
    grid-row: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    color: rgba(255,255,255,0.7);
}

.name {
    grid-column: 1 / span 2;
    display: flex;
    justify-content: center;
    align-items: center;
    color: rgba(255,255,255,0.7);
}

.card-on > .name, .card-on > .percentage {
    color: rgba(0,0,0,0.87);
    transition: linear 0.2s;
}

.card-on > .card-icon {
    filter: invert(87%);
    transition: linear 0.2s;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Project 0</title>
    <link rel="stylesheet" href="assets/css/floor.css">
</head>
<body>

    <div class="grid-container">

        <!-- Start main -->
            <div class="system-container">
                <div class="card-container">
                    <h3 class="card-title">Lights</h3>
                    <div class="button-container">
                        <div class="card-button four-tile" id="card-button">
                            <img class="card-icon" id="light-status" src="assets/img/lighting_outline.svg">
                            <div class="percentage" id="swt">Off</div>
                            <div class="name">GF</div>
                        </div>
                        <div class="card-button four-tile" id="card-button">
                            <img class="card-icon" id="light-status" src="assets/img/lighting_outline.svg">
                            <div class="percentage" id="swt">Off</div>
                            <div class="name">FF</div>
                        </div>
                        <div class="card-button"></div>
                        <div class="card-button four-tile">
                            <img class="card-icon" id="sched-off" src="assets/img/clock_modern_outline.svg">
                            <div class="name">Scheduler</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <!-- End main -->

    </div>

    <!-- start script section -->

    <script src="assets/vendor/main-card.js"></script>
    
    <!-- end script section -->

</body>
</html>

and the JS function works, but only for the first element that it found with the specified ID. I know that that's the expected behavior using getElementById, but I've search a bit and I cannot find a way to make the function work with every element that as that ID. Someone can help?

UPDATE: I've tweaked the code in this way adding as suggested a class (called swt) instead of an ID and adding data-status="true" (or false) inside the div; but it throws me an error saying that btn[i] is undefined and getAttribute cannot work with it but btn[i].nodeName give me "DIV" as a feedback so it's not undefined (or I'm understanding it wrong?)

var btn = document.querySelectorAll(".swt");

for (var i = 0; i < btn.length; i++) {
    btn[i].addEventListener("click", function() {
        const state = btn[i].getAttribute("data-status")
        if (state === "true") {
            btn.innerText = "On";
        } else if (state === "false") {
            btn.innerText = "Off";
        } else {
            btn.innerText = "Not Connected";
        }

        btn.parentNode.querySelector("img.light-status").classList.toggle("light-on");
        btn.parentNode.classList.toggle("card-on");
    })
}
  • Is adding jQuery to your page an option? This would make things quite a bit easier. – Tomalak Sep 24 '20 at 10:26
  • **Id** must be unique. – Rayees AC Sep 24 '20 at 10:26
  • Does this answer your question? [Get multiple elements by Id](https://stackoverflow.com/questions/5338716/get-multiple-elements-by-id) – PMerlet Sep 24 '20 at 10:28
  • First of all. The same `id` must not appear more than once in HTML. Is it possible to change the part using `id` to `class`? – kako-jun Sep 24 '20 at 10:28
  • 1
    You should not have several elements with the same ID; you should rather assign a specific attribute (`data-whatever`) or class to all elements that should use that function, then select them with `document.querySelectorAll()` and loop through all the returned elements to add the `onClick` event handler. – secan Sep 24 '20 at 10:29
  • @Tomalak jQuery is an option if make think easier. – Paranoid Nemo Sep 25 '20 at 15:34
  • @kako-jun sure is, sorry I'm still learning and I didn't know that ID should be unique. – Paranoid Nemo Sep 25 '20 at 15:36

2 Answers2

0

Try

 <div class="card-button four-tile" id="card-button">
  <img class="card-icon" class="light-status" src="assets/img/lighting_outline.svg">
  <div class="percentage" class="swt">Off</div>
  <div class="name">GF</div>
</div>

And JS

document.querySelectorAll(".card-button .swt").map(btn => {
  btn.onclick = function() {
      const state = btn.getAttribute("data-state")
      if (state === "true") {
          btn.innerText = "On";
          btn.setAttribute("data-state", "false")
          btn.parentNode.querySelector("img.light-status").src="assets/img/lighting_filled.svg";
      } else {
          btn.innerText = "Off";
          btn.setAttribute("data-state", "true")
          btn.parentNode.querySelector("img.light-status").src="assets/img/lighting_outline.svg";
      }
  
      btn.parentNode.querySelector("img.light-status").classList.toggle("light-on");
      btn.parentNode.classList.toggle("card-on");
  }
}
Veyis Aliyev
  • 313
  • 2
  • 11
  • Thanks for the answer, I'm trying your solution but I don't understand from where "data-state" came. Is something I've to feed into the html or is a standard state for btn.getAttribute? Because if I use it as is it doesn't works here. Also you missed a ")" at the end of the js ;) – Paranoid Nemo Sep 25 '20 at 15:31
  • data-* attributes is custom attributes which added in HTML5. In HTML4 i didnt know it's been or not. Simple About data attrs [You can read here](https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes) – Veyis Aliyev Sep 25 '20 at 18:45
  • @ParanoidNemo Sorry. I didn't tested. – Veyis Aliyev Sep 25 '20 at 18:47
0

Ok, solved as hinted by @Tomalak and using jQuery because I was going nowhere with JS. Here my solution:

jQuery

$(".swt").click(function() {
var status = $(this).attr("data-status");
if (status === "true") {
    $(this).html("Off");
    $(this).attr("data-status", "false");
    $(this).prev().attr("src", "assets/img/lighting_outline.svg");
    $(this).parent().toggleClass("card-on");
} else if (status === "false") {
    $(this).html("On");
    $(this).attr("data-status", "true");
    $(this).prev().attr("src", "assets/img/lighting_filled.svg");
    $(this).parent().toggleClass("card-on");
} else {
    $(this).html("None")
}
console.log(status)
})

Html

<div class="card-button four-tile">
    <img class="card-icon light-status" src="assets/img/lighting_outline.svg">
    <div class="percentage swt" data-status="false">Off</div>
    <div class="name">GF</div>
</div>

maybe is not really elegant but for now works. Still interested to see if someone as a good JS to solve this because why not, I'll gladly learn something new.