Solved Upvote / Downvote Function On Topic Level

  • NodeBB Admin

    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[0].mainPid Easiest approach would be to put the mainPid value in the template in a data tag data-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

  • @baris Thanks! I'll give this one a shot!

  • @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>
        <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>
        <!-- ENDIF !downvote:disabled -->

    In order to read the closest data-pid on upvote/downvote, do I need to create a custom js function for that?

  • NodeBB Admin

    @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 right on, thanks!

  • @baris for custom JS. Where is the best place to add it?

  • NodeBB Admin

    If you have a custom theme you can put it there
    See how persona does it with the custom js code in persona.js

  • @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)[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.

  • NodeBB Admin

    delta should be 1 if you are upvoting and -1 if you are downvoting

  • NodeBB Admin

    In the api call it goes in the second parameter like so

    api[method](`/posts/${pid}/vote`, {
    	delta: 1,
    }).then(() => console.log('voted'););

  • 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'));

    I apologize in advance, maybe I'm not understanding the client-side hooks just yet.

  • NodeBB Admin

    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 like filter:topics.get and add aa hasUpvoted field to each topic.

  • @baris thanks! I'm able to make work now.

    My final question is if it's possible to only expose upvote/downvote in specific category or this will only work in topic_list.tpl?

  • NodeBB Admin

    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 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

  • @baris works perfectly! Thanks for all your help!

  • Topic has been marked as solved  T Teemberland 

Suggested Topics

| | |

© 2014 – 2022 NodeBB, Inc. — Made in Canada.