1

In a django project, I'm trying to make a table with cells turning red when user clicks on it.

here is my template :

<table id="this_week" width=88%>
    <tr id = "days">
        <th><p>Horaire</p></th>
        <th><p>lun.</p></th>
        <th><p>Mar.</p></th>
        <th><p>Mer.</p></th>
        <th><p>Jeu.</p></th>
        <th><p>Ven.</p></th>
        <th><p>Sam.</p></th>
        <th><p>Dim.</p></th>
    </tr>
    {% with hours="9h 9h30 10h 10h30 11h 11h30 12h 12h30 13h 13h30 14h 14h30 15h 15h30 16h 16h30 17h 17h30 18h 18h30 19h 19h30 20h 20h30 21h" %}
    {% for i in hours.split %}
        <tr id= "{{ i }}">
            <th><p>{{ i }}</p></th>
            <th id="{{ i }} lun" class="available" onclick='deliveryBooking()'></th>
            <th id="{{ i }} mar" class="available" onclick='deliveryBooking()'></th>
            <th id="{{ i }} mer" class="available" onclick='deliveryBooking()'></th>
            <th id="{{ i }} jeu" class="available" onclick='deliveryBooking()'></th>
            <th id="{{ i }} ven" class="available" onclick='deliveryBooking()'></th>
            <th id="{{ i }} sam" class="available" onclick='deliveryBooking()'></th>
            <th id="{{ i }} dim" class="available" onclick='deliveryBooking()'></th>
        </tr>
    {% endfor %}
    {% endwith %}
</table>
<script>
function deliveryBooking()
{
    if ($(this).hasClass('available')) {
        $(this).removeClass('available');
        $(this).addClass('unavailable');
        console.log($(this));
    };
};
</script>

But that script does nothing, even in the console log nothing appears. Then I tried to remove the "onclick" attribute on the cells and imported a js file with this code (I tried the following functions one after the other) with no more results :

$(document).ready(function() {

$("#this_week").children().find('.available').click(function(event){
    $(event.target).removeClass("available").addClass("unavailable");
    console.log($(event.target));
});

$("#this_week").children().find('.available').click(function(){
    $(this).removeClass("available").addClass("unavailable");
    console.log($(this));
});

});

I also tried to remove the "children()" part and other little changes but I don't know what to try next. Any ideas about what I'm doing wrong ?

AlexMdg
  • 115
  • 1
  • 8

3 Answers3

2

Here is the simplest method

All I did was to remove the onclick and add

$(".available").on("click",function() { 
  $(this).toggleClass("available unavailable"); 
});

The creation of the table is irrelevant, I use jQuery here purely to create the cells for the example

$.each("9h 9h30 10h 10h30 11h 11h30 12h 12h30 13h 13h30 14h 14h30 15h 15h30 16h 16h30 17h 17h30 18h 18h30 19h 19h30 20h 20h30 21h".split(" "),function(i,hour) {

        $("#hours").append(`<tr><th><p>${hour}</p></th>
            <th id="${i}lun" class="available"></th>
            <th id="${i}mar" class="available"></th>
            <th id="${i}mer" class="available"></th>
            <th id="${i}jeu" class="available"></th>
            <th id="${i}ven" class="available"></th>
            <th id="${i}sam" class="available"></th>
            <th id="${i}dim" class="available"></th></tr>`);
})
$(".available").on("click",function() { 
  $(this).toggleClass("available unavailable"); 
});
.available { background-color:green }
.unavailable { background-color:red }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="this_week" width=88%>
    <tr id="days">
        <th><p>Horaire</p></th>
        <th><p>Lun.</p></th>
        <th><p>Mar.</p></th>
        <th><p>Mer.</p></th>
        <th><p>Jeu.</p></th>
        <th><p>Ven.</p></th>
        <th><p>Sam.</p></th>
        <th><p>Dim.</p></th>
    </tr>
    <tbody id="hours"></tbody>
</table>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • I see, you wrote the table with js instead of django. I don't know yet if it will ease my future work on this page or make it harder : I'll have to work with django models, variables, etc... I upvoted the answer but will make my final choice later today after going back to the back-end a little bit. Meanwhile i'll keep with @Nishant_Dixit answer (less changes) and see how it goes. Thanks for this anyways, it's good learning for me. – AlexMdg Sep 10 '18 at 10:25
  • The writing of the table is completely irrelevant - I did it to have a working version. Only change was to remove the onclick – mplungjan Sep 10 '18 at 10:37
  • 1
    Wow yeah you're right. The problem was i put the – AlexMdg Sep 10 '18 at 11:47
  • Alternatively have `$(function() { $(".available").on("click",function() { $(this).toggleClass("available unavailable"); }); });` anywhere on the page – mplungjan Sep 10 '18 at 12:28
0

You need pass this in onclick function, by defualt this refers to window object.

HTML

<th id="{{ i }} dim" class="available" onclick='deliveryBooking(this)'></th>

Js

<script>
function deliveryBooking(element)
{
    if ($(element).hasClass('available')) {
        $(element).removeClass('available');
        $(element).addClass('unavailable');
        console.log($(element));
    };
};
</script>
Nishant Dixit
  • 5,388
  • 5
  • 17
  • 29
0

Remove onclick=deliveryBooking(), and use this code.

$('#this_week').on('click', '.available, .unavailable', function(){
    $(this).toggleClass('available unavailable')
})

This code uses event delegation. Please read jQuery API in case you need to understand more. .on / .toggleClass

On an unrelated note, I think your markup is probably wrong. <th> is used for table headers, while you <td> for cells which contain actual data. I think all the <th> within you for loop need to be changed to <td>, except the first one.

rmn
  • 1,119
  • 7
  • 18
  • No need for delegation since the table is created before the script. See my solution for a simpler version – mplungjan Sep 10 '18 at 10:51
  • You're right. There's no need for delegation in this case. But i have kind of already preferred binding to the parent element, rather than to 10 individual elements. But just now, i read that [delegate saves CPU when binding event handlers; bind saves CPU when events trigger](https://stackoverflow.com/a/8827535/2206733) which actually makes a lot of sense. So yup, anyone reading it, please see @mplungjan's answer. I'll leave this here for anyone having the same binding/delegation dilemma and for td/th issue. – rmn Sep 10 '18 at 10:58
  • What is really interesting is that jQuery handles the toggle afterwards, so only necessary to bind to .available – mplungjan Sep 10 '18 at 11:08
  • @mplungjan True, thats why your code's more elegant. It works because they are real bindings to DOM elements irrespective of class/id/attribute changes. While those delegates are like indirect bindings, the original selector no longer matches and it stops working. i.e. Delegates are like the symbolic links of event bindings, :p – rmn Sep 10 '18 at 11:35
  • Yep thanks for the th/td thing and for bringing up that delegation thing, might be useful someday :p – AlexMdg Sep 10 '18 at 11:49