Reputation: 157
I made a simple application that it's UI shows an Input Text and two buttons: Fetch and Show.
The general idea is after the user types a word and clicks on "Fetch" the app would request the Meaning Like words from Datamuse API and returns in a JSON format the words and their tags (Noun,Verb, Adjective...).
I want that if the apps succeeds to fetch those words, then a success text will be in a variable called "fetchStatus".
Afterwards, I would like that the value of "fetchStatus" will be transferred in res.render to the index.ejs that has the UI code so the user could see if the fetch from Datamuse was successful or not.
The function who runs the fetch called "FetchData(req.body.wordInput)".
The problem is that the res.render function runs before the FetchData function, therefore the fetchStatus value is an empty string.
In the function FetchData I've tried to return the string and pass it to res.render but with no success.
The same situation happened if I put the "fetchStatus" as a parameter or as a global variable.
app.js
============
//jshint esversion:6
var fetchStatus = "";
var vocabularyTags = {
syn: {name:"synonym", freq:0},
n: {name:"noun", freq:0},
v: {name:"verb", freq:0},
adj:{name:"adjective", freq:0},
adv:{name:"adverb", freq:0},
u:{name:"undetermined", freq:0},
prop: {name:"propery", freq:0}
};
const express = require("express");
const bodyParser = require("body-parser");
const request = require("request");
var app = express();
// Setting ejs
app.set('view engine', 'ejs');
// Setting body-parser
app.use(bodyParser.urlencoded({ extended: true }));
app.get("/",function(req,res){
// res.sendFile(__dirname+"/index.html");
res.render("index", {fetchStatus:"", vocabularyTags:{}});
});
app.post("/",function(req,res){
// var fetchStatus = "";
var buttonPressed = req.body.submit;
if (buttonPressed === "fetch") {
FetchData(req.body.wordInput);
console.log("Fetch Status: "+fetchStatus);
res.render("index",{ fetchStatus:fetchStatus ,vocabularyTags:{} });
}
else if (buttonPressed === "show") {
//ShowData();
var vocabularyTagsResults = vocabularyTags;
res.render("index",{fetchStatus:"" ,vocabularyTags:vocabularyTagsResults});
// Clear Vocabulary Tags Frequencies
for (var key in vocabularyTags) {
vocabularyTags[key].freq = 0;
}
}
});
app.listen(3000,function(){
console.log("Server is running on port 3000");
});
function FetchData(wordInput) {
// var fetchStatus = "";
var options = {
url:"https://api.datamuse.com/words",
method:"GET",
qs: {
ml: wordInput
}
};
request(options,function(error,response,body){
if (error) {
fetchStatus = error;
}
else {
var dataMuseML = JSON.parse(body);
console.log(dataMuseML);
// Counting the related tags
dataMuseML.forEach(function(item){
var tags = item.tags;
tags.forEach(function(tag){
vocabularyTags[tag].freq++;
});
});
fetchStatus = "Fetch from Datamuse API has succeeded!";
}
});
// return fetchStatus;
}
views/index.ejs
================
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Datamuse API</title>
</head>
<body>
<h1>Datamuse API</h1>
<form action="/" method="post">
<input type="text" name="wordInput" placeholder="Enter a word...">
<button type="submit" name="submit" value="fetch">Fetch</button>
<button type="submit" name="submit" value="show">Show</button>
</form>
<h3> <%= fetchStatus %> </h3>
<% for (var key in vocabularyTags) { %>
<p> <span><%= vocabularyTags[key].name %>:</span> <span> <%= vocabularyTags[key].freq %></span> </p>
<% } %>
</body>
</html>
The expected result is that "fetchStatus" will have a success or an error text so I could pass it to res.render which will put it in index.ejs.
Upvotes: 0
Views: 2194
Reputation: 5215
You should use Promise
for that
function FetchData(wordInput) {
// var fetchStatus = "";
var options = {
url:"https://api.datamuse.com/words",
method:"GET",
qs: {
ml: wordInput
}
};
return new Promise((resolve, reject) => {
request(options,function(error,response,body){
if (error) {
reject(error);
}
else {
var dataMuseML = JSON.parse(body);
console.log(dataMuseML);
// Counting the related tags
dataMuseML.forEach(function(item){
var tags = item.tags;
tags.forEach(function(tag){
vocabularyTags[tag].freq++;
});
});
resolve("Fetch from Datamuse API has succeeded!");
}
});
});
// return fetchStatus;
}
And then you can call it like that:
app.post("/",function(req,res){
// var fetchStatus = "";
var buttonPressed = req.body.submit;
if (buttonPressed === "fetch") {
FetchData(req.body.wordInput).then(res => {
console.log("Fetch Status: "+res);
res.render("index",{ fetchStatus:res ,vocabularyTags:{} });
}).catch(err => {
console.log("Error: "+err);
res.render("index",{ fetchStatus:err ,vocabularyTags:{} });
})
}
// ...
}
If you want to keep your result in a global, you can just set your fetchStatus, and just call resolve
and then
like that:
// ...
return new Promise((resolve, reject) => {
if (error) {
fetchStatus = error;
}
else {
// ...
fetchStatus = "Fetch from Datamuse API has succeeded!";
}
});
});
resolve(fetchStatus);
}
app.post("/",function(req,res){
if (buttonPressed === "fetch") {
FetchData(req.body.wordInput).then(res => {
// res or fetchStatus should be available here but it's better to use res
console.log("Fetch Status: "+res);
res.render("index",{ fetchStatus:res ,vocabularyTags:{} });
})
}
}
Upvotes: 1