Onilol
Onilol

Reputation: 1339

django url tag not being called

I have a template structure similar to this:

    #X_List.html
    <div class="row">
        {% include './X_List_Table.html' %}
    </div>
    <div id="confirm" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="testmodal" aria-hidden="true">
    <div class="modal-dialog modal-sm" role="document">
        <div class="modal-content"></div>
    </div>
</div>

    #X_List_Table.html
    <table>
      <thead>
        <tr>
          <th>Desc</th>
          <th>Activate</th>
        </tr>
      </thead>
      <tbody>
        {% for item in x_list %}
          <tr>
            <td>{{ item.id }}</td>
            <td><a data-toggle="modal" href="{% url 'x:x_quantity' item.id %}" data-target="#confirm">Click me</a></td>
          </tr>
        {% endfor %}    
      </tbody>
    </table>

My view is defined as:

#views.py
def x_quantity(request, id):
  return render(request, 'modal.html', {'quantity': X.objects.filter(pk=id).count()}

and the modal.html:

<div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
    <h3>Attention</h3>
</div>
<div class="modal-body">
    <p>The number of elements is {{ quantity }}</p>
</div>
<div class="modal-footer"></div>

The problem is:

Supposing that I have 2 elements in the table, their urls would be:

Consider that for these elements:

When I click on the link, it should run the view, get the quantity based on the id of the element, return it as a context variable to the modal so it can be displayed.

The problem is:

When I click on a link, the view is being called with the id of the element, which can be confirmed by looking at the server shell [06/Apr/2018 17:00:23] "GET /x/x_quantity/1 HTTP/1.1" 200 898.

If I click on the other element, THE VIEW IS NOT BEING CALLED, there is no request going out.

What I intend to do is to display a modal with the quantity of the element clicked.

Is this a confusion on my part regarding how the {% url 'app:app_view' var %} should behave on a href or I'm not supposed to do this and should, instead, use AJAX?

Perhaps this is related with "refreshing" context variables as well?

Upvotes: 6

Views: 221

Answers (2)

Daniel Hepper
Daniel Hepper

Reputation: 29967

The explanation for the behavior you are seeing can be found in the Bootstap documentation:

If a remote URL is provided, content will be loaded one time via jQuery's load method and injected into the .modal-content div. If you're using the data-api, you may alternatively use the href attribute to specify the remote source. An example of this is shown below:

If you want to use the same modal to load different content, you have to use Ajax.

A (quite ugly) workaround would be to render a modal for each item in x_list. Just be aware that the value doesn't get updated if you open the same modal twice.

Upvotes: 1

Kres
Kres

Reputation: 154

Let me first clarify that before this example I have never used Bootstrap. I found your question interesting so I played a little bit with Bootstrap CDN. Also I do not use a lot of Javascript so everyone feel free to correct any bad practices.

I think what you want is doable using AJAX so here is my solution:

I changed a link to a button because all the modal examples had buttons not links :)

#X_List.html
<table>
  <thead>
    <tr>
      <th>Desc</th>
      <th>Activate</th>
    </tr>
  </thead>
  <tbody>
    {% for x in x_list %}
      <tr>
        <td>{{ x.id }}</td>
        <td><button id="{{ x.id }}" type="button" class="btn btn-info modal-btn">Click me</button></td>
      </tr>
    {% endfor %}
  </tbody>
</table>

<!-- Modal -->
<div id="myModal" class="modal fade" role="dialog">
  <div class="modal-dialog">
    <!-- Modal content-->
    <div class="modal-content">
      <div class="modal-header">
        <h4 class="modal-title"></h4>
        <button type="button" class="close" data-dismiss="modal">&times;      </button>
      </div>
      <div class="modal-body"></div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
      </div>
    </div>
  </div>
</div>

Javascript (you will need js-cookie - I used CDN) passes the id to the server side and then shows received quantity at the end in a modal.

$(document).ready(function() {

    $(".modal-btn").click(function(event) {
        var x_id = $(event.target).attr('id');

        $.ajax({
            url : "/ajaxquantity/",
            type : "POST",
            dataType: "json",
            data : {
                x_id : x_id,
                csrfmiddlewaretoken: Cookies.get('csrftoken')
            },
            success : function(json) {
                var quantity = json.quantity;
                $(".modal-title").text('Id: ' + x_id);
                $(".modal-body").text('Quantity: ' + quantity);
                $('#myModal').modal('show');
            },
            error : function(xhr,errmsg,err) {
                alert(xhr.status + ": " + xhr.responseText);
            }
        });
        return false;
    });
});

Then you need to add this line into urlpatterns list:

url(r'^ajaxquantity/$', views.ajaxquantity, name='ajaxquantity')

And finally the server side. I do not know how your model looks like so here I used your query from the question.

# views.py
def ajaxquantity(request):
    if "x_id" in request.POST:
        response_dict = {}
        x_id = request.POST.get('x_id')
        quantity = X.objects.filter(pk=id).count()
        response_dict.update({'quantity': quantity})
        return JsonResponse(response_dict)

    else:
        return render(request, 'yourapp/X_List.html')

So this worked for me (with a little different QuerySet). It is very important that Jquery is only defined once!!!

Keep in mind that this is a minimal working example.

Upvotes: 0

Related Questions