-
-
Notifications
You must be signed in to change notification settings - Fork 131
Description
Bug Description
I have a for loop inside a component that renders multiple times a child component (a table with rows). These rows contain a button that updates the state of the component to show a modal in a reactive way. This interaction works, what is not displayed reactively is the modal when the state has changed. I have tried everything but nothing works.
The property that does not work in a reactive way is displayed_modal, and I can assure you that the change from False to True does occur because I have debugged it. It is not a problem with the interface either, because when you load the page with this status set to True for testing purposes, the modals are displayed. What doesn't work is the reactivity.
Expected behaviour
The modal is displayed in a reactive manner based on the change of state.
Screenshots / Screenrecords
Parent component:
from django.db.models.query import QuerySet
from django_unicorn.components import UnicornView
from apps.passwords.models import Password
from authentication.models import AppUser
class PasswordTableView(UnicornView):
"""
Password table component
"""
user_passwords: QuerySet[Password]
def mount(self) -> None:
"""
Mounts the component
"""
self.load_passwords()
def load_passwords(self) -> None:
"""
Loads passwords
"""
user: AppUser = self.request.user
self.user_passwords = user.passwords.all()
Parent template:
{# Password table component #}
{% load unicorn %}
Passwords
<button class="text-xs text-white bg-gray-900 p-2 rounded-md transition-colors hover:bg-gray-900/90">
Add password
</button>
</div>
<div class="mt-4 rounded-md shadow-md overflow-x-auto">
<table class="w-full text-left">
<thead class="text-xs text-white bg-gray-900 uppercase">
<tr>
<th class="px-6 py-3">Name</th>
<th class="px-6 py-3">Password</th>
<th class="px-6 py-3">Username</th>
<th class="px-6 py-3">Email</th>
<th class="px-6 py-3">Site</th>
<th class="px-6 py-3">Actions</th>
</tr>
</thead>
<tbody class="text-sm">
{% if not user_passwords %}
<tr>
<td class="px-6 py-4" colspan="6">No passwords found</td>
</tr>
{% endif %}
{% for password in user_passwords %}
{% unicorn 'password-row' password=password key=password.id %}
{% endfor %}
</tbody>
</table>
</div>
</div>
Child component:
from django_unicorn.components import UnicornView
from apps.passwords.components.password_table import PasswordTableView
from apps.passwords.models import Password
class PasswordRowView(UnicornView):
"""
Password table component
"""
password: Password
displayed_modal = False
def display_modal(self) -> None:
"""
Displays a modal
Parameters
----------
modal_id : str
The id of the modal to display
"""
self.displayed_modal = True
def hide_modal(self) -> None:
"""
Hides the modal
"""
self.displayed_modal = False
def delete_password(self, password_id: int) -> None:
"""
Deletes a password
"""
password = Password.objects.get(id=password_id)
password.delete()
parent: PasswordTableView = self.parent
parent.load_passwords()
Child template:
{{ password.name }}<td class="px-6 py-4">
<div class="flex items-center gap-5">
<p>**********</p>
<button class="w-[50px] text-xs text-gray-700 bg-gray-300 py-0.5 rounded-md transition-colors hover:bg-gray-300/80"
id="copy-password-button"
data-password="{{ password.password }}">Copy</button>
</div>
</td>
<td class="px-6 py-4">{{ password.username|default:"..." }}</td>
<td class="px-6 py-4">{{ password.email|default:"..." }}</td>
{% if password.site %}
<td class="px-6 py-4">
<a class="underline text-blue-500"
href="{{ password.site }}"
target="_blank">{{ password.site }}</a>
</td>
{% else %}
<td class="px-6 py-4">...</td>
{% endif %}
<td class="px-6 py-4">
<div class="flex items-center gap-1">
<button class="text-xs text-yellow-900 bg-yellow-400 px-1.5 py-1 rounded-md transition-colors hover:bg-yellow-300/90">
Edit
</button>
<button unicorn:click.stop="display_modal"
class="text-xs text-red-900 bg-red-400 px-1.5 py-1 rounded-md transition-colors hover:bg-red-300/90">
Delete
</button>
</div>
</td>
{% if displayed_modal %}
<div class="fixed top-0 left-0 w-full h-screen flex items-center justify-center bg-black/20 z-50">
<div class="bg-white rounded-md shadow-lg">
<div class="flex items-center justify-between p-4 border-b">
<h3 class="text-xl font-bold">Warning</h3>
<button unicorn:click="hide_modal"
class="w-8 h-8 flex items-center justify-center rounded-lg hover:bg-gray-100">
<svg class="w-5"
fill="none"
stroke-width="1.5"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="p-4 border-b border-gray-200">
<p>
You are about to delete the password <strong>{{ password.name }}</strong>. Are you sure you want to proceed?
</p>
</div>
<div class="flex items-center gap-2 p-4">
<button unicorn:click="delete_password({{ password.id }})"
unicorn:refresh
unicorn:loading.attr="disabled"
unicorn:loading.class="opacity-50 cursor-not-allowed"
unicorn:loading.class.remove="hover:bg-red-500/90"
class="w-28 flex items-center justify-center gap-1 text-white bg-red-500 py-2.5 rounded-md transition-colors hover:bg-red-500/90"
id="delete-password-{{ password.id }}">
Delete
<svg unicorn:target="delete-password-{{ password.id }}"
unicorn:loading.class.remove="hidden"
class="hidden w-5 animate-spin"
fill="none"
stroke-width="1.5"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99" />
</svg>
</button>
<button unicorn:click="hide_modal"
class="flex items-center justify-center gap-1 text-white bg-gray-900 px-5 py-2.5 rounded-md transition-colors hover:bg-gray-900/90">
Cancel
</button>
</div>
</div>
</div>
{% endif %}
Steps to reproduce
No response
What browsers are you seeing the problem on?
No response
👀 Have you checked for similar open issues?
- I checked and didn't find similar issue
Code of Conduct
- I agree to follow this project's Code of Conduct
Are you willing to work on this issue ?
None