0

I am working on an express app using nodejs and mongoose, i am trying to use js function to update the number of likes on a post in database in my ejs file but it is not working , i have tried onclick() also, bascically anything inside the script tag is not running . Why is this happening , and how can i update the likes of a particular post in database by clicking a button.

Though, i have achieved this likes updation by redirecting to a route in app.js where mongoose function updateOne does it , but i want likes updated without reloadig the page on a button click

update likes route in app.js

app.get('/liked/:id', (req,res)=>{
    Post.updateOne({_id: req.params.id}, {$inc: {likes:1}}, (err,likedpost)=>{
        if(err) console.log(err)
        else{
            res.redirect("/posts/engineering");
        }
   })
})

show.ejs

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  // here i want to add post model of mongoose
     var Post = require("../../models/post.js")


  <h1> <%= post.title %> </h1>
  <h3> <%= post.publish_date %> </h3>
  <p> <%= post.content %></p>
  <button class="likes">like</button>  

</body>
<script>
  console.log("like button increment");              // not printing on console
  var l = document.querySelector(".likes");
  l.addEventListener("click", function(){
    console.log("***********");
    // here i wanted to update the "likes" field of this post by 1 i.e when user clicks the like button without reloading the page

     Post.updateOne({_id: post._id}, {$inc: {likes: 1}});
    console.log(post.likes + "people liked" +  post.title)

  })
</script>


</html>
Ritish Gupta
  • 761
  • 1
  • 5
  • 8

1 Answers1

0

If you want like to update without reloading , you need to use AJAX request.

You don't need to include post.js (var Post = require("../../models/post.js")) in the display page, let the like route be handled by the express server as usual.

In the front end/client code, Shift the script tag inside the body tag, at the end.

<body>
  // here i want to add post model of mongoose


  <h1> <%= post.title %> </h1>
  <h3> <%= post.publish_date %> </h3>
  <p> <%= post.content %></p>
  <button class="likes">like</button>  

<script>
  console.log("like button increment");              // Will print to browser console
  var l = document.querySelector(".likes");
  l.addEventListener("click", function(){
    console.log("***********");
    // MAKE AN AJAX REQUEST (POST) HERE TO localhost//liked/:id (pass the appropriate id)
    // or replace localhost with actual host/domain
    // Check the status returned by the POST request made on the server, if OK, update the 
    //like value using event listener

  })
</script>

</body>

As I have mentioned in the comments, MAKE AN AJAX REQUEST (POST) to the like route localhost//liked/:id (pass the appropriate id) or replace localhost with actual host/domain.

Check the status returned by the POST request made on the server, if OK, update the like value using event listener.

In the express like route, if database part successful, just send an 200 OK status, don't redirect or anything else.

In express , change the like route from .get to .post, this is important.

Check AJAX examples or tutorial to make an AJAX request.

Rupjyoti
  • 394
  • 1
  • 7
  • i have tried it using ajax request but when i am making the post request i need to pass post.slug where post is the object which i passed in show.ejs file , unfortunately post is undefined when i use it in script tag : httpRequest.open('POST', 'http://localhost:3000/posts/liked/' + post.slug); . how can i get this post object to work in script – Ritish Gupta Aug 27 '20 at 12:48
  • var Post = require("../../models/post.js") You are using "Post" with P in capital, why are you using "post" with small letter later. Maybe that's why it is undefined. – Rupjyoti Aug 27 '20 at 12:53
  • as you said earlier , no need to import the mongoose schema in ejs file i have let the ajax request handle that part the only problem is 'post' is an server object and it is not accesible in client-side js . how to make it accessible – Ritish Gupta Aug 27 '20 at 13:00
  • Now I understand the problem. Are you properly passing the {post:post} object in the render function. Maybe thats why post is undefined because you are not passing it. Also, you need to use <%= post._id %> or the proper variable calling the AJAX request to set the correct url of the express id route. – Rupjyoti Aug 27 '20 at 13:00
  • Please try now, it should work. Use <%= post.slug %> inside script. Assuming you are correctly passing the post object in res.render – Rupjyoti Aug 27 '20 at 13:05
  • yes , i am passing object is render function and using <%=%> is not working :httpRequest.open('POST', 'http://localhost:3000/posts/liked/' + <%=post.slug%>); – Ritish Gupta Aug 27 '20 at 13:05
  • IS it still undefined ? Also we need an extra '/' because the path is /posts/liked/variable_slug – Rupjyoti Aug 27 '20 at 13:09
  • yes i did console.log(post) inside script it also shows undefined – Ritish Gupta Aug 27 '20 at 13:12
  • Just above the script, add
    >
    Inside script, now assign var post_slug = document.getElementById('mydiv').dataset.test; Now check using console.log if undefined. Also check https://stackoverflow.com/questions/28603658/can-a-js-script-get-a-variable-written-in-a-ejs-context-page-within-the-same-fil/28603921#28603921 for more info. It seems like there is a way to get the variables inside script tag. Check which one works. If we can resolve the undefined part, every thing will be fine.
    – Rupjyoti Aug 27 '20 at 13:20
  • it is working fine now but i want the number of likes to update automatically, but now i need to refresh the page to see the likes increased – Ritish Gupta Aug 27 '20 at 13:21
  • You don't need to refresh the page. If your AJAX call succeeds, just grab the like count using document.getElementById or any other selector and increment it by 1. Thats it. No refresh needed. – Rupjyoti Aug 27 '20 at 13:26
  • httpRequest.open('POST', 'http://localhost:3000/posts/liked/' + '<%= post.slug %>'); i did this in url – Ritish Gupta Aug 27 '20 at 13:26
  • how can i pass a variable from server side to ajax request? – Ritish Gupta Aug 27 '20 at 14:38
  • And how can i ensure that a user likes the post only once? – Ritish Gupta Aug 27 '20 at 14:47
  • You want to pass a variable from the server as a response to AJAX ? You can just respond with res.json({"UpdatedLikes":`${likeCount}`}) or something similar in the like POST route. To ensure one user doesnot like more than once, a. In the client side disable the like button after like clicked, b. in the server side, validate if user already liked that post, if so return the same like count and you should not increment the like count in the display. Note, I used template string in the variable above, Stackoverflow is changing that. – Rupjyoti Aug 27 '20 at 14:58
  • it is showing this error : Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client , when i do this in post route: return res.json({"UpdatedLikes": "likedpost.likes"}).redirect("/posts/" + subject + "/" + req.params.slug); – Ritish Gupta Aug 27 '20 at 15:13
  • in order to check that a particular user has liked a post i need to reference that post to that user in the user model right? in this way a user will have a list of posts he/she has liked. Or is any other way around to check for a particular user likes a particular post only once? – Ritish Gupta Aug 27 '20 at 15:25
  • For the error "Cannot set headers", you cannot redirect after res.json. It will give that error because you are already sending response and after that you again want to redirect. It will not work that way. – Rupjyoti Aug 27 '20 at 15:33
  • Yes, you need to have some reference of the user in the post or the other way in the DB or model. Not sure if there is any other way. A post can have many likes, so refer the users to a post, might be better. As you wish. – Rupjyoti Aug 27 '20 at 15:35