thevengefulco
thevengefulco

Reputation: 309

(Django) Ajax - Multiple Objects

I really need some help with Ajax and Django! I'm trying to iterate over all Item objects so that each one has an individual form that allows the user to favorite the item with an ajax button. Here is my form:

<div class="row">
{% for item in items%}
  <div class="col-sm-6 col-md-4">
    <div class="thumbnail">
        {% if item.photo %}
      <img src="{{ MEDIA_URL }}{{item.photo.url}}">
        {% endif %}
      <div class="caption">
        <h3>{{item.name}}</h3>
        <p>{{item.description}}</p>
        <h3>Price: {{item.price}}</h3>
        <h3>Rating: {{item.rating}}</h3>
        <p>
            <form id="add_favorite_form">
                {% csrf_token %}
                <button id='fav' class='btn btn-primary' type="submit" data-itemid="{{item.id}}" value="Favorite">
                Favorite
                <span class="glyphicon glyphicon-thumbs-up"</span></a>
            </form>
        </p>
      </div>
    </div>
  </div>
{% endfor %}
</div>

Here is the Ajax:

    <script type="text/javascript">
        $(document).on('submit', '#add_favorite_form',function(e){
            e.preventDefault();
            var $fav = $('#fav');
            $.ajax({
                type: "POST",
                url: "/items/favorites/",
                data: {
                    id: $($fav).attr('data-itemid'),
                    csrfmiddlewaretoken:$("input[name=csrfmiddlewaretoken]").val()
                },
                success: function(){
                    alert("button works but is broken. Only the first Item instance is added to favorites")

                }
            });
        });
    </script>

And finally, my views:

def favorite_item(request):
    favorites, created = Favorite.objects.get_or_create(user=request.user)
    if request.method == "POST":
        id = request.POST['id']
        item = Item.objects.get(id=id)
        print item
        favorites.items.add(item)
        favorites.save()
    return HttpResponse(' ')

As you can see, the button uses {{item.id}} as the data-* attribute, so I assumed that this would pass the value of each individual item.id to the variable var $fav = $('#fav'); in the ajax script. However, only the first item.id ever seems to be passed because that is the only Item object that is added to favorites.

How can I solve this issue? Thanks for any help.

Upvotes: 0

Views: 1036

Answers (2)

Risadinha
Risadinha

Reputation: 16666

  1. You are creating an HTML element with id fav inside a loop. This will result in incorrect HTML with several elements having the same id, if the loop has more than one iteration.

  2. You lookup $('#fav') instead of the element that triggered the submit event.

=> Remove id='fav' from your markup. (You can add an ID like id='fav-{{item.id}} if you want but it is not necessary.

=> Change your JS:

<script type="text/javascript">
    var csrftoken = $("input[name=csrfmiddlewaretoken]").val();
    $(document).on('submit', '#add_favorite_form',function(e){
        e.preventDefault();
        var itemId= $(e.target).data('itemid');  // jquery +1.4.3 or attr()
        $.ajax({
            type: "POST",
            url: "/items/favorites/",
            data: {
                id: itemId,
                csrfmiddlewaretoken: csrftoken
            },
            success: function(){
                alert("Added favorite " + itemId);
            }
        });
    });
</script>

EDIT:

A simpler way to do it, is to use the form as such and just submit it via AJAX.

<form id="add_favorite_{{ item.id }}" class="add_favorite_form" method="POST" action="{% url 'add-favorite' %}">
    {% csrf_token %}
    <input type="hidden" name="id" value="{{ item.id }}" />
    <button id='fav' class='btn btn-primary' type="submit" value="Favorite">
        Favorite
    <span class="glyphicon glyphicon-thumbs-up"</span></a>
</form>

JS:

<script type="text/javascript">
    var csrftoken = $("input[name=csrfmiddlewaretoken]").val();
    $(document).on('submit', '.add_favorite_form',function(e) {
        e.preventDefault();
        e.stopPropagation();
        var $form = $(this);
        var url = $form.attr( "action" );
        var thisId = $form.attr( "id" );
        $.post(url, $form.serialize())
            .done(function(data) {
                alert("Added favorite " + thisId);
            });
    });
</script>

Upvotes: 1

Sayse
Sayse

Reputation: 43300

You have a couple things wrong, but the one that is causing you the issue is that $('#fav') will only ever find the first element on the page with that id.

You'll find it hard to adjust your current javascript since it relies on the page submission. You could change it around to just have the button use an onclick event.

You will just need to include the CSRF token still but there are lots of resources about how to do that.

<button onclick="favourite({{item.id}})" class='btn btn-primary' value="Favorite">

function favourite(id){
    // Use the id passed to the method
}

Upvotes: 0

Related Questions