Reputation: 309
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
Reputation: 16666
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.
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
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