node.js ajax express show restful data on a web page - ajax

I am newbie in node.js development and I have a particular problem. I want to create a one page web app with node.js which will the user will submit request data and then gets data back from imdb api and will show them on the same page. My code is the following
server.js
#!/usr/bin/env node
var express = require('express');
var app = express();
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
var fs = require('fs');
var inputFile = fs.readFileSync('index.html').toString();
console.log(inputFile);
app.get('/', function(request, response) {
response.send(inputFile);
});
var port = process.env.PORT || 8080;
app.listen(port, function() {
console.log("Listening on " + port);
})
app.post('/', function(req, res){
if (req.body.mysearch == ""){
var search = "heroes";
}else{
var search = req.body.mysearch;
}
console.log(search);
var http = require('http');
http.get("http://www.imdbapi.com/?t=" + search, function(res) {
console.log("Got response: " + res.statusCode);
var data = '';
res.on('data', function (chunk){
data += chunk;
})
res.on('end',function(){
// the whole of webpage data has been collected. parsing time!
var obj = JSON.parse(data);
console.log( obj.Title );
})
}).on('error', function(e) {
console.log("Got error: " + e.message);
})
});
index.html
<html>
<head>
<meta charset="utf-8">
<title>Title of the document</title>
</head>
<body>
<form id="myform" method="post" action="/"enctype="application/x-www-form-urlencoded">
<input type="text" id="search" name="mysearch">
<input type="submit" id="mysubmit" value="Search IMDB">
</form>
<div id="myTitle">
</div>
</body>
</html>
The code so far has successfully parsing the data from imdb and shows them on the console. The question is how I am going to print them on the web page (e.g on the div tag) without reload the page (ajax)

I had a similar question regarding re-rendering of div that got answered
how-to-re-render-html-div-in-node-js
Basically solution was to use client side frameworks like Angular.js to help in re-rendering via 2 way data binding.

Related

Why does 'import socket.io' doesn't work for me?

I'm learning Socket.io and practicing the demo tutorial with individual client side script file.
However, it didn't work as expected.
Here is my code.
client side HTML: index.html
<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
<ul id="messages"></ul>
<form id="form" action="">
<input id="input" autocomplete="off" /><button>Send</button>
</form>
<script src="./app.js"></script>
</body>
</html>
client side JS: app.js
import { io } from "socket.io-client";
var socket = io('http://localhost:3000');
var messages = document.getElementById('messages');
var form = document.getElementById('form');
var input = document.getElementById('input');
form.addEventListener('submit', function(e) {
e.preventDefault();
if (input.value) {
socket.emit('chat message', input.value);
input.value = '';
}
});
socket.on('chat message', function(msg) {
var item = document.createElement('li');
item.textContent = msg;
messages.appendChild(item);
window.scrollTo(0, document.body.scrollHeight);
});
server side JS: index.js
const app = require('express')();
const http = require('http').Server(app);
const io = require('socket.io')(http);
const port = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
console.log('a new user join: ', socket.id);
socket.on('chat message', msg => {
io.emit('chat message', msg);
});
});
http.listen(port, () => {
console.log(`Socket.IO server running at http://localhost:${port}/`);
});
After node index to execute my server and open localhost:3000 on my browser, the console.log should tells 'a new user join: xxx', but it didn't.
Is there anything wrong with client side app.js?

ExpressJS XMLHttpRequest Routing Error

I have an issue where I am trying to pass my file information in query parameter form to the route that I have set up to upload my AWS file and then return the url. The issue I am running into is that the form is located within the view file accessed with the /create/comment route and prepended to all of my routes is /app. In my XMLHttpRequest I am requesting /app/sign and the file query parameters, but for some reason it keeps prepending this with /app/create or /app/create/app/sign, which is why I have 404 error. Is there a way a specific method to prevent the prepending of /app/create?
Error function at xhr.send();
function sign_request(file, done) {
var xhr = new XMLHttpRequest();
console.log(xhr);
console.log(file);
xhr.open("GET", "app/sign?file_name=" + file.name + "&file_type=" + file.type);
xhr.onreadystatechange = function() {
if(xhr.readyState === 4 && xhr.status === 200) {
var response = JSON.parse(xhr.responseText);
console.log(response);
done(response);
}
};
xhr.send();
};
Error Message:
comment:139 GET http://localhost:3000/app/create/app/sign?file_name=File-name.png&file_type=image/png 404 (Not Found)
Here is my route setup:
var express = require('express');
var router = express.Router();
router.use('/app');
var config = require(path.resolve(__dirname, '..', '..','./config/config.js'));
var models = require('../models/db-index');
var fs = require('fs');
var aws = require('aws-sdk');
/*==== /SIGN ====*/
router.get('/sign', function(req, res){
aws.config.update({accessKeyId: config.awsAccessKeyId, secretAccessKey: config.awsSecretAccessKey});
var s3 = new aws.S3()
var options = {
Bucket: config.awsBucket,
Region: 'us-east-1',
Key: req.query.file_name,
Expires: 60,
ContentType: req.query.file_type,
ACL: 'public-read'
}
s3.getSignedUrl('putObject', options, function(err, data){
if(err) return res.send('Error with S3')
res.json({
signed_request: data,
url: 'https://s3.amazonaws.com/' + S3_BUCKET + '/' + req.query.file_name
});
});
});
router.get('/create/comment',function(req, res){
models.DiscoverySource.findAll({
where: {
organizationId: req.user.organizationId
}, attributes: ['discoverySourceName']
}).then(function(discoverySource){
res.render('pages/app/comment-create.hbs',{
discoverySource: discoverySource
});
});
});
Form (Accessed at /app/create/comment):
<!DOCTYPE html>
<head>
{{> app/app-head}}
</head>
<body>
{{> app/app-navigation}}
<div class="container">
<div class="col-md-12">
<div class="row-form-container">
<label for="report-link">File Attachment:</label>
<input type="file" name="fileAttachment" id="image">
<img id="preview">
</div>
</div>
<script type="text/javascript">
function upload(file, signed_request, url, done) {
var xhr = new XMLHttpRequest();
xhr.open("PUT", signed_request);
xhr.setRequestHeader('x-amz-acl', 'public-read');
xhr.onload = function() {
if (xhr.status === 200) {
done();
};
};
xhr.send(file);
}
function sign_request(file, done) {
console.log('work please');
var xhr = new XMLHttpRequest();
console.log(xhr);
console.log(file);
xhr.open("GET", "app/sign?file_name=" + file.name + "&file_type=" + file.type);
xhr.onreadystatechange = function() {
if(xhr.readyState === 4 && xhr.status === 200) {
var response = JSON.parse(xhr.responseText);
console.log(response);
done(response);
}
};
xhr.send();
};
document.getElementById("image").onchange = function() {
var file = document.getElementById("image").files[0]
if (!file) return
sign_request(file, function(response) {
upload(file, response.signed_request, response.url, function() {
document.getElementById("preview").src = response.url
});
});
};
</script>
</body>
Adding a / before app/sign when you send a request will prevent the prepending of current subpath.
Try:
xhr.open("GET", "/app/sign?file_name=" + file.name + "&file_type=" + file.type);

Node server to echo POST/URL parameters in real time

I'm working on a project where I'm sending temperature data via Arduino to a Node server. Arduino sends data to the server through URL parameters:
http://localhost:3000/submit?temprature=25
I'm then fetching the posted data using the following Node server.js
var express = require('express');
url = require('url');
var app = express();
app.get('/submit', function(req, res){
var data = url.parse(req.url,true).query;
console.log(data);
});
app.listen(3000, function(){
console.log('listening on *:3000');
});
I'm able to show the required data with console.log(), but what I want is, as soon as Arduino sends the data through URL parameters, that data should automatically echo/print on the server: http://localhost:3000/index.html like in real time. How can I achieve this?
You can use socket.io to emit events every time the temperature is updated by your arduino device:
var http = require('http');
var url = require('url');
var express = require('express');
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server); //pass a http.Server instance
server.listen(3000);
app.get('/submit', function(req, res){
var data = url.parse(req.url,true).query;
io.emit('temperature', data);
res.send('Temperature Updated to: ' + data.temperature);
});
app.get('/index', function(req, res){
res.sendFile(__dirname + '/public/index.html');
});
Then on the client side, you can listen for events and update the information. This is public/index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Socket.IO Temperature Example</title>
<link rel="stylesheet" href="style.css">
<script src="https://cdn.socket.io/socket.io-1.3.5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-alpha1/jquery.min.js"></script>
</head>
<body>
<h1 id="temperature"></h1>
<script>
var socket = io('http://localhost:3000');
socket.on('temperature', function (data) {
console.log(data);
$('h1#temperature').html(data.temperature);
});
</script>
</body>
</html>

complex nodejs url mapping

I need help in url mapping in express.js framework in nodejs.
router.get('/first/:second_param', function(res,req){
//processing second_param and rendering a template,
res.render('first.html');
});
router.get('/first/:second_param/get_items', function(res,req){
//again evaluating second_param and and responding accordingly
res.send(jsonData);
});
Is this kind of routing possible in Express 4.0?
first.html makes a ajax request at url './get_items'
Yes, it is possible to do it with Express 4.0.
Here is an example:
you need to install ejs and express: npm install ejs express
app.js file:
var express = require('express');
var app = express();
app.set('view engine', 'ejs');
app.get('/', function(req, res) {
res.redirect('/home/2');
});
app.get('/home/:itemId', function(req, res) {
var itemId = req.params.itemId;
console.log(itemId);
res.render('index');
});
app.get('/api/items/:itemId', function(req, res) {
var itemId = req.params.itemId;
console.log('item id: %s', itemId);
res.json([{name: 'item1'}]);
});
app.listen(8080, function() {
console.log('server up and running at 8080');
});
views/index.ejs file:
<!doctype html>
<html>
<head>
</head>
<body>
<h1>Hello World!</h1>
<script>
function responseGET() {
if(this.readyState !== 4 || this.status !== 200) return;
alert(this.responseText);
}
function getItems(URL) {
var request = new XMLHttpRequest();
request.open('GET', URL, true);
request.onreadystatechange = responseGET.bind(request);
request.send(null);
}
function domReady() {
getItems('http://localhost:8080/api/items/1');
}
document.addEventListener('DOMContentLoaded', domReady);
</script>
</body>
</html>
Basically I am have a server which is serving an index.html when someone requests at /home/:itemId and also I am exposing another route for serving items /api/items/:itemId.
From the client side once the DOM is ready I am requesting to /api/items/:itemId some items which then are displayed in the index html.

PhoneGap upload Image to server on form submit

I am facing problem here as in phonegap image is uploaded to the server once u select a picture.I don't want to upload image before submitting form. Image is uploaded automatically to server which is something i don't want.I want to upload image with the form, where form contains many more fields which is required to send along with image. What are the possible ways to submit with form?
<!DOCTYPE HTML >
<html>
<head>
<title>Registration Form</title>
<script type="text/javascript" charset="utf-8" src="phonegap-1.2.0.js"></script>
<script type="text/javascript" charset="utf-8">
// Wait for PhoneGap to load
document.addEventListener("deviceready", onDeviceReady, false);
// PhoneGap is ready
function onDeviceReady() {
// Do cool things here...
}
function getImage() {
// Retrieve image file location from specified source
navigator.camera.getPicture(uploadPhoto, function(message) {
alert('get picture failed');
},{
quality: 50,
destinationType: navigator.camera.DestinationType.FILE_URI,
sourceType: navigator.camera.PictureSourceType.PHOTOLIBRARY
});}
function uploadPhoto(imageURI) {
var options = new FileUploadOptions();
options.fileKey="file";
options.fileName=imageURI.substr(imageURI.lastIndexOf('/')+1);
options.mimeType="image/jpeg";
var params = new Object();
params.value1 = "test";
params.value2 = "param";
options.params = params;
options.chunkedMode = false;
var ft = new FileTransfer();
ft.upload(imageURI, "http://yourdomain.com/upload.php", win, fail, options);
}
function win(r) {
console.log("Code = " + r.responseCode);
console.log("Response = " + r.response);
console.log("Sent = " + r.bytesSent);
alert(r.response);
}
function fail(error) {
alert("An error has occurred: Code = " = error.code);
}
</script>
</head>
<body>
<form id="regform">
<button onclick="getImage();">select Avatar<button>
<input type="text" id="firstname" name="firstname" />
<input type="text" id="lastname" name="lastname" />
<input type="text" id="workPlace" name="workPlace" class="" />
<input type="submit" id="btnSubmit" value="Submit" />
</form>
</body>
</html>
Create two functions you can call separately. One function for just getting the image, and another function to upload the image.
You can do something like below.
<!DOCTYPE html>
<html>
<head>
<title>Submit form</title>
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
<script type="text/javascript" charset="utf-8">
var pictureSource; // picture source
var destinationType; // sets the format of returned value
// Wait for device API libraries to load
//
document.addEventListener("deviceready",onDeviceReady,false);
// device APIs are available
//
function onDeviceReady() {
pictureSource = navigator.camera.PictureSourceType;
destinationType = navigator.camera.DestinationType;
}
// Called when a photo is successfully retrieved
//
function onPhotoURISuccess(imageURI) {
// Show the selected image
var smallImage = document.getElementById('smallImage');
smallImage.style.display = 'block';
smallImage.src = imageURI;
}
// A button will call this function
//
function getPhoto(source) {
// Retrieve image file location from specified source
navigator.camera.getPicture(onPhotoURISuccess, onFail, { quality: 50,
destinationType: destinationType.FILE_URI,
sourceType: source });
}
function uploadPhoto() {
//selected photo URI is in the src attribute (we set this on getPhoto)
var imageURI = document.getElementById('smallImage').getAttribute("src");
if (!imageURI) {
alert('Please select an image first.');
return;
}
//set upload options
var options = new FileUploadOptions();
options.fileKey = "file";
options.fileName = imageURI.substr(imageURI.lastIndexOf('/')+1);
options.mimeType = "image/jpeg";
options.params = {
firstname: document.getElementById("firstname").value,
lastname: document.getElementById("lastname").value,
workplace: document.getElementById("workplace").value
}
var ft = new FileTransfer();
ft.upload(imageURI, encodeURI("http://some.server.com/upload.php"), win, fail, options);
}
// Called if something bad happens.
//
function onFail(message) {
console.log('Failed because: ' + message);
}
function win(r) {
console.log("Code = " + r.responseCode);
console.log("Response = " + r.response);
//alert("Response =" + r.response);
console.log("Sent = " + r.bytesSent);
}
function fail(error) {
alert("An error has occurred: Code = " + error.code);
console.log("upload error source " + error.source);
console.log("upload error target " + error.target);
}
</script>
</head>
<body>
<form id="regform">
<button onclick="getPhoto(pictureSource.PHOTOLIBRARY);">Select Photo:</button><br>
<img style="display:none;width:60px;height:60px;" id="smallImage" src="" />
First Name: <input type="text" id="firstname" name="firstname"><br>
Last Name: <input type="text" id="lastname" name="lastname"><br>
Work Place: <input type="text" id="workplace" name="workPlace"><br>
<input type="button" id="btnSubmit" value="Submit" onclick="uploadPhoto();">
</form>
</body>
</html>
You're already sending custom fields in your example.
var params = new Object();
params.value1 = "test";
params.value2 = "param";
options.params = params;
Just populate params with your form fields.
I also faced same problem, but I have done using two server side calls on one click. In this, in first call submit data and get its id in callback using JSON then upload image using this id. On server side updated data and image using this id.
$('#btn_Submit').on('click',function(event) {
event.preventDefault();
if(event.handled !== true)
{
var ajax_call = serviceURL;
var str = $('#frm_id').serialize();
$.ajax({
type: "POST",
url: ajax_call,
data: str,
dataType: "json",
success: function(response){
//console.log(JSON.stringify(response))
$.each(response, function(key, value) {
if(value.Id){
if($('#vImage').attr('src')){
var imagefile = imageURI;
$('#vImage').attr('src', imagefile);
/* Image Upload Start */
var ft = new FileTransfer();
var options = new FileUploadOptions();
options.fileKey="vImage";
options.fileName=imagefile.substr(imagefile.lastIndexOf('/')+1);
options.mimeType="image/jpeg";
var params = new Object();
params.value1 = "test";
params.value2 = "param";
options.params = params;
options.chunkedMode = false;
ft.upload(imagefile, your_service_url+'&Id='+Id+'&mode=upload', win, fail, options);
/* Image Upload End */
}
}
});
}
}).done(function() {
$.mobile.hidePageLoadingMsg();
})
event.handled = true;
}
return false;
});
On server side using PHP
if($_GET['type'] != "upload"){
// Add insert logic code
}else if($_GET['type'] == "upload"){
// Add logic for image
if(!empty($_FILES['vImage']) ){
// Copy image code and update data
}
}
I could not get these plugins to upload a file with the other answers.
The problem seemed to stem from the FileTransfer plugin, which states:
fileURL: Filesystem URL representing the file on the device or a data URI.
But that did not appear to work properly for me. Instead I needed to use the File plugin to create a temporary file using the data uri to get me a blob object: in their example, writeFile is a function which takes a fileEntry (returned by createFile) and dataObj (blob). Once the file is written, its path can be retrieved and passed to the FileTransfer instance. Seems like an awful lot of work, but at least it's now uploading.

Resources