I wanted to quickly build a small web app, so I decided to go purely with django and what django offers - template rendering, so no React/Vue or such. The problem that I am having is, that I have some cards, which are being displayed in a for loop (jinja) once the user clicks on a card, a modal shows up and this is where it gets messy.
I want to pass the id of the card, so that I can make a get request and render the data in the modal. The code that I have is:
// index.html
<div id="machine-cards" class="grid grid-cols-3 gap-4 m-20">
{% for machine in machines %}
<div id="card-{{ machine.id }}" onclick="setModalData({{ machine.id }})" class="bg-white shadow-md rounded px-4 pt-4 pb-2 mb-4 transform hover:scale-105 cursor-pointer">
<div id="card-header" class="flex justify-between">
<p>Machine number: {{ machine.number }}</p>
<div id="state"
class="rounded-full h-4 w-4 {% if machine.status == 1 %} bg-green-500 {% elif machine.status == 2 %} bg-red-500 {% elif machine.status == 3 %} bg-yellow-500 {% else %} bg-gray-500 {% endif %}">
</div>
</div>
<div id="card-body" class="flex justify-center align-center mt-5 mb-5">
<p>{{ machine.manufacturer }}</p>
</div>
<div id="card-footer" class="flex justify-end">
<p class="text-gray-300 text-sm">Last updated: 28.06.2021</p>
</div>
</div>
{% endfor %}
</div>
{% include "general/modal.html" %}
<script>
function setModalData(cardId) {
// not sure what to do with the cardId :(
modal.style.display = 'flex';
}
</script>
// general/modal.html
<body>
<!-- The Modal -->
<div id="modal" class="hidden justify-center items-center h-full w-full absolute bg-black bg-opacity-50 top-0">
<!-- Modal content -->
<div class="bg-white shadow-md rounded px-6 pt-4 pb-8 w-1/2 h-1/2">
<div class="modal-header flex justify-end">
<span class="cursor-pointer text-3xl" onclick="modal.style.display = 'none'">×</span>
</div>
<div class="modal-content flex justify-center items-center ">
<div class="loader ease-linear rounded-full border-4 border-t-4 border-gray-200 h-12 w-12 mb-4"></div>
</div>
</div>
</div>
</body>
</html>
<script>
// Get the modal
let modal = document.getElementById("modal");
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
// somehow get the ID, fetch the data and hide the loader
</script>
I know how to do it with React or Vue.js, however, the application is very small and I wanted to quickly prototype it, so I decided to avoid using react/vue or such for now. I was considering giving alpine.js a go as it is smaller compared to the others.
What I have also tried and I hope this is not my best solution, is to move the include block in the for loop and have a hidden modal for every card, which is definitely not the most optimal solution.
I went for the suggestion in the comments by @Swati, which requires jquery (it is also possible to do it without, but in my opinion it is not worth it). The part of the the code that change is
// index.html
// some unchanged html code
<div class="machine-modal">
{% include "general/modal.html" %}
</div>
<script>
function setModalData(cardId) {
$(".machine-modal").html('').load(`{% url 'machine_details' %}?id=${cardId}`);
}
</script>
The view, which is under the machine_details
url will render the modal.html
with the needed context
def machine_details(request):
machine_id = request.GET.get('id', None)
if machine_id is not None:
machine_data = Machine.objects.get(machine=machine_id)
return render(request, 'general/modal.html', {'machineDetails': machine_data})
Lastly, the modal is hidden in an if block and shown only when the data is present
// modal.html
{% if machineDetails %}
// html code
{% endif %}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.