Refresh content in a for loop using jquery in Django - javascript

I am creating a website that allows users to search for a list of papers. Once a list of papers is returned, the user can click "like" or "dislike" to one or more papers. The like count should dynamically update as the user click the like button.
I am using jquery to handle the dynamic update of the like count. However, I am not sure how to tell the success function in the ajax WHICH id to update. The reason is that the id is generated on the fly, and it is determined by which papers are returned as search results to the user.
So far, I have the following in the template:
{% for result in results %}
<li >
{{ result.title}},
<span class="like_span fa fa-thumbs-up"></span>
<strong id="like_count_{{ result.pk }}">{{result.likes}} </strong>
</li>
{% endfor %}
As you can see, i specify the id of the part where I want the dynamic update to happen as "like_count_{{ result.pk }}". I am not sure if this is the best way to go about it.
The jquery part looks like this:
<script>
$(document).ready(function(){
$(".like_button").click(function(){
$.ajax({
type: "GET",
data: {'pk': $(this).data('pid'),
'liked': $("span").hasClass('fa fa-thumbs-up') },
url: "{% url 'search:paperpreference' %}",
success: function(response) {
var pk = $(this).data('pid');
$(?????).html(response.likes )
},
error: function(response, error) {
alert(error);
}
});
});
});
</script>
Simply put, I don't know how can i specify the ????? part such that when success, the new like count is only updated to that specific paper, not the first paper in the loop.
The views.py has the following so far:
def paperpreference(request):
# if request.method == "GET":
pid = request.GET['pk']
paper = Paper.objects.get(pk=pid)
likes = paper.likes + 1
paper.likes = likes
paper.save()
data = {'likes': paper.likes}
return JsonResponse(data)
I am new to Jquery, any help would be much appreciated!

Thanks to suggestions by #dirkgroten, the like count can now be dynamically updated by the following jquery function. The trick is to move the pk declaration to before the ajax.
<script>
$(document).ready(function(){
$(".like_button").click(function(){
var pk = $(this).data('pid')
$.ajax({
type: "GET",
data: {'pk': pk,
'liked': $("span").hasClass('fa fa-thumbs-up') },
url: "{% url 'search:paperpreference' %}",
success: function(response) {
$("#like_count_"+ pk).html(response.likes )
},
error: function(response, error) {
alert(error);
}
});
});
});
</script>

another option is return the id from the server.
def paperpreference(request):
# if request.method == "GET":
pid = request.GET['pk']
paper = Paper.objects.get(pk=pid)
likes = paper.likes + 1
paper.likes = likes
paper.save()
data = {'likes': paper.likes,'pid':pid}
return JsonResponse(data)
<script>
$(document).ready(function(){
$(".like_button").click(function(){
var pk = $(this).data('pid')
$.ajax({
type: "GET",
data: {'pk': pk,
'liked': $("span").hasClass('fa fa-thumbs-up') },
url: "{% url 'search:paperpreference' %}",
success: function(response) {
$("#like_count_"+ response.pid).html(response.likes )
},
error: function(response, error) {
alert(error);
}
});
});
});
</script>

Related

AJAX Data not Posting to View in Django

I've implemented a basic checkout wherein a user may select a shipping address from a list of addresses via the 'address' class. It works on the server side, but I would like to use AJAX to avoid having the page refresh with each selection. The code is not posting any data, however. What am I doing wrong?
views.py
def pick_address(request):
if request.method == 'POST':
checkout = Checkout.objects.get(pk=request.POST.get('checkout'))
checkout.shipping_address = ShippingAddress.objects.get(pk=request.POST.get('address'))
checkout.save()
return HttpResponse('success')
pick_address.js
<script>
$('.address').click(function () {
$.ajax({
type: 'POST',
url: '{% url 'pick-address' %}',
dataType:'json',
data: {
checkout: {{ checkout.pk }},
address: {{ address.pk }},
csrfmiddlewaretoken: '{{ csrf_token }}'
},
success: function (data) {
if (data['success']) {
alert('success!');
}
}
});
});
</script>
In views.py
def pick_address(request):
if request.method == 'POST':
checkout = Checkout.objects.get(pk=request.POST.get('checkout'))
checkout.shipping_address = ShippingAddress.objects.get(pk=request.POST.get('address'))
checkout.save()
ctx={'success':True}
return HttpResponse(json.dumps(ctx),content_type='application/json')
in pick_address.js
success: function (data) {
if (data.success) {
alert('success!');
}
}
I was using the slim version of jQuery, which does not support AJAX. The code was otherwise (mostly) correct.

Django/Ajax/Jquery running two ajax requests in the same event.

I think I'm really close to getting this working but I need some help with the Jquery as everything works as intended on the second click and beyond. It just doesn't work on the first click.
I'm basically trying to replicate the youtube like and dislike buttons. So you click the thumbs up, it shows +1 and if you click it again it subtracts one. All that logic works until I get into the AJAX and Jquery portion.
I have one ajax request that adds the user to the "liked" ManyToManyField. Then I have one apiview that I'm connecting to just produce the upvote and downvote count, then displaying that into the template.
This all works, but again the first click produces the correct result in the console. The second click produces the "opposite" result in the template and correct result in the console. Then of course if I reload every time I click "up" it works as intended but i'm trying to prevent reloading.
template - Jquery/Ajax
$(".upvote-btn").click(function(e){
e.preventDefault()
var this_ = $(this)
var upvoteToggleUrl = this_.attr("data-href")
var voteCountAPIUrl = "{% url 'streams:vote-count' streampost.pk %}";
$.ajax({
url: upvoteToggleUrl,
method: 'GET',
data: {},
success: function(data){
}, error: function(error){
console.log(error)
console.log("error")
}
})
$.ajax({
url: voteCountAPIUrl,
method: 'GET',
data: {},
success: function(data){
console.log(data.upvotes)
console.log(data.downvotes)
$('.upvote-count').text(data.upvotes);
}, error: function(error){
console.log(error)
console.log("error")
}
})
})
HTML
<p>
Upvotes
<div class="upvote-count" data-href="{% url 'streams:vote-count' streampost.pk %}">
{{ streampost.upvotes.count }}
</div>
<a class="upvote-btn" data-href='{{ streampost.get_api_upvote_url }}'
href='{{ streampost.get_upvote_url }}'>Up</a>
Downvotes {{ streampost.downvotes.count }}
</p>
It seems to me like you want the upvote request to complete first before you retrieve the upvote count. To do that, you need to make the second request in the callback of the first:
$(".upvote-btn").click(function(e){
e.preventDefault()
var this_ = $(this)
var upvoteToggleUrl = this_.attr("data-href")
var voteCountAPIUrl = "{% url 'streams:vote-count' streampost.pk %}";
$.ajax({
url: upvoteToggleUrl,
method: 'GET',
data: {},
success: function(data){
$.ajax({
url: voteCountAPIUrl,
method: 'GET',
data: {},
success: function(data){
console.log(data.upvotes)
console.log(data.downvotes)
$('.upvote-count').text(data.upvotes);
}, error: function(error){
console.log(error)
console.log("error")
}
})
}, error: function(error){
console.log(error)
console.log("error")
}
})
})

JQuery tokenfield with django not working

I am trying to incorporate a search field in a django registration form. I would like to use a bootstrap tokenfield that searches a django model for possible matches to the search string. I've been struggling with this for a couple of days now. Here is my code below.
<div class="form-inline" id="keywords_div">
{% csrf_token %}
<input type="text" name="search_text" class="form-control" id="tokenfield" placeholder="Enter keyword" style="width: 50%" />
<button type="button" id="addKeyword-btn" class="btn btn-primary">Add</button>
My JQuery code.
$(function(){
//auto complete ajax code.
$('#tokenfield').tokenfield({
autocomplete: {
//source:['red','blue','green','yellow','violet','brown','purple','black','white'],
delay: 100
},
showAutocompleteOnFocus: true,
}).keyup(function(){
alert('key pressed');
$.ajax({
url: "/user_account/auto_complete_search/",
type: 'POST',
data: {
'search_text': $('#tokenfield').val(),
'csrfmiddlewaretoken': $("input[name=csrfmiddlewaretoken]").val()
},
success: function(data){
console.log(data)
},
dataType: 'text'
});
});
});
});
Django View
#This is the function that handle the auto complete search functionality.
def autocomplete_search_view(request):
if request.method == 'POST':
search_text = request.POST['search_text']
else:
search_text = ''
keywords = Keywords.objects.filter(keyword__icontains=search_text)
#data = serializers.serialize('json', keywords, fields=('keyword'))
return HttpResponse('Query completed', content_type='application/text')
user_account/urls.py
url(r'^auto_complete_search/$', autocomplete_search_view, name='autocomplete_search'),
The error from the browser.
What am I doing wrong here?
After a very long time of searching for the answer, I eventually got it right. see the code below. I'm trying to figure out how to make the dropdown menu scrollable but code below does exactly what I wanted.
$('#tokenfield').tokenfield({
autocomplete: {
source: function(request, response){
if(request.term.length >= 5){
$.ajax({
url: "/user_account/auto_complete_search/",
type: 'POST',
data: {
'search_text': request.term,
'csrfmiddlewaretoken': $("input[name=csrfmiddlewaretoken]").val()
},
success: function(data){
if(data != ""){
var dataArr = [];
$.each(data, function(i, jsonObj){
dataArr[i] = jsonObj.fields.keyword;
});
response(dataArr);
}
else{
response([]);
}
},
dataType: 'json'
});
}
else{
response([]);
}
},
delay: 300,
},
showAutocompleteOnFocus: true
});
Django view.
#This is the function that handle the auto complete search functionality.
def autocomplete_search_view(request):
if request.method == 'POST':
search_text = request.POST['search_text']
else:
search_text = ''
return HttpResponse([{}], content_type='application/json')
keywords = Keywords.objects.filter(keyword__icontains=search_text)
data = serializers.serialize('json', keywords, fields=('keyword'))
return HttpResponse(data, content_type='application/json')
The HTML is still the same. Hope this helps somebody in the future.

Show succes message from ajax

I have a question, So I create a sistem that update in database a row when onChange a select box. All goes well, but I want to drop a succes message if update was with succes.
My view :
<form action="" id="updateStatus" method="post">
<select id="statusSelect"
name="{{ gift.id_instant_gagnant }}"
class="form-control"
onChange="updateCadeauStatus({{ gift.id_instant_gagnant }})">
{% for key,statut in form_logistique.statut.choices %}
<option value="{{ key }}"
{% if gift.etat == key %}selected="selected"{% endif %}>
{{ statut }}
</option>
{% endfor %}
</select>
</form>
<script>
function updateCadeauStatus(id) {
var id = id;
var selectedName = $("#statusSelect option:selected").val();
var url_deploy = 'http:localhost/updateStatus'
console.log(id);
console.log(selectedName);
$.ajax({
url: url_deploy,
type: "POST",
async: true,
data: { id_cadeau:id, id_status:selectedName}
});
}
</script>
The controller :
public function updateStatus(){
$iGiftId = $_POST['id_cadeau'];
$iNewStatus = $_POST['id_status'];
$bUpdate = $this->updateStatusByGiftId($iGiftId, $iNewStatus);
return $this->render('logistique.twig');
}
The model :
public static function updateStatusByGiftId($iGiftId, $iStatusId){
$request = sprintf( ' UPDATE `%s` set etat = %d WHERE id = %d ', $table, $iStatusId, $iGiftId);
return Mysqli::query($request, $database);
}
So everything goes well but I want to drop a message after every update, too be displayed in the view. Please help me!!! Thx in advance, sorry for my english.
$.ajax({
url: url_deploy,
type: "POST",
async: true,
data: { id_cadeau:id, id_status:selectedName},
success : function(data){
console.log('success');
},
error: function(){
console.log('error');
}
});
You can drop the response of the check file on ajax.
$.ajax({
url: url,
type: "POST",
...
success: function(response){
window.alert(response);
}
})
To be more specific, if you want to give a message only when you successfully changed the row. Modify the validation file (url:) and print a messagge only when you had success..
There are other ways to do that..
You can print a "message id" and get it with the script and drop a message:
$.ajax({
url: url,
type: "POST",
...
success: function(response){
if(response == '1'){
window.alert('Successfully changed!!');
}else if(response == '0'){
$("#foo").html("Error, not changed :(");
}else{
------ something else ------
}
}
})
Hope I could help !
Im not sure if you have your response in another file.
Cuz your response now is in the var data in the line with the code:
}).done(function(data){
$.ajax({
url: url_deploy,
type: "POST",
async: true,
data: { id_cadeau:id, id_status:selectedName}
}).done(function(data){
$("[SuccesDiv]").append("[Succes MSG]");
});
The text between the [ - ] is ment to put there your own element or data.
[EDIT]
I did'nt look good...
You are not looking when it is changed.
To do that, do this:
$("select").on("change", function(){
$.ajax({
url: url_deploy,
type: "POST",
async: true,
data: { id_cadeau:id, id_status:selectedName}
}).done(function(data){
$("[SuccesDiv]").append("[Succes MSG]");
});
});

Django url rewrites and passing a parameter from Javascript

As a bit of a followup question to my previous , I need to pass a parameter to a view. This parameter is not known until the JS executes.
In my URLConf:
url(r'^person/device/program/oneday/(?P<meter_id>\d+)/(?P<day_of_the_week>\w+)/$',
therm_control.Get_One_Day_Of_Current_Thermostat_Schedule.as_view(),
name="one-day-url"),
I can pass it this URL and it works great! ( thanks to you guys).
http://127.0.0.1:8000/personview/person/device/program/oneday/149778/Monday/
In My template I have this:
var one_day_url = "{% url personview:one-day-url meter_id=meter_id day_of_the_week='Monday' %}";
In my javascript:
$.ajax({
type: 'GET',
url: one_day_url ,
dataType: "json",
timeout: 30000,
beforeSend: beforeSendCallback,
success: successCallback,
error: errorCallback,
complete: completeCallback
});
When this triggers it works fine except I dont necessarily want Monday all the time.
If I change the javascript to this:
var one_day_url = "{% url personview:one-day-url meter_id=meter_id %}";
and then
$.ajax({
type: 'GET',
url: one_day_url + '/Monday/',
dataType: "json",
timeout: 30000,
beforeSend: beforeSendCallback,
success: successCallback,
error: errorCallback,
complete: completeCallback
});
I get the Caught NoReverseMatch while rendering error. I assume because the URLconf still wants to rewrite to include the ?P\w+) .
I seems like if I change the URL conf that breaks the abailty to find the view , and if I do what I do above it gives me the NoREverseMatch error.
Any guidance would be appreciated.
I usually do something along the lines of
var one_day_url = "{% url personview:one-day-url meter_id=meter_id day_of_the_week='REPLACE_ME' %}";
// ...
url: one_day_url.replace('REPLACE_ME', 'Sunday')
you may want to use this kind of project which is meant to answer to this precise question...
notice: it may help hacker to map the website:
https://github.com/Dimitri-Gnidash/django-js-utils
When I don't use this project I put a default value in the url and replace it by correct value.
so use a complete reverse then:
url: one_day_url.replace('/Monday/','/Caturday/')
and even if you replace monday by monday it will works...
note: this ugly haks will fail if your default value is already sooner in the url so use it consequently.
Why not just pass them in as part of the request data. You can use the jQuery get function and pass them in as paramaters.
$.get("{%url personview%}", {'meter_id':"meter_id", "day_of_the_week":"monday" ...}, function(){do stuff when info is returned});
Then in your view you can do:
meter = request.GET['meter_id']
This will allow you to use it in your view.
I had a similar question. I wanted to open a URL when someone clicked a button. For what it's worth, here is how I handled this situation.
Define the URL as an attribute:
{% for article in articles %}
<button data-article-url="{% url view_article article.id %}">
Read Article #{{ article.id }}
</button>
{% endfor %}
Using jQuery, read the attribute and carry on:
var article_url = $(this).attr("data-article-url");
$.ajax({
url: article_url,
...
});
You could use tokens in your url and pass it as a variable to your module:
<script src="{{ STATIC_URL }}js/my-module.js"></script>
<script>
$(function(){
MyModule.init(
"{% url personview:one-day-url meter_id='0000' day_of_the_week='{day}' %}"
);
});
</script>
// js/my-module.js
var MyModule = {
init: function(one_day_url) {
var id = 1, day = 'Saturday';
this._one_day_url = one_day_url;
console.log(this.one_day_url(id, day));
$.ajax({
type: 'GET',
url: this.one_day_url(id, day),
dataType: "json",
timeout: 30000,
beforeSend: beforeSendCallback,
success: successCallback,
error: errorCallback,
complete: completeCallback
});
},
one_day_url: function(meter_id, day) {
return this._one_day_url.replace('0000', meter_id).replace('{day}', day);
}
};
Notice that token should match the regex type to resolve successfully (I can't use {meter_id} because it's defined with \d+).
I'm a little bit unsatisfied with this solution and I ended by writing my own application to handle javascript with django: django.js. With this application, I can do:
{% load js %}
{% django_js %}
{% js "js/my-module.js" %}
// js/my-module.js
var MyModule = {
init: function() {
var id = 1, day = 'Saturday';
console.log(
Django.url('personview:one-day-url', id, day),
Django.url('personview:one-day-url', [id, day]),
Django.url('personview:one-day-url', {
meter_id: id,
day_of_week: day
})
);
$.ajax({
type: 'GET',
url: Django.url('personview:one-day-url', id, day),
dataType: "json",
timeout: 30000,
beforeSend: beforeSendCallback,
success: successCallback,
error: errorCallback,
complete: completeCallback
});
}
};
$(function(){
MyModule.init();
});

Categories

Resources