I do not understand what this small block of code means - javascript

so after reading a dozen tutorials and posts, I figured that '/todo/'+item is the URL that this code sends the request to, but is the entire URL https://MyHomePageURL + '/todo/'+item? but when I entered that http url, the page was invalid. I entered basically any possible http URLs before and after every request I made and only "http://127.0.0.1:5000/todo" which is the homepage worked and no other URL worked. (for example, when the value of item is chair, this -> http://127.0.0.1:5000/todo/chair should work but it doesn't). Also is there any reason why this Ajax request has to be specifically sent to that specific https:// URL?
the code I'm specifically talking about is from the file "todo-list.js"
$(document).ready(function(){
$('form').on('submit', function(){
var item = $('form input');
var todo = {item: item.val()};
$.ajax({
type: 'POST',
url: '/todo',
data: todo,
success: function(data){
location.reload();
}
});
return false;
});
$('li').on('click', function(){
var item = $(this).text().replace(/ /g, "-");
$.ajax({
type: 'DELETE',
url: '/todo/' + item,
success: function(data){
location.reload();
}
});
});
});
and for broader context, here's the code file called "todoController.js"
var bodyParser = require('body-parser');
var data = [{item: 'chair'}, {item: 'flower'}, {item: 'bed'}];
var urlencodedParser = bodyParser.urlencoded({extended: false});
module.exports = function(app) {
app.get('/todo', function(req, res){
res.render('todo', {todos: data});
});
app.post('/todo', urlencodedParser, function(req, res){
data.push(req.body);
res.json(data);
});
app.delete('/todo/:item', function(req, res){
data = data.filter(function(todo){
return todo.item.replace(/ /g, '-') !== req.params.item;
});
res.json(data);
});
};
this is the main code that starts the app named "index.js".
var express = require('express');
var app = express();
var todoController = require('./todoController');
app.set('view engine', 'ejs');
app.use(express.static('./'));
todoController(app);
app.listen(5000, '127.0.0.1');
another code file working this app named "todo.ejs"
<html>
<head>
<title>Todo List</title>
<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-
CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
crossorigin="anonymous"></script>
<script src="assets/todo-list.js"></script>
<link href="assets/styles.css" rel="stylesheet"
type="text/css">
</head>
<body>
<h1>My Todo List</h1>
<div id="todo-table">
<form>
<input type="text" name="item" placeholder="Add new
item..." required />
<button type="submit">Add Item</button>
</form>
<ul>
<% for(var i=0; i < todos.length; i++){ %>
<li><%= todos[i].item %></li>
<% } %>
</ul>
</div>
</body>
</html>

When you type the URL in browser address bar and press enter, browser will make a GET request to the server. If you check your server code (second file you have provided) that URL /todo/:item only accepts DELETE request. That's why you are getting invalid page when you access that URL from browser. But the URL /todo has both GET and POST methods defined. That's why you got GET response defined in server when you hit that URL from the browser.

It's confusing but as I understand you want to understand the code here are my thoughts, ajax is making an HTTP DELETE request over the resource (i.e todo/:item)
$.ajax({
type: 'DELETE',
which at the server is received by the following the code
app.delete('/todo/:item', function(req, res){
If you run this in postman (not in the browser) with the appropriate setting you would be able to see it working. Hope it helps.

Related

Display output of fs.readdirSync() in front end HTML file

I am very new to node.js and have been googling for a solution to the problem stated in my question title above.
Basically I am building a simple web api that allows users to upload their files and then query them individually after that. So I am trying to figure out how to display the list of files in the server directory so instead of them remembering the exact file name, they can pick it from the list.
Here's my full html code project/public/index.html (EDIT - after answered by Oorja)
<!DOCTYPE html>
<html>
<head>
<script src="./node_modules/jquery/dist/jquery.min.js"></script>
</head>
<style>
.dropdown-content {
display: none;
position: absolute;
background-color: #f6f6f6;
min-width: 230px;
overflow: auto;
border: 1px solid #ddd;
z-index: 1;
}
.show {display:block;}
</style>
<body>
<h1>api service</h1>
<br>
<div id="upload_form">
<h3>Upload images</h3>
<form action="/api/uploadImages" method="post" enctype="multipart/form-data">
<input type="file" name="image" multiple="multiple"><br><br>
<input type="submit" value="Upload">
</form>
</div>
<div id="query_images">
<h3>Query images</h3>
<form action="/api/queryImages" method="get" enctype="text/plain">
<input type="text" name="image_name"><br><br>
<input type="submit" value="Query">
</form>
</div>
<div class="dropdown">
<button onclick="show_list()" class="dropbtn">Images</button>
<div id="image_list" class="dropdown-content">
<input type="text" placeholder="Search for your images..." id="userInput">
</div>
</div>
<script>
function show_list() {
var image_list = document.getElementById("image_list");
$.getJSON('http://localhost:8080/list-files', function(data) {
data.forEach(function(file) {
$(image_list).append($('' + file + ''));
})
});
}
</script>
</body>
</html>
And below is the javascript full code project/server.js (EDIT - after answered by Oorja)
var express = require('express'),
multer = require('multer'),
bodyParser = require('body-parser'),
path = require('path')
fs = require('fs');
var app = express();
var imageStorage = multer.diskStorage({
destination: function(req, file, callback) {
callback(null, './uploaded_files');
},
filename: function(req, file, callback) {
callback(null, file.fieldname + '_' + Date.now() + '_' + file.originalname);
}
});
var upload = multer({
storage: imageStorage,
fileFilter: function(req, file, callback) {
console.log('Checking file extension...');
var extension = path.extname(file.originalname);
if (extension == '.jpg' || extension == '.png' || extension == '.jpeg') {
console.log('Extension looks good!');
callback(null, true);
} else {
callback('Please upload images only!', false);
}
}
}).array('image');
app.use(bodyParser.json());
app.use('/uploaded_files', express.static('./upload_files'));
// define http methods handlers
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname, 'public', 'index.html'))
});
app.get('/list-files', function(req, res) {
var files = fs.readdirSync('./uploaded_files');
res.json(files);
})
app.get('/api/queryImages', function(req, res) {
var imageName = req.query.image_name
console.log(imageName);
res.sendFile(path.join(__dirname, 'uploaded_files', imageName));
});
app.post('/api/uploadImages', function(req, res) {
upload(req, res, function(err) {
if (err) {
console.log(err);
return res.end('Something went wrong!');
}
console.log('Upload successful!')
res.send('Successfully uploaded images!');
});
});
app.listen(port=8080, function(a) {
console.log('Listening to port ' + port);
});
The javascript works /list-files as I can see the list of files in my console or if I go to /list-files url, however, I cannot figure out how to send the output to front end - I don't know how to connect them - so then when I click on the button under div class="dropdown" they will appear as a list <a> element.
Could someone please point me in the right direction or even better, give me an example?
Thank you in advance!
EDIT
Output of files from the javascript above /list-files is as below
[ '.DS_Store',
'Screen Shot 2018-06-02 at 2.15.10 pm.png',
'aaa.png',
'bbb.png',
'ccc.png',
'ddd.png',
'eee.png' ]
Also, to clarify, I am using Express framework to build this web api.
Once you have the list of files ready, make an API end-point for it. Say, /get-files. Assuming you're using express as a node.js server, you can do this -
const express = require('express');
const fs = require('fs');
const app = express();
// Makes your upload_files directory public. Don't use this in a real app.
// Create a separate route to serve file data. This is just for brevity of code.
app.use('/upload_files', express.static('./upload_files'))
app.get('/get-files', (req, res) => {
// your logic of getting file names
const files = fs.readdirSync('./upload_files');
res.json(files);
});
app.listen(3000); // start a server at localhost:3000
Now, on your frontend, you can open an XHR GET request to fetch the name of files you have on the node.js server like so -
function show_list() {
var image_list= document.getElementById('image_list');
// Assuming you have jQuery as well...
$.getJSON('http://localhost:3000/get-files', function (data) {
data.forEach(file => {
// Do something with the file name
$(image_list).append($('' + file + ''));
})
});
}
You can read more about Express here.
You can also do what Tamas has done with Server-side templating. It will send the data along with the HTML file but I doubt if that is what you asked for.
You should try a template engine like EJS.
Example usage if you use express:
EJS uses the views folder in root for html files default, so create it and put your index.html there.
0. Install EJS: npm install ejs
1. Include EJS in express: app.set('view engine', 'ejs');
2. Add to your route: res.render('index', {files: files});
3. Get it in HTML, modify your index.html (put it where you need):
<% for (var i = 0; i < files.length; i++) { %>
<%= files[i] %>
<% }; %>
Or if you need it as a JS variable use:
<script> var files = <%- JSON.stringify(files) %>; </script>
More information

get() method or function

Unresolved function or method get().
I'm new in js and node and I got stuck with this while trying to make a chat using sockets. Here is the code:
.js
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
server.listen(8888);
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
io.sockets.on('connection', function (socket) {
socket.on('send message', function (data) {
io.sockets.emit('new message', data);
});
});
.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>glupi chat</title>
<style>
#chat{
height: 500px;
}
</style>
</head>
<body>
<div id="chat"></div>
<form id="send-message">
<input size="35" id="message">
<input type="submit">
</form>
<script src='jquery-3.2.1.js'></script>
<script src="/socket.io/socket.io.js"></script>
<script>
$document.ready(function () {
var socket = io.connect();
var $messageForm = $('#send-message');
var $messageBox = $('#message');
var $chat = $('#chat');
$messageForm.submit(function (e) {
e.preventDefault();
socket.emit('send message', $messageBox.val());
$messageBox.val('');
});
socket.on('new message', function (data) {
$chat.append(data + "<br/>");
});
});
</script>
</body>
</html>
I'm using IntelliJ IDEA, I have every module and library that I need installed.
It appears that you have no route for the jQuery file you specify with this:
<script src='jquery-3.2.1.js'></script>
A nodejs express server does not server ANY files by default so unless you have a general purpose route for your static files or a specific file for that jQuery file, your express server will not know how to serve that file when the browser requests it.
You have several possible choices for how to fix that:
Change the jQuery URL in the script tag in your web page to point to one of the public CDNs for jQuery. There are often performance advantages to doing this. For example, you could change to this: <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>.
Use express.static() on your server to configure a directory of static assets that will be automatically served by express when requested by the browser.
Create a specific route for the jQuery file just like you did with your exist app.get('/', ...)that responds to the/` GET request.

Parsing RSS feed with node.js

I'm trying to get rss to work with node, but it does nothing for me.
Sorry for such a noob question, I've been struggling with this for a while.
Here's my server.js
var express = require('express'),
app = express(),
server = require('http').createServer(app),
RSS = require('rss')
server.listen(3000);
app.set('views', __dirname, 'views');
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
/* lets create an rss feed */
var feed = new RSS({
title: 'Feed',
feed_url: 'https://www.rt.com/rss/',
site_url: 'https://www.rt.com/',
language: 'en'
});
/* loop over data and add to feed */
feed.item({
title: 'item title',
// description: 'use this for the content. It can include html.',
// url: 'https://www.rt.com/rss/', // link to the item
// guid: '1123', // optional - defaults to url
});
// cache the xml to send to clients
var xml = feed.xml();
And here's my index.html
<html>
<head>
<title>Feed</title>
</head>
<body>
<h1>Feed</h1>
<div id="content"></div>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
var content = <%= feed.item %>;
var <%= feed.item %> = "true";
</script>
</body>
</html>
When I run node server.js, there's only the h1 title in the index page.

Express' render/redirect does not work if the call isn't coming from a submit method in a form

Task
Perform a POST request from a JS method, so that variable values can be sent as parameters.
Environment
NodeJS
Express
BodyParser
ejs
My first attempt
Frontend:
<html>
<head>
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js'></script>
<script type="text/javascript">
function postAnswer() {
$.post('vote', { message: "hello!"}, function(returnedData) {
console.log("Post returned data: " + returnedData);
});
}
</script>
</head>
<body>
<button id='send' onClick='postAnswer()' class='btn btn-success btn-xs'>Svara</button>
</body>
</html>
Server.js:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser());
require('./app/routes.js')(app);
app.set('view engine', 'ejs');
app.use('/public', express.static(__dirname + '/public'));
var server = require('http').createServer(app);
server.listen(8080);
console.log('Server running on port 8080...');
routes.js:
module.exports = function(app) {
app.get('/', function(req, res) {
res.render('vote.ejs', {
message: ''
});
});
app.post('/vote', function(req, res) {
var msg = req.body.message;
console.log("Got POST request with message: " + msg);
res.render('index.ejs', {
message: ''
});
});
};
Result:
The render method won't render a new page. It will however return the entire 'index.ejs' file in the returnedData parameter.
Server:
Client:
Second attempt:
<html>
<head>
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js'></script>
<script type="text/javascript">
function postAnswer() {
$.post('vote', { message: "hello!"}, function(returnedData) {
console.log("Post returned data: " + returnedData);
});
return false;
}
</script>
</head>
<body>
<form action='/vote' method='post'>
<button id='send' type='submit' onsubmit='return postAnswer()' class='btn btn-success btn-xs'>Svara</button>
</form>
</body>
</html>
Result:
This does work, but it's not a very clean solution.
My questions:
Why doesn't the first attempt work?
How can I send variables as parameters to a POST request with a nice clean solution?
I'm not a jQuery expert, but I think the first attempt doesn't work because $.post makes an AJAX request, the same way as you would in a single-page app to interact with an API in the background.
Your second example submits a form, which is an in-browser action that performs a navigation action (as specified by the method attribute of the form). In this case, the event listener you add in jQuery is redundant, and should be removed - it's making another background POST request, before the form submits the content of its fields in its request.
As for your second question, the way to submit additional variables with a form submission (presuming that you actually want to do a navigating form submission and not an XHR background request against an API) is to use <input type="hidden"> elements.
So, to summarize, to do what you're describing in your question, your example HTML should look like this (minus the comments):
<!DOCTYPE html> <!-- only you can prevent quirks mode -->
<html>
<head>
<meta charset="UTF-8"> <!-- ༼ つ ◕_◕ ༽つ Give UNICODE -->
</head>
<body>
<form action='/vote' method='post'>
<input type="hidden" name="message" value="hello!">
<button id='send' type='submit' class='btn btn-success btn-xs'>Svara</button>
</form>
</body>
</html>

triggering a Get request with document.body.appendChild()

We can exchange strings between our express server and a client website (even cross domain) with this code (works perfectly) :
app.js:
var express = require("express");
var app = express();
var fs=require('fs');
var stringforfirefox = 'hi buddy!'
app.get('/getJSONPResponse', function(req, res) {
res.writeHead(200, {'Content-Type': 'application/javascript'});
res.end("__parseJSONPResponse(" + JSON.stringify( stringforfirefox) + ");");
});
app.listen(8001)
index.html:
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.js"></script>
<script>
function __parseJSONPResponse(data) { alert(data); }
document.onkeypress = function keypressed(e){
if (e.keyCode == 112) {
var script = document.createElement('script');
script.src = 'http://localhost:8001/getJSONPResponse';
document.body.appendChild(script); // triggers a GET request ??????
}
}
</script>
<title></title>
</head>
<body>
</body>
</html>
We use document.createElement() and document.body.appendChild() to trigger a Get request as the highest voted answer here suggested.
Our question: is it fine to create a new Element with evey request, because we plan to make a lot of requests with this. Could that cause any problems. Or should we clear such an Element after we received the response?

Categories

Resources