Upvote / Downvote Function On Topic Level
-
I did some search here and found this thread:
Topic voting like adult swim boards had
Hey guys! Actually, when they requested that modification from us, we made the requisite changes in NodeBB core, and their theme contained the actual customi...
NodeBB Community (community.nodebb.org)
I get the gist of it, but how do I get the post total of the first post? That way, when users upvote / downvote the topic, it upvotes / downvotes the first post?
Thanks!
-
To make those work you need to code them as well.
When the post is voted either up or down you need to change the value in the DOM.
As for the
upvoted
class you need to update the topic_list.tpl template and add the class if the topic is already voted. Since that data isn't available in core you need to use a hook likefilter:topics.get
and add aahasUpvoted
field to each topic. -
The way it currently works is when someone upvotes the first post of the topic, the topic also gets one upvote. If you look at the /recent page it shows vote counts for topics this vote count comes from the vote count of the first post of the topic.
-
@baris said in Upvote / Downvote Function On Topic Level:
The way it currently works is when someone upvotes the first post of the topic, the topic also gets one upvote. If you look at the /recent page it shows vote counts for topics this vote count comes from the vote count of the first post of the topic.
Gotcha! Getting the total votes is not a problem then.
Is there a way to upvote/downvote the first post in the topic from the topics level?
I'm trying to make these upvote / downvote icons functional here:
-
Yes it is possible, once the upvote is clicked you need to make the same upvote api call to the backend. You can get the post id of the first post from the data on the /recent page. It is stored in
ajaxify.data.topics[0].mainPid
Easiest approach would be to put the mainPid value in the template in a data tagdata-mainPid="{topics.mainPid}"
in the topic_list.tpl template and then you can read it when the upvote button is clicked.You will probably need to return the current vote status as well to show if the user has already upvoted/downvoted the main post. You can probably add that extra data in
filter:topics.get
on the server side and render the correct html in your custom topics_list.tpl.The api call for votes is here https://github.com/NodeBB/NodeBB/blob/master/public/src/client/topic/votes.js#L60-L64
-
@baris sorry, still kinda new to this. Correct me if I'm wrong, but I think votes.js is looking for the closest data-pid and not data-mainPid in the template right? Here's my current code and I'm sure I'm missing a lot of stuff here:
<div class="col-md-1 hidden-xs hidden-sm total-post-votes" data-pid="{topics.mainPid}"> <a component="post/upvote" href="#" class="<!-- IF posts.upvoted -->upvoted<!-- ENDIF posts.upvoted -->"> <i class="fa fa-chevron-up"></i> </a> <div title="{topics.votes}">{topics.votes}</div> <!-- IF !downvote:disabled --> <a component="post/downvote" href="#" class="<!-- IF posts.downvoted -->downvoted<!-- ENDIF posts.downvoted -->"> <i class="fa fa-chevron-down"></i> </a> <!-- ENDIF !downvote:disabled --> </div>
In order to read the closest data-pid on upvote/downvote, do I need to create a custom js function for that?
-
@Teemberland Yes since what you are doing isn't supported by core, you need some custom JS that runs when the user clicks the upvote/downvote buttons on the topic list. In that custom JS code you need to get the closest pid(which is the mainPid of the topic) and then make the API call.
-
@baris for custom JS. Where is the best place to add it?
-
@baris I think I'm close. I just need to know how I can pass in 'delta' in my custom js (I believe delta is required in upvote/downvote)
https://github.com/NodeBB/NodeBB/blob/master/public/src/client/topic/votes.js#:~:text=api[method](%60/posts/%24%7Bpid%7D,%7D
var pid = $(this).closest('.total-post-votes').find('.tl-upvote').attr('data-pid'); var method = $(this).closest('.total-post-votes').find('.tl-upvote').hasClass('upvoted') ? 'put' : 'del'; api[method]('/v3/' + '/posts/' + pid + '/vote').then(() => { delta: delta, });
Let me know if this is incorrect though. I'm not sure if I should call toggleVotes from the client side.
-
This post is deleted!
-
@baris the following code is working, however, the upvoted class is not persisting when I navigate to another page, like for instance when I click the topic and go back to topic list, the class disappears.
Also, when I do upvote, I can see the first post being upvoted, but the vote number is not changing onclick. The page has to reload to see the vote number.
function topicVotes() { $(window).on('action:ajaxify.end', function () { require(['api'], function (api) { $('.tl-upvote').closest('.total-post-votes').find('.tl-upvote').on('click', function () { var pid = $(this).attr('data-pid'); var method = $(this).hasClass('upvoted') ? 'put' : 'del'; api[method](`/posts/${pid}/vote`, { delta: 1, }).then(() => console.log('voted')); $(this).toggleClass('upvoted'); }); }); }); }
I apologize in advance, maybe I'm not understanding the client-side hooks just yet.
-
To make those work you need to code them as well.
When the post is voted either up or down you need to change the value in the DOM.
As for the
upvoted
class you need to update the topic_list.tpl template and add the class if the topic is already voted. Since that data isn't available in core you need to use a hook likefilter:topics.get
and add aahasUpvoted
field to each topic. -
If you want it to be only visible on a certain category, you will need to add a conditional in the topic_list.tpl. For example
{{{ if (template.category && (cid == "3")) }}} Display only on /category page and category id is 3 {{{ end }}}
The values used in the conditionals come from
ajaxify.data
you can see them in your browser when you load a category page. It is the same data you get when you visit/api/category/3
-
-
-
-