Why setImmediate() not working in expressJS router? - javascript

I try to call a expressJS function from view
This is my AJAX :
const classify = (name) => {
$.ajax({
type: "GET",
url: `http://localhost:3000/classify/${name}`,
success: function (response) {
//loader.hide()
if (response.message != undefined) {
alert(`${response.message}`)
window.location = response.url
}
},
});
}
$("#classify").on("click", () => {
loader.show()
wait.show()
data.hide();
const docsName = $("#nameDocs a").text();
classify(docsName);
});
And this is my router :
router.get("/classify/:name", (req, res, next) => {
let result = main(req.params.name);
console.log("Function in process");
console.log(`Get ${result}`);
console.log("Next, send to view");
setImmediate(() => {
res.send({ url: "/", message: result });
console.log("Send success");
});
});
But I'm confused because it's res.send () before the function execution has finished. So I get undefined.
My console shows like this :
Function in process
Get undefined
Next, send to view
Send success
GET /classify/pdf_1617994486865_G_PM%20No.%2011%20Tahun%202010.pdf 200 18.193 ms - 11

Related

Sending multiple arrays from NODEJS API in response not wait for the response [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 9 months ago.
This post was edited and submitted for review 9 months ago and failed to reopen the post:
Original close reason(s) were not resolved
I have tried different ways to send data in arrays but it shows null. I am sure this is because the response fires before the actual response return. Well, this is my guess! I may be wrong.. I want to know the best practice to do this?
My expected result in the payload:
data: {
allCountries: [{TotalCountries: 12}]
allStates: [{StateId: "15327", STR: "Form",…}, {StateId: "15326", STR: "Form",…},…]
AllCities: [,…]
AllCust: {Id: "1825",…}
}
Now, in nodejs controller, I have 4 functions
exports.getAllDetails = async (req, res) => {
if (!req.query.clientId) {
return res.status(406).send({
success: false,
message: "ID is required"
})
}
let id = req.query['custId'];
let allCountries= await getAllCountries(req, res, id)
// let allStates= this.getStates(req, res, id);
// let allCities= this.getAllCities(req, res, id);
// let custDetails= this.getCustDetails(req, res, id);
return res.send({
success: true,
data:
[allCountries]
[allStates],
[AllCities],
[AllCust]
})
}
Now I have created separate functions for all. i.e.
async function getAllCountries(req, res, id) {
let allCountries;
allCountries= `SELECT query..`
connection.query(allCountries, (err, result) => {
if (result) {
if (result.length > 0) {
return result;
} else {
res.status(204).send({
success: false,
message: `No data found.`,
});
}
}
});
}
I am getting null array in result?
Can anyone tell me the best way to do this?
Because you're trying to return data from callback function :
async function getAllCountries(req, res, id) {
let allCountries;
allCountries= `SELECT query..`
connection.query(allCountries, (err, result) => {
if (result) {
if (result.length > 0) {
return result; // this won't work because it is inside callback function.
} else {
res.status(204).send({
success: false,
message: `No data found.`,
});
}
}
});
}
you need to return promise object :
async function getAllCountries(id) {
let allCountries;
allCountries= `SELECT query..`
return new Promise((resolve) => {
connection.query(allCountries, (err, result) => {
if (result) {
if (result.length > 0) {
resolve(result);
} else {
resolve(null);
}
}
});
});
}
also where you're using this function :
let allCountries= await getAllCountries(id);
if (allCountries == null) {
return res.status(204).send({
success: false,
message: `No data found.`,
});
}
I Will recommend you start using try/catch to handle errors instead of all your function passing the param req/res, whit this solution your code will be more readable.
function getAllCountries(req, res, id) {
return new Promise((res, rej) => {
let allCountries;
allCountries = `SELECT query..`;
connection.query(allCountries, (err, result) => {
if (err) {
rej(err);
}
if (result.length === 0) {
rej({
success: false,
message: `No data found.`,
});
}
res(result);
});
});
}
in your main function:
exports.getAllDetails = async (req, res) => {
if (!req.query.clientId) {
return res.status(406).send({
success: false,
message: 'ID is required',
});
}
try {
let id = req.query['custId'];
let allCountries= await getAllCountries(id)
...
return res.send({
success: true,
data: {
allCountries, //as you want this as array wrap the allCountries as [allCountries]
...
}
})
} catch (err) {
return res.status(400).send(err);
}
};

How to make pagination from an API with AJAX with the same query?

I don't know how good I could the write the title but it's a little bit complicated.
So I have this webpage in /music-maker endpoint which have a modal. In the modal there is an input field which takes in a user input and post it to the backend through AJAX post request. Then that user query is used to make an API request to https://example.com/api/?key=${key}&q=${query}. The result is then displayed in the webpage.
Now that part is working as it should be but the issue comes when I try to implement an infinite scrolling feature to it.
Please note at this point that the api request above returns the first page of data only and if I specify page 2 then it will return the data from page 2 of that exact query.
So whenever the user scrolls to the bottom I need to make another api request with that exact query as before but for page 2 which I am unable to accomplish. I've tried making a get AJAX request and used a global query variable to store the query from post request but it returns undefined.
Here are the endpoints of the app:
let query;
router.get('/music-maker', (req, res) => {
res.render('music-maker');
});
router.post('/music-maker', async (req, res) => {
query = encodeURI(req.body.input);
const key = '205XxXxX54825-0ab1';
try{
const url = `https://example.com/api/?key=${key}&q=${query}`;
const fullRes = await axios.get(url);
if( fullRes.status === 200 ) {
return res.json({
data: fullRes.data
});
}
}catch(err) {
res.json({
error: 'Unable to retrieve data.'
});
}
});
router.get('/music-maker/page', async (req, res) => {
console.log('1: ', query); // returns undefined
const pageQuery = req.query.q;
try{
console.log('2: ', pageQuery)
}catch(err) {
console.log(err)
}
});
Here are the AJAX requests:
const formInput = $(".searchbar input");
const userSearchInput = formInput.val();
const modalForm = $("form");
$(modalForm).submit((e) => {
e.preventDefault();
const actionUrl = $(e.target).attr("action");
$.ajax({
type: "POST",
url: actionUrl,
dataType: "json",
data: {
input: userSearchInput
},
beforeSend: function() {
$(formInput).val("");
},
success: function({ data }) {
if ( data ) {
$(".data-container").html(data);
} else if (data.error) {
$(".error-container").html(data.error);
}
},
complete: function() {
$(".loader-container").addClass("hidden");
},
});
});
// When the user scrolls to the bottom of the container, this ajax request fires
$('.data-container').on('scroll', function(e) {
const elem = $(e.currentTarget);
if (elem[0].scrollHeight - elem.scrollTop() == elem.outerHeight()) {
console.log(userSearchInput); // this is undefined
$.ajax({
type: "GET",
url: `/music-maker/page/`,
dataType: "json",
beforeSend: function() {
console.log('sending');
},
success: function( data ) {
console.log('incoming');
},
complete: function() {
console.log('complete');
},
});
}
});
How can I get the other pages' data of the same query by making an API request through AJAX?
update:
server part code
router.get("/music-maker/search/:query/:page", async (req, res) => {
let query = req.params.query;
let page = req.params.page;
console.log("query: " + query);
console.log("page: " + page);
return res.json({
query: req.params.query,
page: req.params.page
});
});
client/browser
let userSearchInput = "";
let pageNumber = 1;
function getMusicMaker() {
userSearchInput = $(".searchbar input").val();
userSearchInput = encodeURIComponent(userSearchInput);
const actionUrl = "/music-maker/search";
$.ajax({
url: `${actionUrl}/${userSearchInput}/${pageNumber}`,
dataType: "json",
beforeSend: function () {
$(".searchbar input").val("");
},
success: function (data) {
alert(data.query + "\n" + data.page)
}
});
}
$("form").submit((e) => {
e.preventDefault();
pageNumber = 1; // new search, reset page number
getMusicMaker();
});
$(".data-container").on("scroll", function (e) {
const elem = $(e.currentTarget);
if (elem[0].scrollHeight - elem.scrollTop() == elem.outerHeight()) {
pageNumber++; // set page 2,3,4,....
getMusicMaker();
}
});
I think you have multiple problems, to fix it need whole rewrite to your code (client and server) but I suggest to use single http method, POST or GET.
endpoint for static pages list:
/music-maker/1
/music-maker/2
or
/music-maker = /music-maker/page/1
/music-maker/page/2
for search
/music-maker/search/keywords
/music-maker/search/keywords/2
/music-maker/search/keywords/3
to set page number when user scroll you can do like this
let pageNumber = 1;
$('.data-container').on('scroll', function (e) {
const elem = $(e.currentTarget);
if (elem[0].scrollHeight - elem.scrollTop() == elem.outerHeight()) {
pageNumber++;
$.ajax({
type: "GET",
url: `/music-maker/page/${pageNumber}`,
.......
});
}
});

Why does jQuery's ajax success method doesn't work?

I am trying to add some animation while a type-file input is processing the file, I decided to use jQUery's ajax method to send the form data.
I noticed that the beforeSend method works, but not with the success method, but instead, the error method contains all the response sent by my node server. I tried looking for similiar question but none of them work for me.
JS:
fileForm.on('submit', function(e) {
e.preventDefault();
let formData = new FormData();
formData.append('file', $('#input-file').prop('files')[0]);
$.ajax({
url: this.action,
dataType: 'script',
cache: false,
contentType: false,
processData: false,
beforeSend: () => {
console.log('loading');
},
success: function(response) {
console.log(response); // Not logging anything
setTimeout(() => {
console.log('succeded: ' + response);
}, 500);
},
error: (err) => {
console.log(err); // This logs the response
},
data: formData,
type: this.method.toUpperCase()
});
});
Node.JS:
router.post('/image', upload.single('file'), async (req, res) => {
if (req.session.passport !== undefined) {
try {
console.log(req.file, req.body);
const query = {_id: req.session.passport.user};
const user = await modelAct(userModel, query, 'findOne');
// const opt = {
// query: query,
// data: {
// $set: {
// avatar_path: req.file.path
// }
// }
// };
// await modelAct(userModel, opt, 'updateOne');
res.status(200).json({fileData: req.file});
} catch(err) {
console.log(err);
if ((typeof err.message == 'string')) {
res.sendStatus(err.message);
} else {
res.sendStatus(500);
}
}
} else {
res.sendStatus(401);
}
});

Youtube search API results not displaying in the EJS file

I am implementing YouTube Search API in my Website, when I am calling the api from my route the results are returned but the page is rendered while the results are being computed, I guess because of the asynchronous behavior.
My route through which I am calling the API:
router.get('/video/results/:search_query', middleware.ensureAuthenticated, function (req, res) {
query = req.params.search_query;
console.log(query);
var dataFinal;
var resp = youtube.search.list({
part: 'snippet',
q: query,
type: 'video'
},function (err, data, response) {
if (err) {
console.error('Error: ' + err);
res.json({
status: "error"
});
}
if (data) {
// console.log(typeof data);
dataFinal = data;
// return res.json({
// status: "ok",
// data: data
// });
console.log(data);
//res.render('resultsVideo',{results:data})
}
});
res.render('resultsVideo',{data:dataFinal})
});
Please tell me how can I call the API and use the results in my EJS file to display.
you can use function callback to get the desired result.
router.get('/video/results/:search_query', middleware.ensureAuthenticated, function (req, res) {
query = req.params.search_query;
console.log(query);
var dataFinal;
function resp() = youtube.search.list({
part: 'snippet',
q: query,
type: 'video'
},function (err, data, response) {
if (err) {
console.error('Error: ' + err);
res.json({
status: "error"
});
}
if (data) {
// console.log(typeof data);
return data;
// return res.json({
// status: "ok",
// data: data
// });
console.log(data);
//res.render('resultsVideo',{results:data})
}
});
res.render('resultsVideo',{data:resp()})
});

Check that email exists with Node within API

Introduction
Ok, I have Three functions. the first two generate data for the third.
Gets post data (email)
Gets API key
Uses API key, User_key and email and post them to the API
What I need
I need the third to print the following to my console providing the email is present.
else {
console.log("Login successful !");
console.log("API Key", api);
console.log("userKey", userkey);
console.log("useremail", login_email);
console.error("Third You have logged in !");
}
What I am getting
error null
I am getting this even though I post a email that exist. Dose anyone see where I am going wrong in my code ?
Node Code
var firstFunction = function () {
var promise = new Promise(function (resolve) { // may be redundant
setTimeout(function () {
app.post('/test.js', function (req, res) {
console.log(req.body);
// Get varibles from the post form
var login = req.body.LoginEmail;
// res.send(email_user);
res.send(login);
//resolve when get the response
resolve({
data_login_email: login
});
});
console.error("First done");
}, 2000);
});
return promise;
};
//---------------------------------- Function to get API key from Pardot (AUTHENTICATION) ------------------------------
//----------------------------------------------------------------------------------------------------------------------
var secondFunction = function () {
var promise = new Promise(function (resolve) {
setTimeout(function () {
nodePardot.PardotAPI({
userKey: userkey,
email: emailAdmin,
password: password,
DEBUG: false
}, function (err, client) {
if (err) {
// Authentication failed
console.error("Authentication Failed", err);
} else {
// Authentication successful
var api_key = client.apiKey;
console.log("Authentication successful !", api_key);
resolve({data_api: api_key});
}
});
console.error("Second done");
}, 2000);
});
return promise;
};
//---------------------------------- Function to post data to Pardot ---------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------
function thirdFunction(result) {
var promise = new Promise(function () {
setTimeout(function () {
var headers = {
'User-Agent': 'Super Agent/0.0.1',
'Content-Type': 'application/x-www-form-urlencoded'
};
// Configure the request
var api = result[1].data_api;
var userEmail = result[0].data_login_email;
var options = {
url: 'https://pi.pardot.com/api/prospect/version/4/do/read',
method: 'POST',
headers: headers,
form: {
'email': userEmail,
'user_key': userkey,
'api_key': api
}
};
// Start the request
request(options, function (error, response) {
if (!error && response.statusCode == 200) {
console.log("error", error);
}
else {
console.log("Login successful !");
console.log("API Key", api);
console.log("userKey", userkey);
console.log("useremail", login_email);
console.error("Third You have logged in !");
}
});
}, 3000);
});
return promise;
}
// sequence of functions
Promise.all([firstFunction(), secondFunction()])
.then(thirdFunction);

Categories