Search code examples
htmlpython-3.xflaskbootstrap5-modal

Display each dictionary of a list in a different modal


I'm using flask for my website application. It consists of reading certain files that contain a large number of dictionaries. I extracted that information on a list of dictionaries that looks like something like this (It's really importante to know that some dictionaries have the same value for the key "Event" but different information):

[
    {
        "Event": 100
        "Description": "This is a event 100 description",
        "CardID": 10,
        "Title": "This is a event 100 title",
        "Result": 1,
    },
    {
        "Event": 107
        "Description": "This is a event 107 description",
        "CardID": 20,
        "Title": "This is a event 107 title",
        "Result": 3,
    },
    {
        "Event": 107
        "Description": "This is a event 107 description",
        "CardID": 30,
        "Title": "This is a event 107 title",
        "Result": 1,
    },
    {
        "Event": 118
        "Description": "This is a event 118 description",
        "CardID": 50,
        "Title": "This is a event 118 title",
        "Result": 10,
    }
    ...
]

In the flask app i render a template which has a table, which iterates over other list with another information related with the dictionary from above but with less information (the event and a brief description). The first value of the body table has a link to open a modal which would show the information of the event and depending the button that is presses, it should show the information of the next event with the same number or the information of the next event.

I can't add images since is one of my first questiones but the modal that is shown when the link on the table is clicked, shows the information from all the events but i only want the information from one event (100 in this case) and, when the button "Siguiente validación ->" is pressed it should show the information of the next event 100 and, when "Siguiente Evento" is pressed it should show the information of the next event on the table (e.g.: 200)

This is the template code for the table and the modal:

{% extends './layout.html' %}

{% block body %}

<div class="container mb-5">

    <table border="1" id="tablaEventos" class="table table-striped table-bordered" style="width:100%">
        <thead>
            <tr>
                <th>Evento</th>
                <th>Descripción</th>
            </tr>
        </thead>
        <tbody>
            {% for eventInformation in listEventInformation %}
            <tr>
                <td>
                    <a href="" data-bs-toggle="modal" data-bs-target="#modal_Event{{ eventInformation.Evento }}">
                      {{ eventInformation.Evento }}
                    </a>
                </td>
               <td>{{ eventInformation.Descripción }}</td>
            </tr>
            {% endfor %}
        </tbody>
    </table>

    <!-- Modal -->
    {% for eventInformation in listEventInformation %}
    <div class="modal fade" data-bs-backdrop="static" id="modal_Event{{ eventInformation.Evento }}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
        <div class="modal-dialog">
          <div class="modal-content">
            <div class="modal-header">
              <h1 class="modal-title fs-5" id="exampleModalLabel">{{ eventInformation.Evento }}</h1>
              <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
              <div class="row">
                    <button type="button" class="btn btn-outline-primary btn-sm col-md-3">
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-left" viewBox="0 0 16 16">
                        <path fill-rule="evenodd" d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z"/>
                      </svg>
                        Validación Anterior
                    </button>
                    <!-- I used showModal(100) with data-current-result='1' here to demonstrate fetching the next result. Change here to match your logic -->
                    <button type="button" class="btn btn-outline-primary btn-sm col-md-3 ms-auto" data-current-result="1" onclick="showModal(this, 100)">
                        Siguiente Validación
                      <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-right" viewBox="0 0 16 16">
                        <path fill-rule="evenodd" d="M1 8a.5.5 0 0 1 .5-.5h11.793l-3.147-3.146a.5.5 0 0 1 .708-.708l4 4a.5.5 0 0 1 0 .708l-4 4a.5.5 0 0 1-.708-.708L13.293 8.5H1.5A.5.5 0 0 1 1 8z"/>
                      </svg>
                    </button>
              </div>
              <div class="container mt-3 mb-3" id="modalContent">
                  <!-- Modal content goes here -->
                  {% for eventKey, eventValue in eventInformation.items() %}
                    <li>{{eventKey}}: {{eventValue}}</li>
                  {% endfor %}
              </div>
            </div>
            <div class="modal-footer">
                <div class="container-fluid">
                    <div class="row">
                        <button type="button" class="btn btn-primary col-md-4">Evento anterior</button>
                        <!-- I used showModal(200) here to demonstrate fetching the next event. Change here to match your logic -->
                        <button type="button" class="btn btn-primary col-md-4 ms-auto" data-bs-toggle="modal" data-bs-target="#modal_Event{{ eventInformation.Evento }}" onclick="showModal(this, 200)">Siguiente Evento</button>
                    </div>
                </div>
            </div>
          </div>
        </div>
    </div>
    {% endfor %}
</div>

<!-- CDN MODAL-->
<script src="//cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>

<!-- CDN DATA TABLES-->
<script src="//code.jquery.com/jquery-3.5.1.js"></script>
<script src="//cdn.datatables.net/1.12.1/js/jquery.dataTables.min.js"></script>
<script src="//cdn.datatables.net/1.12.1/js/dataTables.bootstrap5.min.js"></script>

<script>
    $(document).ready(function () {
        $('#tablaEventos').DataTable({
            "language":{
                "url": "//cdn.datatables.net/plug-ins/1.12.1/i18n/es-ES.json"
            }
        });
    });

    const eventInfo = {{ eventInformation }}; // Use the value of eventInformation as a JS variable

----------

    function showModal(elementClicked, eventId) {
        var eventModalElement = document.getElementById('modal_Event');
        // Use getOrCreateInstance to prevent 'ghosting' that would result if a new modal were created
        var eventModal = bootstrap.Modal.getOrCreateInstance(eventModalElement);

        var currentResult = elementClicked.getAttribute("data-current-result");
        if (currentResult) {
            // Use the Start and End values to determine whether to increase the value of the currentResult or go to the next event
            // if currentResult less than end currentResult + 1
            // else eventId + 100 and currentResult = 1
        }

        // Fetch the modal content element
        var modalContent = document.getElementById("modalContent");
        // Set the HTML of the modal content element
        modalContent.innerHTML = getEventModalHtml(eventId);

        // Show the
        eventModal.show();
    }

    function getEventModalHtml(eventId) {
        html = "";

        for([eventKey, eventValue] of Object.entries(eventInfo)) {
            if (eventInfo["Evento"] === eventId) {
                html += <li>''+eventKey+': '+eventValue</li>>;
            }
        }

        return html;
    }
</script>

{% endblock %}

The real problem I think is how to show only the dictionary you are iterating over in the list and when you press the button, show the information of the next iteration.


Solution

  • After hours of testing I managed to fix it, the only problem I had was that the modal ID was being overwritten. To go from one event to another with the button "Siguiente Evento" I have solved it in part also in the same way, thanks to loop.index0 that jinja2 offers this is the new way to generate modals so when clicking on the button "Siguiente Evento" it simply shows the modal with the next ID.

      <div class="container mb-5">
    
        <table border="1" id="tablaEventos" class="table table-striped table-bordered" style="width:100%" align="center">
            <thead>
                <tr>
                    <th>Evento</th>
                    <th>Descripción</th>
                </tr>
            </thead>
            <tbody>
                {% for eventInformation in listEventInformation %}
                <tr>
                    <td>
                        <a href="" data-bs-toggle="modal" data-bs-target="#modal_{{ loop.index0 }}">
                          {{ eventInformation.Evento }}
                        </a>
                    </td>
                    <td>{{ eventInformation.Descripción }}</td>
                </tr>
                {% endfor %}
            </tbody>
        </table>
    
        <!-- Modal -->
        {% for eventInformation in listEventInformation %}
        <div class="modal fade" data-bs-backdrop="static" id="modal_{{ loop.index0 }}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
          <div class="modal-dialog">
            <div class="modal-content">
              <div class="modal-header">
                <h1 class="modal-title fs-5" id="exampleModalLabel">{{ eventInformation.Evento }}</h1>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
              </div>
              <div class="modal-body">
                <div class="container mt-3 mb-3">
                    <ul class="disc">
                    {% for eventKey, eventValue in eventInformation.items() %}
                        <li>{{ eventKey }}: {{ eventValue }}</li>
                    {% endfor %}
                    </ul>
                </div>
              </div>
              <div class="modal-footer">
                  <div class="container-fluid">
                      <div class="row">
                        <button type="button" class="btn btn-primary col-md-4" href="#modal_{{ loop.index0 - 1 }}" data-bs-toggle="modal" data-bs-dismiss="modal">Evento anterior</button>
                        <button type="button" class="btn btn-primary col-md-4 ms-auto" href="#modal_{{ loop.index0 + 1 }}" data-bs-toggle="modal" data-bs-dismiss="modal">Siguiente Evento</button>
                      </div>
                  </div>
              </div>
            </div>
          </div>
        </div>
        {% endfor %}
      </div>