Reputation: 237
I'm having trouble linking this together. I'm trying to build a small leaderboard app. basically users just vote things up or down. I've got everything working except I want the leaderboard itself to update in real time or close to it without having to refresh the page.
I know I need a way to basically get an updated list based on the votes and sort them by highest votes. So I used Django rest to build an API endpoint that produces a response in the order that I want.
The next step would be to use AJAX to get that response. I just can't figure out how to get my new list in place of the old list. I started to write my ajax request and found that I was rewriting my whole HTML template, that can't be right. Could someone provide me some direction? I might just be overthinking this. Maybe I just need an ajax request that refreshes the whole page.
I think I might be having trouble grasping "updating" the HTML classes. I don't need to append or prepend just reorder the given elements.
Or I'm totally overthinking this whole thing so another perspective may be what I need.
View
def streams_list(request):
streams_ranked = StreamPost.objects.annotate(q_count=Count('upvotes')) \
.order_by('-q_count')
context = {
'streams_ranked' : streams_ranked,
'form': StreamPostForm()
}
return render(request, 'streams/index.html', context)
Index.html If I manually refresh this page, it works perfectly.
<div id='stream-list'>
{% include 'streams/leaderboard_list.html' %}
</div>
leaderboard_list.html
<div class="row">
<div class="col-md-12">
{% for stream in streams_ranked %}
<div class="post-list-box">
<h1 class="stream-title">{{ stream.title }}</h1>
<h4 class="stream-description">{{ stream.description }}</h4>
<a class="btn btn-warning " href="{% url 'streams:detail' pk=stream.pk %}">
View Stream</a>
<p>comment area</p>
<div class="row">
<div class="col-sm-3 voting-buttons">
<a class="upvote-btn" data-href='{{ stream.get_api_upvote_url }}'
href='{{ stream.get_upvote_url }}'><i class="fas fa-thumbs-up"></i></a>
<span class="upvote-count" data-href="{% url 'streams:vote-count' pk=stream.pk %}">
{{ stream.upvotes.count }}
</span>
<a class="downvote-btn" data-href="{{ stream.get_api_downvote_url }}"
href='{{ stream.get_downvote_url }}'><i class="fas fa-thumbs-down"></i></a>
<span class="downvote-count" data-href="{% url 'streams:vote-count' pk=stream.pk %}">
{{ stream.downvotes.count }}
</span>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
AJAX/JS
$('#stream-list').click(function() {
$.ajax({
url: '/',
method: 'GET',
data: {},
success: function(data){
$('#stream-list').html(data);
}, error: function(error){
console.log(error)
console.log("error")
}
})
});
Update Final Working Code
Templates index
<div id='stream-list'>
<tbody class='table_body'>
{% include 'streams/leaderboard_list.html' %}
</tbody>
</div>
leaderboard_list.html
<div class="row">
<div class="col-md-12">
{% for stream in streams_ranked %}
<div class="post-list-box">
<h1 id="stream-title">{{ stream.title }}</h1>
<h4 id="stream-description">{{ stream.description }}</h4>
<a class="btn btn-warning" href="{% url 'streams:detail' pk=stream.pk %}">
View Stream</a>
<p>comment area</p>
<div class="row">
<div class="col-sm-3 voting-buttons">
<a class="upvote-btn" data-api-upvote='{{ stream.get_api_upvote_url }}'
href='{{ stream.get_upvote_url }}'><i class="fas fa-thumbs-up"></i></a>
<span id="upvote-count" data-upvotes="{% url 'streams:vote-count' pk=stream.pk %}">
{{ stream.upvotes.count }}
</span>
<a class="downvote-btn" data-api-downvote="{{ stream.get_api_downvote_url }}"
href='{{ stream.get_downvote_url }}'><i class="fas fa-thumbs-down"></i></a>
<span id="downvote-count" data-downvotes="{% url 'streams:vote-count' pk=stream.pk %}">
{{ stream.downvotes.count }}
</span>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
JS to control displaying the updated list
var refreshStream = function(){
var getNewDataUrl = '/streams/'
$.ajax({
url: getNewDataUrl,
method: 'GET',
data: {},
success: function(data){
$('#stream-list').replaceWith($('#stream-list',data));
},
error: function(error){
console.log(error);
console.log("error");
}
});
}
var total_seconds = 5; // refresh every 5 seconds
setInterval(function(){
refreshStream();
},total_seconds * 1000);
View
def streams_list(request):
streams_ranked = StreamPost.objects.annotate(q_count=Count('upvotes')) \
.order_by('-q_count')
context = {
'streams_ranked' : streams_ranked,
'form': StreamPostForm()
}
return render(request, 'streams/index.html', context)
Upvotes: 3
Views: 4357
Reputation: 8525
Use setInterval
to refresh the concerned page of HTML every specific second.
var refreshStream = function(){
$.ajax({
url: '/url_to_view/',
method: 'GET',
data: {},
success: function(data){
$('#stream-list').replaceWith($('#stream-list',data));
},
error: function(error){
console.log(error);
console.log("error");
}
});
}
var total_seconds = 5; // refresh every 5 seconds
setInterval(function(){
refreshStream();
},total_second * 1000);
Keep your view the way it was:
def streams_list(request):
streams_ranked = StreamPost.objects.annotate(q_count=Count('upvotes')) \
.order_by('-q_count')
context = {
'streams_ranked' : streams_ranked,
'form': StreamPostForm()
}
return render(request, 'streams/leaderboard_list.html', context)
Upvotes: 4