Submit a POST and process the result in Nodejs/EJS - javascript

I have an Index Site (EJS) that reads an array into a select form.
index.ejs
<html>
<head>
</head>
<body>
<center>
<form action="/dates" method="POST">
<b>INDEX:</b>
<select id="index" name="index" onchange="this.form.submit()">
<option id="0"> Please choose Index </option>
<% collectionnames.map(item=> { %>
<option id="<%= item._id%>"> <%= item %> </option>
<% }) %>
</select>
<br>
</form>
</body>
</html>
When the Index is chosen it posts the index value to /dates in app.js
app.js
var express = require('express');
var MongoClient = require('mongodb').MongoClient;
var app = express();
var bodyParser = require('body-parser');
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({ extended: false }));
app.use( bodyParser.json() );
app.use(express.static('public'));
app.get('/', function(req, res) {
var collectionnames = [];
MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true }, function (err, client) {
if (err) {
console.log("Error");
} else {
console.log("Connected to MongoDB to get collections...");
}
var db = client.db('my-mongodb');
db.listCollections().toArray(function (err,collections) {
collections.forEach(function(collection){
var elem = new Object();
if (collection.name !== "system.indexes"){
//console.log(collection.name);
elem = collection.name;
collectionnames.push(elem);
};
});
console.log("got collections...")
res.render('index.ejs' , { collectionnames: collectionnames } );
});
});
});
app.post('/dates', function (req, res) {
const postBody = req.body;
index = postBody.index;
var dates = [];
MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true }, function (err, client) {
if (err) {
console.log("Error");
} else {
console.log("Connected to fetch results");
}
var db = client.db('my-mongodb');
db.collection (postBody.index, function(err, values){
values.find().sort({VALUETIME:+1}).toArray( function (err,results){
results.forEach(function(result){
dates.push(result.VALUEDATE);
//console.log(elem)
});
console.log("got results...")
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
var unique = dates.filter( onlyUnique );
console.log(unique);
res.send(unique);
});
});
});
});
How can i just pass the array "unique" back to my index.ejs to process it in another select form? What happens right now (with res.send(unique)) is that i receive a list in the browser with the array values:
0 "2018-09-01"
1 "2018-09-02"
2 "2018-09-05"
3 "2018-09-03"
4 "2018-09-04"
5 "2018-08-31"
More specific: how to retrieve the array/values back to my index.ejs and do something with it?
Thanks.

You can use for loop on collectionnames like:
//Assuming your `collectionnames = ['2018-09-01', '2018-09-02', '2018-09-03', '2018-09-04']`
<select id="selectId">
<option value="">Select</option>
<% if (collectionnames.length) { %>
<% for (var i = 0; i < collectionnames.length; i++) { %>
<option value="<%=collectionnames[i]%>"><%=collectionnames[i] %> </option>
<% } %>
<% } %>
</select>
EDIT: How to send data back to same ejs page?
In order to use same ejs page you need to use Single Page Application approach. For single-page you need to submit data using Ajax call and not form-submit. Check out this repository and various example of how to implement single-page application.
Also if you don't want to go into single-page application just change your api response, render same page with new data:
app.post('/dates', function (req, res) {
const postBody = req.body;
index = postBody.index;
var dates = [];
MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true }, function (err, client) {
if (err) {
console.log("Error");
} else {
console.log("Connected to fetch results");
}
var db = client.db('my-mongodb');
db.collection (postBody.index, function(err, values){
values.find().sort({VALUETIME:+1}).toArray( function (err,results){
results.forEach(function(result){
dates.push(result.VALUEDATE);
//console.log(elem)
});
console.log("got results...")
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
var unique = dates.filter( onlyUnique );
console.log(unique);
// Change here
res.render('index.ejs' , { collectionnames: unique });
});
});
});
});

Related

Cannot read property items of null

I am learning javascript and databases, so I am practicing by making a todo list application. Which add item dynamically in the lists. List is created through URL like http://localhost:3000/work creates a work list, but whenever I try to add something it shows an error.
my JS code:
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const app = express();
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static("public"));
mongoose.connect("mongodb://localhost:27017/todolistDB", {useNewUrlParser: true, useUnifiedTopology: true });
const itemsSchema = {
name: String
};
const Item = mongoose.model ("Item", itemsSchema);
const item1 = new Item ({
name: "item1"
});
const item2 = new Item ({
name: "item2"
});
const item3 = new Item ({
name: "item3"
});
const defaultItems = [item1, item2, item3];
const listSchema = {
name: String,
items: [itemsSchema]
};
const List = mongoose.model("List", listSchema);
app.get("/", function(req, res) {
Item.find({}, function(err, foundItems){
if(foundItems.length === 0){
Item.insertMany(defaultItems, function(err){
if(err){
console.log(err);
} else {
console.log("Succesfully saved the items");
}
});
res.redirect("/");
} else {
res.render("list", {listTitle: "Today", newListItems: foundItems});
}
});
});
app.get("/:customListName", function(req, res){
const customListName = req.params.customListName;
List.findOne({name: customListName}, function(err, foundList){
if(!err){
if(!foundList){
//Create a new list
const list = new List({
name: customListName,
items: defaultItems
});
list.save();
res.redirect("/" + customListName);
} else{
//show the existing list
res.render("list", {listTitle: foundList.name, newListItems: foundList.items})
}
}
});
});
app.post("/", function(req, res){
const itemName = req.body.newItem;
const listName = req.body.list;
const item = new Item ({
name: itemName
});
if(listName === "Today"){
item.save();
res.redirect("/");
} else {
List.findOne({name: listName}, function(err, foundList){
if(err){
console.log(err);
} else{
foundList.items.push(item);
foundList.save();
res.redirect("/" + listName);
}
});
}
});
app.post("/delete", function(req, res){
const checkedItemId = req.body.checkbox;
Item.findByIdAndRemove(checkedItemId, function(err){
if(!err){
console.log("Succesfully deleted the item!!");
res.redirect("/");
}
});
});
app.get("/about", function(req, res){
res.render("about");
});
app.listen(3000, function() {
console.log("Server started on port 3000");
});
My ejs code:
<%- include("header") -%>
<div class="box" id="heading">
<h1> <%= listTitle %> </h1>
</div>
<div class="box">
<% newListItems.forEach(function(item) { %>
<form action="/delete" method="post">
<div class="item">
<input type="checkbox" name="checkbox" value="<%=item._id%>" onchange="this.form.submit()">
<p><%=item.name%></p>
</div>
</form>
<% }); %>
<form class="item" action="/" method="post">
<input type="text" name="newItem" placeholder="New Item" autocomplete="off">
<button type="submit" name="list" value="<%=listTitle%>">+</button>
</form>
</div>
<%- include("footer") -%>
The List.findOne function might return either one "List" { name: String, items: [itemsSchema]} item or null. Unfortunately, you don't check for the null condition which can happen if this list hasn't been created yet in your database.
To solve this issue, you'll need to add an existence check for the foundList variable in your code.
If the foundList variable isn't null, then the foundList contains a list and a new item can be pushed to it.
Else if the foundList variable is null, you can create a new list with this name and the item you want to add to it.
if (err) {
console.log(err);
} else if (foundList !== null) {
foundList.items.push(item);
foundList.save();
res.redirect("/" + listName);
} else {
// List is not found, here you can create a new list with the item, or possibly return an error to the user (listName not found!)
foundList = new List({ foundList: [item], name: listName });
foundList.save();
res.redirect("/" + listName);
}
PS: You could refactor the code I wrote above to reduce duplication.

Building a project around Bing translate and Node.js

I am trying to build a web app that allows a user to press a button and translate a piece of text using the Bing translator api. I try to run a translator.js file through a script tag but I of course cannot run this node.js code through the client html page. What would be the proper way to design this app. Is my only choice to use something such as requirejs? I also have an app.js file built using express from which I run the app. Sorry for posting a lot of code, I want to give people an idea of the structure of my app. My experience is limited so I am feeling somewhat lost as to how to approach the design of this portion of the app. I don't expect anyone to write the code for me, but to just point in a direction of techniques that I could research so that I could build this properly.
Here is my Node.js translation request called translator.js
const request = require('request');
const uuidv4 = require('uuid/v4');
var key_var = 'TRANSLATOR_TEXT_SUBSCRIPTION_KEY';
if (!process.env[key_var]) {
throw new Error('Please set/export the following environment variable: ' + key_var);
}
var subscriptionKey = process.env[key_var];
var endpoint_var = 'TRANSLATOR_TEXT_ENDPOINT';
if (!process.env[endpoint_var]) {
throw new Error('Please set/export the following environment variable: ' + endpoint_var);
}
var endpoint = process.env[endpoint_var];
let options = {
method: 'POST',
baseUrl: endpoint,
url: 'translate',
qs: {
'api-version': '3.0',
'to': ['en']
},
headers: {
'Ocp-Apim-Subscription-Key': subscriptionKey,
'Content-type': 'application/json',
'X-ClientTraceId': uuidv4().toString()
},
body: [{
'text': 'hallo welt'
}],
json: true,
};
function displayBingTranslate() {
request(options, function(err, res, body){
document.querySelector("#bingTranslateOutput") = JSON.stringify(body, null, 4);
});
};
var accessBingTranslate = document.getElementById("accessBingTranslateButton");
accessBingTranslate.addEventListener("click", function() {
displayBingTranslate();
});
And here is my html
<!-- Section to view online translation -->
<div class="container">
<div class="row">
<div class="col-lg-12 p-0">
<button
class="btn btn-outline-dark btn-sm mb-1"
id = "accessBingTranslateButton">Translate Flashcard</button>
<div class="row m-0 p-0">
<div id="bingTranslateOutput" class="col-lg-12 m-0">
</div>
<script>
// Overall list of flashcards.
var flashcardList = {
flashcards: [],
// Adds a flashcard object to Flashcard array.
addFlashcard: function(fcTextQuestion, fcTextTranslated) {
this.flashcards.push({
fcTextQuestion: fcTextQuestion,
fcTextTranslated: fcTextTranslated
});
},
};
// Add flashcards on load.
var flashcardsDB = <%- JSON.stringify(flashcardsDB) %>;
console.log("the DB:", flashcardsDB);
flashcardsDB.forEach(function(fcardDbToAdd){
flashcardList.addFlashcard(fcardDbToAdd.question, fcardDbToAdd.translation);
});
document.querySelector("#displayFlashcardTotal").textContent = flashcardList.flashcards.length;
console.log("the rest:",flashcardList.flashcards);
var currentFlashcard = 0;
</script>
<script src="/scripts/translator.js"></script>
</body>
</html>
and here is my app.js
var express = require("express");
var app = express();
var bodyParser = require("body-parser");
var mongoose = require("mongoose");
var methodOverride = require("method-override");
// Fix mongoose deprecations
mongoose.set('useNewUrlParser', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndex', true);
mongoose.set('useUnifiedTopology', true);
// Connect to database.
var url = "///////";
mongoose.connect(url, {
useNewUrlParser: true,
useCreateIndex: true,
}).then(() => {
console.log("connected to mongoDB");
}).catch(err => {
console.log("Error:", err.message);
});
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static(__dirname + '/public'));
// Set 'views' directory for any views
// being rendered res.render()
app.set("view engine", "ejs");
// Override HTTP verbs if necessary.
app.use(methodOverride("_method"));
var flashcardSchema = new mongoose.Schema ({
question: String,
translation: String
});
//creates model with above schema and has methods such as .find etc.
var Flashcard = mongoose.model("Flashcard", flashcardSchema);
app.get('/', (req, res) => {
Flashcard.find({}, function(err, allFlashcards){
if(err){
console.log(err);
} else {
res.render("home", {flashcardsDB: allFlashcards});
}
});
});
// Post to an input action
app.post("/flashcards", function(req, res) {
var question = req.body.question;
var translation = req.body.translation;
var newFlashcard = {question: question, translation: translation};
console.log(newFlashcard);
Flashcard.create(newFlashcard, function(err, newlyCreated){
if(err){
console.log(err);
} else {
res.redirect("/flashcards");
}
});
});
// Show info.
app.get("/info",function (req, res) {
res.render("info");
});
// Show all flashcards
app.get("/flashcards", function(req, res){
Flashcard.find({}, function(err, allFlashcards){
if(err){
console.log(err);
} else {
res.render("flashcards", {flashcards: allFlashcards});
}
});
});
// Show form to create new campground
app.get("/new", function(req, res){
res.render("new");
});
// Edit flashcard
app.get("/flashcards/:id/edit", function(req, res){
Flashcard.findById(req.params.id, function(err, selectedFlashcard){
if(err){
req.flash("error", "Flashcard not found!");
} else {
res.render("edit", {flashcard: selectedFlashcard});
}
});
});
// Update flashcard
app.put("/flashcards/:id", function(req, res){
Flashcard.findByIdAndUpdate(req.params.id, req.body.flashcard, function(err, updatedFlashcard){
if(err){
res.redirect("/flashcards");
} else {
res.redirect("/flashcards");
}
});
});
// Destroy Flashcard
app.delete("/flashcards/:id", function(req, res){
Flashcard.findByIdAndRemove(req.params.id, function(err){
if(err){
res.redirect("back");
} else {
//req.flash("success", "flashcard deleted.");
res.redirect("/flashcards");
}
});
});
app.listen(3000, () => console.log("Flashcard app is listening"));
I think the best aproach would be to pass the translator.js to the node.js server. Create a route on express for translations, and through that route you will call the translator.js and return the result. Then, on your html page, instead of running the translator.js directly, send a request to your server passing the necessary data.
On your app.js, you can do a route like this:
const translator = require('path_to_translator');
app.get('/translation', translator);
And then on your translator.js, you can export a function that will receive the parameters you need and return the result:
const bingTranslate = (req, res) => {
// YOUR CODE HERE
}
module.exports = bingTranslate
And then on your html you will make the button send a request to your server instead of calling translator.js, so you can change the value of the #bingTranslateOutput button based on the response you will receive from the server.

How can I put input value to the JSON in node.js file

I was making the TODO list web application.
This is the 'todo.html' code below :
<html>
<head>
<title>My TODO List</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="main.css">
<script>
$(document).ready(function() {
$("#submit").click(function() {
var bla = $('#item').val();
$("#todo").append("<li class='todoVal'>" + bla + "</li>");
});
// $(document).click(function(e) {
// if (e.target.className == 'todoVal') {
// var t = e.target.innerText
// $(e.target).remove();
// $("#completed").append("<li class='completedVal'>" + t + "</li>");
// }
// });
$(document).click(function(e) {
if (e.target.className == 'completedVal') {
$(e.target).remove();
}
});
jQuery.fn.single_double_click = function(single_click_callback, double_click_callback, timeout) {
return this.each(function() {
var clicks = 0,
self = this;
jQuery(this).click(function(event) {
clicks++;
if (clicks == 1) {
setTimeout(function() {
if (clicks == 1) {
single_click_callback.call(self, event);
} else {
double_click_callback.call(self, event);
}
clicks = 0;
}, timeout || 500);
}
});
});
}
$(document).single_double_click(function(e) {
if (e.target.className == 'todoVal') {
var t = e.target.innerText
$(e.target).remove();
$("#completed").append("<li class='completedVal'>" + t + "</li>");
}
}, function(e) {
if (e.target.className == 'todoVal') {
$(e.target).remove();
}
});
$("#clear").click(function() {
$("li").remove();
});
});
</script>
</head>
<body>
<div id="addItem" class="box">
Task:
<input id="item" type="text" name="add_item" />
<button id="submit" type="button">Add</button>
<button id="clear" type="button">Clear All</button>
</div>
<div id="todo" class="box">
<h4>TODO:</h4>
<ul></ul>
</div>
<div id="completed" class="box">
<h4>Completed:</h4>
<ul></ul>
</div>
</body>
</html>
And this is the 'app.js' file below :
var express = require('express');
var app = express();
var cors = require('cors');
var bodyParser = require("body-parser");
// middleware
app.use(cors());
app.use(bodyParser.json());
var tasks = [];
// This will serve the HTML page todo.html
app.get('/', function(req, res) {
res.sendFile('todo.html', {
root: __dirname
});
});
// GET all tasks
app.get('/tasks', function(req, res) {
res.set('Content-Type', 'application/json')
res.status(200).send(tasks);
});
// POST to add a task
app.post('/task', function(req, res) {
res.set('Content-Type', 'application/json')
/* HELP ME HERE */
// returns 201 on success
res.status(201);
});
// DELETE a task
app.delete('/task', function(req, res) {
/* HELP ME HERE */
// returns 204 on success
res.status(204);
});
// DELETE all tasks
app.delete('/tasks', function(req, res) {
/* HELP ME HERE */
// returns 204 on success
res.status(204);
});
//
// Listen for HTTP requests on port 3000
app.listen(3000, function() {
console.log("listening on port 3000");
});
I want to pass the text box value to the JSON filter by 'TODO' and 'COMPLETED'.
If I add a new TODO list, it goes to the JSON and if the value goes to COMPLETED, it also goes to the JSON
This is the sample JSON result I want:
{"TODO" : [ "Go to market", "Eat dinner with Daniel"], "COMPLETED" : [ "Wash dishes", "Go to gym and Workout" ]}
This is just an example so you guys can just change the format.
Feel free to give me feedback from everything it's always welcome. btw I just started studying how to code
Thank you for spending time on this even if you didn't help me and have a great day!
What you have to do is simply make an Ajax Call to Nodejs APIs. For example,to '/task' and pass the input field value as params in json format then simply fetch them on in Nodejs as req.params.yourjsonKeys.
var inputData = $("#items").val();
$.ajax({
url: "/tasks",
type: "POST",
data: {params: inputData},
dataType: "html",
success: function(data){
if(data.code === 200){ // the response key 'code' from Nodejs
alert('Success');
}
}
});
Next, once you have the params, all you have to do is write it into your file using file system like so:
Create a javascript object with the table array in it
var obj = {
table: []
};
Add some data to it like
obj.table.push({id: req.params.id , square: req.params.square});
Convert it from an object to string with stringify
var json = JSON.stringify(obj);
//use fs to write the file to disk
var fs = require('fs');
fs.writeFile('myjsonfile.json', json, 'utf8', callback);
if you want to append it read the json file and convert it back to an object
fs.readFile('myjsonfile.json', 'utf8', function readFileCallback(err, data){
if (err){
console.log(err);
} else {
obj = JSON.parse(data); //now it an object
obj.table.push({id: 2, square:3}); //add some data
json = JSON.stringify(obj); //convert it back to json
fs.writeFile('myjsonfile.json', json, 'utf8', callback); // write it back
}});
Complete Code:
// POST to add a task
app.post('/task', function(req, res) {
res.set('Content-Type', 'application/json')
var obj = {
table: []
};
obj.table.push({id: req.params.id , square: req.params.square});
var json = JSON.stringify(obj);
var fs = require('fs');
fs.writeFile('myjsonfile.json', json, 'utf8', callback)
fs.readFile('myjsonfile.json', 'utf8', function readFileCallback(err, data){
if (err){
console.log(err);
} else {
obj = JSON.parse(data); //now it an object
obj.table.push({id: 2, square:3}); //add some data
json = JSON.stringify(obj); //convert it back to json
fs.writeFile('myjsonfile.json', json, 'utf8', callback); // write it back
// returns 201 on success
res.json({
code: 201,
message: 'Success'
});
}});
});

How to post an array to Express API

I'm creating APIs with Express.js and SQL Server. I been posting an object which is easy and very simple, but now i have a new question: how to post an array?
Let's say i have a table which stores only two params:
Table_A
Id | CouponId
In fact, the only record that stores is CouponId, 'cause the Id is created by SQL Server on every record. So, the case is that i get a list of coupons from an api, and the idea is select from one to 'n' with a checkbox and save the selection.
This my code so far:
function getList(){
$http.get('/api/coupons')
.then(function(data){
$scope.infoCoupons = data.data.Response;
}
On the HTML view:
<div class="col-lg-12" align="center">
<input type="checkbox" ng-click="selectAll()"/> <a style="font-size:17px;color:black;text-decoration:none;">Select all coupons</a>
<ul class="coupon-list">
<li ng-repeat="coupon in infoCoupons">
<input type="checkbox" ng-model="coupon.Select" ng-click="checked"/> <a style="font-size:17px;color:black;text-decoration:none;">{{coupon.CodeCoupon}}</a>
</li>
</ul>
</div>
Then, to get the selected coupons:
$scope.selectAll = function(){
$scope.all = !$scope.all;
$scope.infoCoupons.forEach(function(o){
o.Select = $scope.all;
});
}
function chosenCoupons(){
var result = new Array();
var checked = 0;
$scope.infoCoupons.forEach(function(e){
if(e.Select === true){
result.push(e.Id);
checked +=1;
}
});
if($scope.all || checked > 0){
alert("Selected coupons!");
}
else if(checked === 0){
alert("Select at least one coupon");
}
}
Then, my code for the API:
const express = require('express');
const bodyParser = require('body-parser');
const sql = require('mssql');
const app = express();
app.use(bodyParser.json());
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, contentType,Content-Type, Accept, Authorization");
next();
});
const dbConfig = {
user: "daUser",
password: "daPass",
server: "daServa",
database: "daDB"
};
const executeQuery = function (res, query, parameters) {
sql.connect(dbConfig, function (err) {
if (err) {
console.log(`There's an error: ${err}`);
res.send(err);
sql.close();
}
else {
var request = new sql.Request();
if (parameters && parameters.length > 0) {
parameters.forEach(function (p) {
request.input(p.name, p.sqltype, p.value);
});
}
request.query(query, function (err, result) {
if (err) {
console.log(`Theres an error: ${err}`);
res.send(err);
sql.close();
}
else {
res.send(result);
sql.close();
}
});
}
});
}
app.post("/api/testApi", function(req, res){
parameters = [
{ name: 'CouponId', sqltype: sql.VarChar, value: req.body.CouponId }
];
var query = "INSERT INTO [Table_A] VALUES(#CouponId)";
executeQuery(res, query, parameters);
});
const PORT = process.env.PORT || 8080
app.listen(PORT, () => {
console.log(`App running on port ${PORT}`)
});
This is the code that usually works for an object. My question is: how can i send result (where result is the obtained array) on the API. I need to change something on my code on parameters?
Hope you can help me. I'm using Javascript, Node, Express and SQL Server.
How to post an array to Express API
In angular you simply do $http.post(url, data).
If you assign data to an object that has an array, it will reach express.
Then express can parse the body since you have app.use(express.bodyParser()); so the object should be available to you on the body.
URL Query Params
If you are trying to use query parameters, to pass an array, lets say on attribute items so you simply declare it multiple times
items=1&items=2&items=3 should be parsed to req.query.items === [1,2,3]

Data not correctly loaded with Node.js using express.js, fs and handlebars

I am kinda new to Node.js and experienced a strange behavior in my application.
At the beginning I am reading all uploaded files to my server using fs.readdir. Then the data is getting stored like this:
// Store all files and their data
var uploads = [];
var docData = [];
//read all files when server starts
fs.readdir(dir, function(err, items) {
if(err) {
console.log("Could not read files from directory " + dir);
}
else {
uploads = items;
uploads.forEach(function(item) {
var path = dir + item;
textract.fromFileWithPath(path, function( err, text ) {
if(err) {
console.log("Could not parse file " + path);
}
else {
var val = {
name : item,
data: text
};
docData.push(val);
}
});
});
}
});
So I store on the one hand the raw files and on the other hand the extracted text as json. But it does not load the files properly. It looks like the items are handed out to the frontend before these arrays are set, but I am not sure about this problem. The data is given to the frontend in this way:
app.get('/:search', function(req, res){
var result = [];
var invalidItems = 0;
for (var i = 0; i < docData.length; i++) {
if(!(stringStartsWith(docData[i].name,"."))) {
var index = i + 1 - invalidItems;
result.push({id: index, doc: docData[i].name, count: 3});
}
else{
invalidItems++;
}
}
res.send(result);
});
And the handlebars template using jade looks like this:
// Template for search results
script#result-template(type='text/x-handlebars-template')
table#data.table.table-striped.table-bordered
thead
tr
th ID
th Document
th Count
th Delete
tfoot
tr
th ID
th Document
th Count
th Delete
tbody
| {{#each this}}
tr
td {{id}}
td
a(href="/uploads/{{doc}}") {{doc}}
td {{count}}
td
span.glyphicon.glyphicon-trash
| {{/each}}
Is there any "clear" way to ensure that all the uploaded data has been parsed before sending the result to the frontend or do you think there is another stupid mistake?
Edit: The call in the js looks like that:
var needle = $('input[name=srch-term]').val();
$.ajax({
url: "http://localhost:1234/"+needle,
type: 'GET',
success: function (resp)
var source = $("#result-template").html();
var template = Handlebars.compile(source);
$("#result").html(template(resp));
},
error: function(e) {
alert('Error: '+e.text);
}
});
The complete app.js looks like this:
var express = require('express');
var path = require('path');
var http = require('http');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var elasticsearch = require('elasticsearch');
var multer = require("multer");
var fs = require('fs');
var textract = require('textract');
var app = express();
var upload = multer({ dest : './public/uploads'});
var dir = './public/uploads/';
// Store all files and their data
var uploads = [];
var docData = [];
//read all files when server starts
fs.readdir(dir, function(err, items) {
if(err) {
console.log("Could not read files from directory " + dir);
}
else {
uploads = items;
uploads.forEach(function(item) {
var path = dir + item;
textract.fromFileWithPath(path, function( err, text ) {
if(err) {
console.log("Could not parse file " + path);
}
else {
var val = {
name : item,
data: text
};
docData.push(val);
}
});
});
}
});
require('dotenv').load();
var client = new elasticsearch.Client({
host: process.env.ES_HOST,
log: 'trace'
});
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use(multer({ dest: './public/uploads/',
rename: function (fieldname, filename) {
//add the current date to the filename to allow multiple uploads
return filename + Date.now();
},
onFileUploadStart: function (file) {
console.log(file.originalname + ' is starting ...');
},
onFileUploadComplete: function (file) {
console.log(file.fieldname + ' uploaded to ' + file.path);
//add the uploaded file to the stored files
uploads.push(file);
textract.fromFileWithPath(file.path, function( error, text ) {
if(error) {
console.log("Could not parse file " + file.path);
}
else {
//add the uploaded file's text to the docData
var len = dir.length - 2;
var val = {
name : file.path.substring(len),
data: text
};
docData.push(val);
}
});
}
}));
app.post('/upload',function(req,res){
upload(req,res,function(err) {
if(err) {
return res.end("Error uploading file.");
}
res.redirect('/');
});
});
app.get('/:search', function(req, res){
var result = [];
var invalidItems = 0;
console.log("Data = " + docData.length);
for (var i = 0; i < docData.length; i++) {
if(!(stringStartsWith(docData[i].name,"."))) {
var index = i + 1 - invalidItems;
result.push({id: index, doc: docData[i].name, count: 3});
}
else{
invalidItems++;
}
}
console.log("data; " + docData.length);
res.send(result);
});
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
app.listen(process.env.SRV_PORT);
module.exports = app;
function stringStartsWith (string, prefix) {
var res;
try {
res = string.slice(0, prefix.length) == prefix;
}
catch(err) {
res = false;
}
return res;
}

Categories

Resources