Home > OS >  Display each dictionary of a list in a different modal
Display each dictionary of a list in a different modal

Time:11-03

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):

[
    {
        "Evento": 100
        "Descrición": "This is a event 100 description",
        "CardID": 10,
        "Title": "This is a event 100 title",
        "Result": 1,
    },
    {
        "Evento": 107
        "Descrición": "This is a event 107 description",
        "CardID": 20,
        "Title": "This is a event 107 title",
        "Result": 3,
    },
    {
        "Evento": 107
        "Descrición": "This is a event 107 description",
        "CardID": 30,
        "Title": "This is a event 107 title",
        "Result": 1,
    },
    {
        "Evento": 118
        "Descrición": "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 >

    <table border="1" id="tablaEventos"  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  data-bs-backdrop="static" id="modal_Event{{ eventInformation.Evento }}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
        <div >
          <div >
            <div >
              <h1  id="exampleModalLabel">{{ eventInformation.Evento }}</h1>
              <button type="button"  data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div >
              <div >
                    <button type="button" >
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"  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"  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"  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  id="modalContent">
                  <!-- Modal content goes here -->
                  {% for eventKey, eventValue in eventInformation.items() %}
                    <li>{{eventKey}}: {{eventValue}}</li>
                  {% endfor %}
              </div>
            </div>
            <div >
                <div >
                    <div >
                        <button type="button" >Evento anterior</button>
                        <!-- I used showModal(200) here to demonstrate fetching the next event. Change here to match your logic -->
                        <button type="button"  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.

CodePudding user response:

I'd say that part of the problem is that you're looping over the elements in evento. Assuming that listaEventos looks like

[
    {
        "Event": 100,
        "Desc": "ejkbjkberwjkber",
    },
    {
        "Event": 200,
        "Desc": "ejkbjkberwjkber",
    },
]

then {% for key, value in evento.items() %} will output Desc as its own table row and Event as its own table row. To display each row as Event/Description:

<tbody>
    {% for evento in listaEventos %}
    <tr>
        <td>
            <button>
              {{ evento.Event }}
            </button>
        </td>
       <td>{{ evento.Desc }}</td>
    </tr>
    {% endfor %}
</tbody>

To show the next event in a series, for example CardID 20, you might want to include more information for each element in listaEventos e.g.

[
    {
        "Event": 100,
        "Desc": "ejkbjkberwjkber",
        "Start": 1,
        "End": 2
    },
    {
        "Event": 200,
        "Desc": "ejkbjkberwjkber",
        "Start": 1,
        "End": 5
    },
]

Also, to minimise the HTML rendered, I'd move the modal to a separate code block outside each table row. That way, you can use a JavaScript function to populate the contents of the modal.

Bringing it all together:

<div >

    <table border="1" id="tablaEventos"  style="width:100%">
        <thead>
            <tr>
                <th>Evento</th>
                <th>Descripción</th>
            </tr>
        </thead>
        <tbody>
            {% for evento in listaEventos %}
            <tr>
                <td>
                    <button onclick="showModal(this, {{ evento.Event }})">
                      {{ evento.Event }}
                    </button>
                </td>
               <td>{{ evento.Desc }}</td>
            </tr>
            {% endfor %}
        </tbody>
    </table>

    <!-- Modal -->
    <div  data-bs-backdrop="static" id="modal_Event" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
        <div >
          <div >
            <div >
              <h1  id="exampleModalLabel"></h1>
              <button type="button"  data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div >
              <div >
                    <button type="button" >
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"  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"  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"  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  id="modalContent">
                  <!-- Modal content goes here -->
              </div>
            </div>
            <div >
                <div >
                    <div >
                        <button type="button" >Evento anterior</button>
                        <!-- I used showModal(200) here to demonstrate fetching the next event. Change here to match your logic -->
                        <button type="button"  onclick="showModal(this, 200)">Siguiente Evento</button>
                    </div>
                </div>
            </div>
          </div>
        </div>
      </div>
</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|tojson }}; // 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, resultId);

        // Show the
        eventModal.show();
    }

    function getEventModalHtml(eventId, resultId) {
        html = "";
        for (event of eventInfo) {
            // The following is just an example to return data
            // Use the eventId and resultId (if it exists) to filter
            if (event["Event"] === eventId) {
                var eventStr = "Event "   event["Event"]   " Result "   event["Result"]   "<br>"
                html  = eventStr;
            }
        }

        return html;
    }
</script>

Hope this helps.

For more reading: Bootstrap modals: https://getbootstrap.com/docs/5.0/components/modal

Jinja tojson filter: https://jinja.palletsprojects.com/en/3.0.x/templates/#jinja-filters.tojson

CodePudding user response:

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 >

    <table border="1" id="tablaEventos"  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  data-bs-backdrop="static" id="modal_{{ loop.index0 }}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
      <div >
        <div >
          <div >
            <h1  id="exampleModalLabel">{{ eventInformation.Evento }}</h1>
            <button type="button"  data-bs-dismiss="modal" aria-label="Close"></button>
          </div>
          <div >
            <div >
                <ul >
                {% for eventKey, eventValue in eventInformation.items() %}
                    <li>{{ eventKey }}: {{ eventValue }}</li>
                {% endfor %}
                </ul>
            </div>
          </div>
          <div >
              <div >
                  <div >
                    <button type="button"  href="#modal_{{ loop.index0 - 1 }}" data-bs-toggle="modal" data-bs-dismiss="modal">Evento anterior</button>
                    <button type="button"  href="#modal_{{ loop.index0   1 }}" data-bs-toggle="modal" data-bs-dismiss="modal">Siguiente Evento</button>
                  </div>
              </div>
          </div>
        </div>
      </div>
    </div>
    {% endfor %}
  </div>
  • Related