Search code examples
djangodjango-modelsbootstrap5-modal

Django: Pass model ID to url using bootstrap modal


I'm trying to create a delete confirmation dialog using bootstrap 5 modals in my Django project.

{% extends 'base.html' %}
{% block content %}

  <div class="col-md-6 offset-md-3">
    {% if messages %}
        {% for message in messages %}
            <div class="alert alert-success alert-dismissible fade show" role="alert">
                {{ message }}
                <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
            </div>
        {% endfor %}
    {% endif %}
  </div>

  <h1>Service Overview</h1>
  <br/>

  <div class="d-grid gap-2 justify-content-md-end">
    <a class="btn btn-primary" href="{% url 'add_service' %}">Add service</a>
    <br/>
  </div>

  <table class="table table-hover table-bordered">
    <thead class="table-secondary">
        <tr>
            <th class="text-center" scope="col">#</th>
            <th scope="col">Name</th>
            <th scope="col">Description</th>
            <th class="text-center" scope="col">Cost</th>
            <th class="text-center" scope="col">Created at</th>
            <th class="text-center" scope="col">Updated at</th>
            <th class="text-center" scope="col">Status</th>
            <th class="text-center" scope="col">Actions</th>
        </tr>
    </thead>
    <tbody>
      {% for service in services %}
          <tr>
              <td class="text-center">{{ service.id }}</td>
              <td>{{ service.name }}</td>
              <td>{{ service.description}}</td>
              <td class="text-center">{{ service.cost }} AED</td>
              <td class="text-center">{{ service.created_date }}</td>
              <td class="text-center">{{ service.updated_date }}</td>
              {% if service.status == "ACTIVE" %}
                <td class="text-center">
                  <span class="badge text-bg-success" style="font-size:0.7em;">{{ service.status }}</span>
                </td>
              {% elif service.status == "INACTIVE"%}
                <td class="text-center">
                  <span class="badge text-bg-danger" style="font-size:0.7em;">{{ service.status }}</span>
                </td>
              {% endif %}
              
              <td class="text-center">
                <!--Update-->
                <a href="{% url 'service_record' service.id %}" class="text-decoration-none">
                    <button  type="button" class="btn btn-warning btn-sm" data-bs-toggle="tooltip" title="Update service">
                        <i class="bi bi-pencil-fill"></i>
                    </button>
                </a>

                <!--Delete modal-->
                <!-- Button trigger modal -->
                <button type="button" class="btn btn-danger btn-sm" data-bs-toggle="modal" data-bs-target="#DeleteDialogueModal">
                  <i class="bi bi-trash"></i>
                </button>


                <!-- Modal -->
                <div class="modal fade" id="DeleteDialogueModal" tabindex="-1" aria-labelledby="modal-title" aria-hidden="true">
                  <div class="modal-dialog" role="document">
                    <div class="modal-content">
                      <div class="modal-header">
                        <h1 class="modal-title fs-5" id="modal-title">Delete service: {{ service.name }}</h1>
                        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                      </div>
                      <div class="modal-body">
                        <p>Are you sure to delete the service {{ service.name }} ?</p>
                      </div>
                      <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Go back</button>
                        <a class="btn btn-danger" href="{% url 'delete_service' service.id %}">Yes, delete</a>
                      </div>
                    </div>
                  </div>
                </div>
              </td>
          </tr>
      {% endfor %}
    </tbody>
  </table>

{% endblock content %}

{% block javascripts %}

<script>

  // Alert when trying to delete a product
  const myModal = document.getElementById('myModal')
  const myInput = document.getElementById('myInput')

  myModal.addEventListener('shown.bs.modal', () => {
    myInput.focus()
  })

</script>

{% endblock javascripts %}

When I click the trash button the dialog opens as expected, but it seems that the ID is not taken corretyly. The modal body always contains the name of the first element in the database and the URL also only points to the first ID in the database.

For example, I click on the trash in line 9, but the URL contains 7. I noticed that after clicking, the first line (ID 7) is grayed out. Screenshot


Solution

  • The issue you are having that you are creating n dialogues for n services and all have the same id, so normally when it wants to open it the first dialogue opens.

    There are 2 solutions for this, the first is easiest but not good in performance and the other is elegant and much easier to maintain.

    First solution Change the dialog id for each dialog like

    <div class="modal fade" id="DeleteDialogueModal_{{service.id}}" tabindex="-1" aria-labelledby="modal-title" aria-hidden="true">
    

    and change the trash button to

    <button type="button" class="btn btn-danger btn-sm" data-bs-toggle="modal" data-bs-target="#DeleteDialogueModal_{{service.id}}">
        <i class="bi bi-trash"></i>
    </button>
    

    This way you will have n dialogues each with a separate ID and will be toggled with a respective button.

    Second Solution The second solution is to have a single dialogue and you change its content by Javascript based on the clicked button something like

     function confirm_delete(id,name)
        {
          $("#model-title").html("Delete " + name);
          $("#model-body").html("Are you sure you want to delete " + name + "?");
          $("#modal").modal();
        }
    

    Also, update the anchor element with service id.

    finally in your template on the delete button

     <button type="button" class="btn btn-danger btn-sm" data-bs-toggle="modal" onclick = "confirm_delete({{service.id}},'{{service.name}}')">
                  <i class="bi bi-trash"></i>
                </button>