Search code examples
javascripthtmlcalendar

Change the color of the button day on a calendar if you click and dismark if you unclick (sum and substract the clicked days)?


I'm trying to make a responsive calendar where if I press a day it change its color and if I press two days it colors the two days (also that sums the days I click on a counter that is shown on screen) and like that consecutivly. Then if press again the day it will decolor and is substracted from the total of the sum.

This is what I have:

let day = document.getElementsByClassName('day');

for (i = 0;  i < day.length; i++) {
    if (day[i].classList.contains('day')) {
        day[i].addEventListener("click", function OnClick() {
            this.classList.add("vacacion");
            this.classList.remove("day");
        })
    } else if (day[i].classList.contains('vacation')) {
        day[i].addEventListener("click", function Click() {
            this.classList.remove("vacacion");
            this.classList.add("day");
        })
    }
}
* {
    margin: 0;
    padding: 0;
    font-family: Arial, Helvetica, sans-serif;
    color: rgb(65, 65, 65);
}

h1, td, th {
    text-align: center;
}

h1 {
    padding: 30px;
    background-color: rgb(140, 161, 218);
    color: white;
}

div#colors {
    margin: 15px 20px;
    display: grid;
    grid-template-columns: 85px 100px 100px auto;
}

div#colors div.config {
    width: 20px;
    height: 12px;
    float: left;
    margin-right: 3px;
    border-radius: 4px;
}

div#colors div.contador {
    width: 110px;
    justify-items: right;
    font-weight: 900;
}

div#colors div.contador h6 {
    font-weight: 600;
}

.festivos {
    background-color: #7d6da1;
    color: white;
}

.vacaciones {
    background-color: #ad626e;
    color: white;
}

.vacacion {
    background-color: #ad626e;
    color: white;
}

.ausencias {
    background-color: #a77f13;
    color: white;
}

div#colors h6 {
    font-size: 0.8em;
    font-weight: 500;
}

div#calendar {
    margin: 15px auto;
    display: grid;
    grid-template-columns: auto auto auto;
    column-gap: 30px;
    row-gap: 30px;
    justify-items: center;
    justify-content: center;
}

table {
    justify-self: center;
    align-self: start;
}

caption {
    background-color: rgb(140, 161, 218);
    padding: 5px;
    color: white;
    font-weight: 900;
}

.finde {
    background-color: rgb(230, 230, 230);
}

th {
    padding: 0 7px 0 7px;

}

td {
    padding: 3px 0 3px 0; 
}

.day {
    background-color: none;
}

@media only screen and (min-width: 1200px) {
    div#calendar {
        grid-template-columns: auto auto auto auto;
    }
}

@media only screen and (max-width: 850px) {
    div#calendar {
        grid-template-columns: auto auto;
    }
}

@media only screen and (max-width: 600px) {
    div#calendar {
        grid-template-columns: auto;
    }
}
<!DOCTYPE html>
<html>
<head>
    <link href="calendario.css" rel="stylesheet" type="text/css">
</head>
  
<body>
    <h1>2023</h1>
     
    <div id="colors">
        <div>
            <div class="festivos config"></div>
            <h6>Festivos</h6>
        </div>
        <div>
            <div class="vacaciones config"></div>
            <h6>Vacaciones</h6>
        </div>
        <div>
            <div class="ausencias config"></div>
            <h6>Ausencias</h6>
        </div>
        <div class="contador"><h6>Días festivos:<span id="contador">#</span></h6></div>
    </div>
    
    <div id="calendar">
        <!-- ENERO 2023 -->
        <table>  
            <caption>ENERO</caption>
            <thead>
                <tr>
                    <th>Lu</th>
                    <th>Ma</th>
                    <th>Mi</th>
                    <th>Ju</th>
                    <th>Vi</th>
                    <th>Sa</th>
                    <th>Do</th>
                </tr>
            </thead>
            
            <tbody>
                <tr>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td class="finde">1</td>
                </tr>
                <tr>
                    <td class="day">2</td>
                    <td class="day">3</td>
                    <td>4</td>
                    <td>5</td>
                    <td class="festivos day">6</td>
                    <td class="finde day">7</td>
                    <td class="finde">8</td>
                </tr>
                <tr>
                    <td>9</td>
                    <td>10</td>
                    <td>11</td>
                    <td>12</td>
                    <td>13</td>
                    <td class="finde">14</td>
                    <td class="finde">15</td>
                </tr>
                <tr>
                    <td>16</td>
                    <td>17</td>
                    <td>18</td>
                    <td>19</td>
                    <td class="festivos">20</td>
                    <td class="finde">21</td>
                    <td class="finde">22</td>
                </tr>
                <tr>
                    <td>23</td>
                    <td>24</td>
                    <td>25</td>
                    <td>26</td>
                    <td>27</td>
                    <td class="finde">28</td>
                    <td class="finde">29</td>
                </tr>
                <tr>
                    <td>30</td>
                    <td>31</td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
            </tbody>
        </table>
     </div>

    <script src="calendario.js"></script>
</body>
  
</html>


Solution

  • You almost got it right! The only thing you missed is the "unchecked" state where you have to remove the class vacation and add day back to it.

    It is also worth mentioning that only the elements that have day class (1,2,6 and 7) at the time you are query the elements (document.getElementsByClassName('day')) will have the click handler registered because you query only those. This is also the reason why you never get to register click handler on vacation items since else if in loop will never be reached.

    I added an extra class for selected elements so it is easier to count them so the counter could be updated appropriately - you could use day or vacation class ass well for this purpose.

    let day = document.getElementsByClassName('day');
    // get counter element
    let counterEl = document.getElementById('contador');
    let counter = 0;
    
    for (i = 0; i < day.length; i++) {
        if (day[i].classList.contains('day')) {
            day[i].addEventListener('click', function click() {
                // you have to add vacation if it is not already in classList
                // and remove it if it is already there. You could check if
                // classList contains vacation and then remove it, but toggle
                // does that under the hood for you
                this.classList.toggle('vacacion');
                this.classList.toggle('day');
                // adding additional selected class to know which ones are selected
                this.classList.toggle('selected');
    
                // if element has selected class then increase the counter,
                // otherwise decrease it
                if (this.classList.contains('selected')) {
                    counter += 1;
                } else {
                    counter -= 1;
                }
    
                // update the counter
                counterEl.innerText = counter;
            });
    
            // the statement below will NEVER execute, since the first condition
            // will always be true because you query only the elements with
            // classname "day" in line 1.
            // ...
        }
    }