We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
I'm building a checklist app for fun and I'm trying to use sortable.js with python Django.
I can make a sortable list work in this example with the html as follows
{% extends 'BJJApp/base.html' %} {% load static %} {%load crispy_forms_tags %} {% block content %} <br><br> <div id="standalone-items-container"> {% for item, formset, links in standalone_items_formsets_links %} <div class="modal fade" id="exampleModalToggle-{{ item.id }}" aria-hidden="true" aria-labelledby="exampleModalToggleLabel-{{ item.id }}" data-item-id="{{ item.id }}" tabindex="-1"> <div class="modal-dialog modal-dialog-centered"> <div class="modal-content"> <div class="modal-header"> <h1 class="modal-title fs-5" id="exampleModalToggleLabel-{{ item.id }}" style="color: {% if item.important %}red{% else %}inherit{% endif %};">{{ item.title }}</h1> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <form method="POST" id="main-form-{{ item.id }}" action="{% url 'viewitem' item.id %}"> {% csrf_token %} <div class="form-group"> <label for="title">Title</label> <input type="text" name="title" class="form-control" id="title-{{ item.id }}" value="{{ item.title }}" required disabled> </div> <div class="form-group"> <label for="memo">Memo</label> <textarea name="memo" rows="5" class="form-control" id="memo-{{ item.id }}" disabled>{{ item.memo }}</textarea> </div> <div class="form-group form-check"> <input type="checkbox" name="important" class="form-check-input" id="important-{{ item.id }}" {% if item.important %}checked{% endif %} disabled> <label class="form-check-label" for="important">Important</label> </div> </form> </div> <div id="links-{{ item.id }}"> {% if links %} <ul> {% for link in links %} <li><a href="{{ link.url }}" target="_blank">{{ link.url|urlizetrunc:50 }}</a></li> {% endfor %} </ul> {% else %} <p> No links available for this item.</p> {% endif %} </div> <div class="d-flex justify-content-end"> <a href="{% url 'updatelinks' item.id %}" style="display: none" id="updatelinks-{{ item.id }}"> <button type="button" class="btn btn-warning me-5"> Add or Remove Links </button> </a> </div> <br> <div class="modal-footer" > <button type="button" id="edit-button-{{ item.id }}" class="btn btn-primary me-2" onclick="toggleEdit({{ item.id }})">Edit</button> <!-- Complete Button Form (if item is not completed) --> {% if item.datecompleted is None %} <form method="POST" action="{% url 'completeitem' item.id %}" style="display:inline-block;"> {% csrf_token %} <button type="submit" class="btn btn-success me-2">Complete</button> </form> {% endif %} <!-- UnComplete Button Form (if item is completed) --> {% if item.datecompleted %} <form method="POST" action="{% url 'uncompleteitem' item.id %}" style="display:inline-block;"> {% csrf_token %} <button type="submit" class="btn btn-success me-2">UnComplete</button> </form> {% endif %} <!-- Delete Button Form --> <form method="POST" action="{% url 'deleteitem' item.id %}" style="display:inline-block;"> {% csrf_token %} <button type="submit" class="btn btn-danger">Delete</button> </form> </div> </div> </div> </div> <div class="card mb-3" style="max-width: 800px;" draggable="true" data-item-id="{{ item.id }}"> <div class="card-body d-flex justify-content-between align-items-center" style="cursor: pointer;"> <!-- <div class="card-body d-flex justify-content-between align-items-center" data-bs-target="#exampleModalToggle-{{ item.id }}" data-bs-toggle="modal" onclick="storeReferrerAndModal('{{ item.id }}', false)" style="cursor: pointer;"> --> <!-- Card Content --> <div> <h5 class="card-title" id="card-title-{{ item.id }}" style="color: {% if item.important %}red{% else %}inherit{% endif %};" >{{ forloop.counter }}. {{ item.title }}</h5> <p class="card-text">{{ item.memo }}</p> </div> <!-- Buttons --> <div> <button class="btn btn-primary" id="exampleModalToggleButton-{{item.id}}" data-bs-target="#exampleModalToggle-{{ item.id }}" data-bs-toggle="modal" onclick="storeReferrerAndModal('{{ item.id }}', false)"> Details </button> <!-- Complete Button Form (if item is not completed) --> {% if item.datecompleted is None %} <form method="POST" action="{% url 'completeitem' item.id %}" style="display:inline-block;"> {% csrf_token %} <button type="submit" class="btn btn-success">Complete</button> </form> {% endif %} <!-- UnComplete Button Form (if item is completed) --> {% if item.datecompleted %} <form method="POST" action="{% url 'uncompleteitem' item.id %}" style="display:inline-block;"> {% csrf_token %} <button type="submit" class="btn btn-success">UnComplete</button> </form> {% endif %} <!-- Delete Button Form --> <form method="POST" action="{% url 'deleteitem' item.id %}" style="display:inline-block;"> {% csrf_token %} <button type="submit" class="btn btn-danger">Delete</button> </form> </div> </div> </div> {% endfor %} </div> {% endblock %} {% block scripts %} <script src="{% static 'Checklist/Checklist.js' %}" ></script> <script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script> <script> document.addEventListener('DOMContentLoaded', function () { const container = document.getElementById('standalone-items-container'); const csrfToken = '{{ csrf_token }}'; // CSRF token for secure POST requests Sortable.create(container, { animation: 150, // Smooth animation while dragging onEnd: function (event) { // Get the updated order of item IDs const updatedOrder = Array.from(container.children).map((card, index) => { // Update the displayed order on the card const titleElement = card.querySelector('.card-title'); titleElement.textContent = `${index + 1}. ${titleElement.textContent.split('. ').slice(1).join('. ')}`; return card.dataset.itemId; }); // Send the updated order to the backend fetch("{% url 'update_item_order' %}", { method: "POST", headers: { "Content-Type": "application/json", "X-CSRFToken": csrfToken, // CSRF token for Django }, body: JSON.stringify({ order: updatedOrder }), }) .then(response => { if (!response.ok) { throw new Error("Failed to update order."); } return response.json(); }) .then(data => { console.log("Order updated:", data); }) .catch(error => { console.error("Error updating order:", error); }); }, }); }); </script> {% endblock %}
in my views I have
def test5(request): items = Item.objects.filter(user=request.user, datecompleted__isnull=True) if request.user.profile.role == "instructor": courses = request.user.checklist_courses.filter(related_course__isnull=False) else: courses = request.user.checklist_courses.exclude( creator__profile__role="instructor" ) courses_percentages = [] standalone_items_formsets_links = [] course_items_formsets_links = [] standalone_items = items.filter(courses__isnull=True).order_by("order") course_items = items.filter(courses__isnull=False) for item in standalone_items: LanguageFormSet = inlineformset_factory(Item, Link, fields=("url",), extra=1) formset = LanguageFormSet(instance=item) links = Link.objects.filter(item=item) standalone_items_formsets_links.append((item, formset, links)) for item in course_items: LanguageFormSet = inlineformset_factory(Item, Link, fields=("url",), extra=1) formset = LanguageFormSet(instance=item) links = Link.objects.filter(item=item) course_items_formsets_links.append((item, formset, links)) for course in courses: total_items = course.items.count() completed_items = course.items.filter(datecompleted__isnull=False).count() # Avoid division by zero if total_items > 0: progress_percentage = (completed_items / total_items) * 100 else: progress_percentage = 0 courses_percentages.append((course, progress_percentage)) return render( request, "BJJApp/test5.html", { "standalone_items": standalone_items, "courses_percentages": courses_percentages, "standalone_items_formsets_links": standalone_items_formsets_links, "course_items_formsets_links": course_items_formsets_links, }, ) def update_item_order(request): if request.method == "POST": try: data = json.loads(request.body) item_ids = data.get("order", []) # Update the order field for each item for idx, item_id in enumerate(item_ids, start=1): Item.objects.filter(id=item_id).update(order=idx) return JsonResponse({"success": True}) except Exception as e: return JsonResponse({"success": False, "error": str(e)}, status=400) return JsonResponse( {"success": False, "error": "Invalid request method."}, status=405 )
this works fine and I can drag and drop and update the order number and display the updated number of the items in the card.
but when I change it to modal, it doesn't work and doesn't update. Can anyone help?
{% extends 'BJJApp/base.html' %} {% load static %} {%load crispy_forms_tags %} {% block content %} <br /><br /> <div id="standalone-items-container"> {% for item, formset, links in standalone_items_formsets_links %} <div class="modal fade" id="exampleModalToggle-{{ item.id }}" aria-hidden="true" aria-labelledby="exampleModalToggleLabel-{{ item.id }}" data-item-id="{{ item.id }}" tabindex="-1" > <div class="modal-dialog modal-dialog-centered"> <div class="modal-content"> <div class="modal-header"> <h1 class="modal-title fs-5" id="exampleModalToggleLabel-{{ item.id }}" style="color: {% if item.important %}red{% else %}inherit{% endif %};" > {{ item.title }} </h1> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" ></button> </div> <div class="modal-body"></div> <br /> <div class="modal-footer"></div> </div> </div> </div> <div class="card mb-3" style="max-width: 800px" draggable="true" data-item-id="{{ item.id }}" > <div class="card-body d-flex justify-content-between align-items-center" style="cursor: pointer" > <!-- Card Content --> <div> <h5 class="card-title" id="card-title-{{ item.id }}" style="color: {% if item.important %}red{% else %}inherit{% endif %};" > {{ forloop.counter }}.{{item.title }} </h5> <p class="card-text">{{ item.memo }}</p> </div> </div> </div> {% endfor %} </div> {% endblock %} {% block scripts %} <script src="{% static 'Checklist/Checklist.js' %}"></script> <script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script> <script> document.addEventListener("DOMContentLoaded", function () { const container = document.getElementById("standalone-items-container"); const csrfToken = "{{ csrf_token }}"; // CSRF token for secure POST requests Sortable.create(container, { animation: 150, // Smooth animation while dragging onEnd: function (event) { // Get the updated order of item IDs const updatedOrder = Array.from(container.children).map( (card, index) => { // Update the displayed order on the card const titleElement = card.querySelector(".card-title"); titleElement.textContent = `${index + 1}. ${titleElement.textContent .split(". ") .slice(1) .join(". ")}`; return card.dataset.itemId; } ); // Send the updated order to the backend fetch("{% url 'update_item_order' %}", { method: "POST", headers: { "Content-Type": "application/json", "X-CSRFToken": csrfToken, // CSRF token for Django }, body: JSON.stringify({ order: updatedOrder }), }) .then((response) => { if (!response.ok) { throw new Error("Failed to update order."); } return response.json(); }) .then((data) => { console.log("Order updated:", data); }) .catch((error) => { console.error("Error updating order:", error); }); }, }); }); </script> {% endblock %}
The text was updated successfully, but these errors were encountered:
No branches or pull requests
I'm building a checklist app for fun and I'm trying to use sortable.js with python Django.
I can make a sortable list work in this example with the html as follows
in my views I have
this works fine and I can drag and drop and update the order number and display the updated number of the items in the card.
but when I change it to modal, it doesn't work and doesn't update. Can anyone help?
The text was updated successfully, but these errors were encountered: