How to add a follow/unfollow button with node js - javascript

I am new to this. I am trying to build a website where users can follow/unfollow each other. Like/Unlike posts.
I am using Node js and MySQL.
I know how to make users add new posts by using a form and this will direct them to a POST route and there I can do the back-end stuff. But how can I add a follow button similar to Twitter/Instagram that changes dynamically when a user clicks on it without refreshing the page.
I thought of something like this in front-end "Profile.ejs file"
<form action="/follow" method="POST">
<input class="btn btn-primary a-btn-slide-text" name="follow" type="submit" value="Follow"/>
</form>
But then I am not able to pass in the information for the user I am trying to follow in the back-end (e.g user_id) and not able to change the button value to "unfollow". This is what I thought I would do on the back-end:
app.post("/follow", function(req, res){
var follow = {follower_id:currentUser.id, followee_id:user_id};
connection.query('INSERT INTO follows SET ?', follow , function(err, result) {
if (err) throw err;
res.redirect("/");
});
});
Any idea on how I can achieve this? Also are there any resources/websites/courses that I could learn from on how to use dynamic/javascript stuff like this with nodejs?

You should use Ajax in your front-end template to send a request to your back-end.
Something like that (you don't need to put it in a form):
<button type="button" id="follow">Follow</button>
<script type="text/javascript">
$("#follow").click(function(){
$.ajax({
url: '/follow',
type: 'GET',
dataType: 'json',
success: function(data, status){
// Here you can change your button text using jQuery
}
});
});
</script>
Then, in your back-end:
app.get("/follow", function(req, res) {
var follow = {follower_id:currentUser.id, followee_id:user_id};
// Do stuff here, call your database, etc.
res.send({ msg: "User followed/unfollowed!" });
});
Your Ajax method will receive this message: { msg: "User followed/unfollowed!" }

Related

passing value through AJAX url attribute to server code

I am building an off-canvas overlay to show all the comments on a blog. I want to use ajax so that users can post and see the update of the comments section without reloading the page.
I have been using ejs syntax for my HTML files but when it goes to ajax, I don't know how to let the back end server recognize the data through the "erl" attribute in ajax.
my ajax code
$("#commentBtn").on("click", () => {
$.ajax({
url: "/home/<%=blog.title%>/comment", <--- I want to send the title attribute of the blog to backend
contentType: "application/json",
success: (response) => {
let commentElem = $("#showComments");
response.comments.forEach(comment => {
commentElem.append('\
<h2>'+comment.id+'</h2>\
<h3>'+comment.content+'</h3>\
');
});
}
})
})
related HTML code
<button type="button" id="commentBtn" uk-toggle="target: #offcanvas-usage">show comment</button>
my router
router.get("/home/:title/comment", async(req, res) => {
await Blog.findOne({title: req.params.title}, (err, foundBlog) => {
if(err) {
console.log(err);
} else{
*do the send comment things ....*
}
})
})
The problem now is the router cannot recognize req.params.title, I think it is the ajax issue that it didn't send the title of the blog to the router. so that the router cannot find the specific blog for me.
Is there any ajax syntax to let my router to use req.params.title?
Thanks in advance!
I'm not familiar with ejs, but can you use template literals?
url: `/home/${blog.title}/comment`
More info here

Creating routes for Ajax calls in NodeJs

let's say I have this route for my rendered HTML:
app.get('/profile/:id', function (req, res) { // my route
res.render('profile', { id: Number(req.params.id) }); // render the file and set a variable
});
and in my client side javascript file for the profile page I want to get data from the server. I request the data when loading the page by sending a user id to the server and the server returns a user object:
$(document).ready(function() {
var user = null;
$.ajax({
type: 'GET',
url: '', // This one is missing here
dataType: 'json'
}).done(function(data){
user = JSON.stringify(data);
});
console.log(user.name);
});
And my server would handle this function:
app.get('', function (req, res) { // missing route
var userId = ; // This is missing
var userObj = getUserById(userId);
res.send(userObj);
});
What route do I have to use? Tutorials say I have to pass in the route like /profile/:id but this route already exists?
I tried defining a new route like:
app.get('/reqUser/:id', function (req, res) { // Ajax route
res.send(getUserById(Number(req.params.id)));
});
and for my Ajax call I pass in the url http://localhost:8888/reqUser/12345 but this seems to be wrong because user is still null after using the Ajax call.
So how can I define a route handling the page and the Ajax call?
Edit: First off, you'll want to fix the bug in your client-side JS, where you are attempting to print user.name before user has been fetched from the server. You can fix this by moving your console.log statement into the done() callback like so:
$(document).ready(function() {
var user = null;
$.ajax({
type: 'GET',
url: '', // This one is missing here
dataType: 'json'
}).done(function(data){
user = JSON.stringify(data);
console.log(user.name); // log here
});
});
Regarding your routes question, you have several options. Below are two common solutions to this problem:
Create a separate api route to distinguish your API requests from your page requests. For example, app.get('/api/profile/:id, (req, res) => {...});'
Add a URL parameter to your AJAX calls specifying the format you want the response to be in, with the default being the page's HTML. For example, your AJAX would send a GET request to the URL /profile/2012?format=json, which would return the profile's information in JSON.
Personally, I prefer the first option, as it makes intent more clear.

res.render sends data back in String format

I am developing an app with the node, express, and mongoose. In my login module, res.render() the function sends the code back to the client side ajax call as string format data. Whereas I wanted it to render a particular view. ajax call is post type call. I can see the entire HTML in string format in success field of ajax.
I did search for similar problem and solutions, but I couldn't find any. Let me know what I am doing wrong.
Client Side :
$.ajax({
type: 'POST',
url: '/login',
data: userDetail,
success: function(data){
console.log(data);
},
error: function(err){
$("p").text("Invalid User Details")
}
});
Server Side :
app.post('/login', urlencodedParser ,function(req,res){
console.log(req.body);
User.find({name : req.body.name , password : req.body.pass},function(err,data){
if (data.length != 0){
Todo.find({},function(err,todo){
if (err) throw err;
var token = jwt.sign(req.body,config.secret,{
expiresIn : '1h'
});
res.render('todo',{
todos : todo,
token : token
});
});
}
else
res.status(401).json({ msg : "Invalid User" });
});
});
Ajax calls do not, by themselves, change what is displayed in the browser. They just fetch data and your Javascript code them decides what to do with that data. This is true no matter what type of Ajax call it is, GET, POST, etc...
If you want to change the current page to show the content you fetched with Ajax, then you have to insert that content into the current page yourself.
Or, in the case of a POST, perhaps you want to submit an HTML form and then the browser will render the content that comes back from that form post for you, but an ajax post will not change what the browser displays at all.
Submitting an HTML form can be done either via Javascript or via native user actions (without any Javascript). But, for the browser to process the result for you, it has to be the browser submitting the form, not an ajax call sending the form. If an Ajax call sends the form (as in the code you show), then the result just comes back to your Javascript and it's up to your Javascript to decide what to do with that result (insert it in the page, etc...).

Routing Express and outputting to template

lets say I have
router.get('/read', function(request, response) {
res.send({"result": "Success sent from routes/index.js."});
});
how do I output a template with the data. If I use res.send() I can't use res.render() right?
If my users are at /read and click a button to send some data with ajax I want to display that data in another template on /read
Edit: One way to get around this is to make a string when you return the data (or maybe not)
success : function(data){
$(".fillIn").html("<p style = 'color:green;'>" + data + "</p>")
}
I don't want a string.
The pic shows that on one page "/" there are 2 buttons and by clicking each button you can send data and that data can be displayed on the right depending on which button was clicked, a form with some data filled in or a table filled in with some data. I use ajax to send the data on click..There will be different forms with different styles. That's why I want to add in a template. I could do that with HTML using .load() I think but I cant figure out how do with that jade.
Here's my other Question
In your index.js file, use the following to capture GET and POST requests and render different responses:
app.get('/read', function(req, res, next){
res.render('emptyFormTemplate');
});
app.post('/read', function(req, res, next){
res.render('dataTableTemplate', {
name: req.body.name,
email: req.body.email
});
});
On the client-side, you you can something like this to POST the data to /read. You would include this script in emptyFormTemplate in the above example.
$('#myForm').submit(function(event){
var formData = {
'name' : $('input[name=name]').val(),
'email' : $('input[name=email]').val()
};
$.ajax({
type: 'POST',
url: '/read',
data: formData,
dataType: 'json'
});
});

Ajax Request in Node - Avoid Page Reload

I have an ajax request being called on form submit. The idea is to save a user's account information without a page reload, and give them a handy flash message to let them know the save was successful. I have no problem saving the data, but I do have a problem with avoiding a redirect on the POST (to a white page with the response data). Here's what I have:
In my Jade view
$("form").on("submit", function (e) {
e.preventDefault(); // prevent page reload
$ajax({
type: "POST",
url: '/account',
data: $("#accountForm").serialize(),
success: function() {
// can req.flash even be used here? How might it be?
req.flash('info', {msg: 'Your profile has been updated!'});
}
}
}
In my controller
exports.postAccount = function(req, res, next) {
var userData = req.body;
userData.id = req.user.user_id;
var updateUserCallback = function(err) {
// This is where everything falls apart
// Theoretically this should run the success handler in the ajax response
res.json(true);
// Any response I send changes the view to a white page with the data, e.g.
// res.send(anyData);
// Flash also doesn't seem to work, which seems weird...
req.flash('info', {msg: 'Your profile has been updated!'});
}
// Successfully saves the data, no problems here
UserModel.updateUser(userData, updateUserCallback);
};
Normally in the updateUserCallback I would just render the account view, but that defeats the purpose of ajax. I want to save the user's data without a page reload/redirect, while letting them know that the ajax function completed successfully (or didn't) via req.flash (flash module).
Basically any res.send() or res.json() call puts that data into a plain white page (no view). I suppose that I'm fundamentally misunderstanding how ajax works, but I've followed other examples for jQuery ajax calls in Node and have not been able to avoid the 'white page' problem.
Node:
var updateUserCallback = function(err) {
return res.send({
message: "Your profile has been updated"
});
}
Client-side JS:
success: function(response) {
// can req.flash even be used here? How might it be?
// Nope
//req.flash('info', {msg: 'Your profile has been updated!'});
$('#someModal').show().html(response.message); // just a sample implementation
}
Instead of using the form submit, you can use simple button click so that page will not get reloaded.

Categories