Search code examples
javascriptjquerypythondjangodjango-tables2

Making a Javascript click function for model objects formatted in Django Tables2 that shows related divs


I'm trying to make a Javascript function involving a django-tables2 table featuring model objects that will show relevant information when clicked. Here is the relevant code:

models.py

class Student(models.Model):
    student_id = models.CharField(max_length=128, unique=True, null=True, blank=True)
    first_name = models.CharField(max_length=128)
    last_name = models.CharField(max_length=128)
    ssn = USSocialSecurityNumberField(null=False)
    gender = models.CharField(max_length=128, choices=GENDER_CHOICES)
    country = CountryField(default='US', blank=True)
    primary_phone = models.CharField(max_length=128)
    email = models.EmailField(max_length=254, validators=[validate_email])
    background = models.CharField(max_length=128, choices=BACKGROUND_CHOICES)
    location = models.CharField(max_length=128, choices=LOCATION_CHOICES, default='south_plainfield')
    created_at = models.DateTimeField(null=True, auto_now_add=True)

tables.py

class StudentListTable(tables.Table):
    name = tables.TemplateColumn('''{{ record.first_name }} {{ record.last_name }}''', verbose_name=u'Name')
    manage = tables.TemplateColumn('''<a href="/students/update_student/{{ record.id }}">Update</a> / <a href="/students/delete_student/{{ record.id }}" onclick="return confirm('Are you sure you want to delete this?')">Delete</a>''')
    assign = tables.TemplateColumn('''<a href="/students/id={{ record.id }}/add_studentcourse">Courses</a> / <a href="/students/id={{ record.student_id }}/add_studentemployment">Employment</a> / <a href="/students/id={{ record.id }}/add_studentcounselor">Counselor</a> / <a href="/students/id={{ record.id }}/show_student_lists">Show</a>''')

    class Meta:
        model = Student
        fields = ('student_id', 'name', 'gender', 'ssn', 'email', 'primary_phone', 'created_at', 'manage', 'assign')
        row_attrs = {
            'id': lambda record: record.pk
        }
        attrs = {'class': 'table table-hover', 'id': 'student_list'}

views.py

def all_My_Student(request):
    student_list = Student.objects.order_by('-created_at')
    table = StudentListTable(student_list)
    RequestConfig(request).configure(table)
    return render(request, 'students/all_my_student.html', {'table': table, 'student_list': student_list})

all_my_student.html

{% block main_content %}
    <div class="box box-primary" id="student_list_table">
        {% if table %}
            {% render_table table %}
        {% endif %}
    </div>

    {% for student in student_list %}
        <div class="detailed" id="{{ student.id }}">
            {{ student.first_name }} {{ student.last_name }}
        </div>
    {% endfor %}
{% endblock %}

{% block custom_javascript %}
    <script>

        $(document).ready(function()
            {
                $('.detailed').hide();


            }
        );

    </script>
{% endblock %}

What I want to do is make a Javascript function that's basically like this: As you can see, the "detailed" class divs are hidden from the start. When you click on a row in the model object table, the "detailed" class div with an id that matches that of the row (or basically corresponds with the same model object in both the table loop and the second loop) will show, and the rest will still be hidden. I hope that it's clear.


Solution

  • As a sidenote, if the queryset used in the table is the same as student_list there is no need to pass student_list separately to the template context, you can just use table.data.

    I would hide the <div class="detailed"> blocks using CSS, and not using JavaScript, as if you do use JavaScript, they might be visible for a slight moment when the page loads.

    You should try to avoid adding id attributes to too much html elements. In your example, you add the student id as an id attribute to both the table <tr>'s and the <div class="detailed"> elements. The HTML spec requires ID's to be unique in the whole document, so if you want to use them, make sure they are unique.

    It's better to use data attributes. In the example below, I added the attribute data-student-id to both the table row and the <div class="detailed"> element. You can now select div[data-student-id="12"] to get the details div element for student with id = 12:

    # table.py
    class StudentListTable(tables.Table):
        name = tables.TemplateColumn('''...''', verbose_name=u'Name')
        manage = tables.TemplateColumn('''....''')
    
        class Meta:
            model = Student
            fields = ('student_id', 'name', 'gender', 'ssn', 'email', 'primary_phone', 'created_at', 'manage', 'assign')
            row_attrs = {
                'data-student-id': lambda record: record.pk
            }
            attrs = {'class': 'table table-hover', 'id': 'student_list'}
    
    {# django template #}
    <style>
        .detailed {
            display: none;
        }
    </style>
    
    {% for student in table.data %}
        <div class="detailed" data-student-id="{{ student.id }}">
            {{ student.first_name }} {{ student.last_name }}
        </div>
    {% endfor %}
    
    {% block custom_javascript %}
    <script>
        $(document).ready(function() {
            $('#student_list tr').on('click', function () {
                var student_id = $(this).data('student-id');
                $('div[data-student-id="' + student_id + '"]').show();
            });
        });
    </script>
    {% endblock %}
    

    Alternatively, you could add the required data to data- attributes of the table and create the details view in JavaScript. That maybe would make the generated HTML a bit smaller.