I'm trying to parse user input from my webpage and store it in a JSON object using inline JavaScript, make a POST request to my Node.js server, and access the contents of the request.
In my example.html, I have a function which does the following:
var xhttp = new XMLHttpRequest();
dataToSubmit = [];
// find some inputs
for ( /* each row of input */ ) {
dataToSubmit.push({
'item': itemName,
'quantity': quantity,
'price': itemPrice
});
}
xhttp.open("POST", "http://localhost:8080/menu", true);
xhttp.setRequestHeader('Content-Type', 'application/json');
xhttp.send(JSON.stringify(dataToSubmit));
EDIT :
After the POST request, I have a dispatcher.js file that processes the requests:
function(request, response) {
var qs = require('querystring');
var requestBody = '';
request.on('data', function(data) { requestBody += data; });
request.on('end', function() {
var qs = require('querystring');
var passed_data = qs.parse(requestBody);
if(request.url === "/menu") {
var menu_handler = require("./menu.js");
menu_handler.processOrder(passed_data);
}
}
I'm exporting processOrder() from my menu.js. The issue is that on the server-side, I have to do the following in order to access the object:
processOrder: function(data) {
for (var a in data) { <-------------- Having to do this seems incorrect
// a is a string, inputs is the expected object
var inputs = JSON.parse(a);
}
}
My question is: is the way I'm creating the JSON object incorrect, or is the way I'm accessing it on the server-side incorrect? My expectation is that, on the server-side, I should be able to do something like this:
processOrder: function(data) {
var inputs = JSON.parse(data);
for (var input in inputs) {
// access to input.item, input.quantity, input.price
}
}
Make dataToSubmit an object:
dataToSubmit = {};
For each input row, add a uniquely keyed property to your dataToSubmit, and assign it an object:
dataToSubmit['keyName' + index] = {}
Assign this new object properties like:
dataToSubmit['keyName' + index]['item'] = itemName;
dataToSubmit['keyName' + index]['quantity'] = quantity;
dataToSubmit['keyName' + index]['price'] = itemPrice;
The cause of me not being able to access the dataToSubmit variable as a JSON object was that I was doing parsing at a previous layer before the data reached the processOrder function. The solution was to make the following changes in my dispatcher.js file (which processes the requestBody before it makes its eventual way to menu.js):
function(request, response) {
var qs = require('querystring');
var requestBody = '';
request.on('data', function(data) { requestBody += data; });
request.on('end', function() {
var qs = require('querystring');
var passed_data;
if(request.headers['content-type'] === 'application/json') { <--- parse JSON data
passed_data = JSON.parse(requestBody);
else {
passed_data = qs.parse(requestBody);
}
if(request.url === "/menu") {
var menu_handler = require("./menu.js");
menu_handler.processOrder(passed_data);
}
}
Furthermore, when creating the JSON object, the following needed to be done in order to access the data as a JSON object rather than as an array:
dataToSubmit = {'content': []};
dataToSubmit['content'].push(
{
'item': itemName,
'quantity': quantity,
'price': itemPrice
}
);
Related
I'm adding a contact me section to a website. I want to be able to send the data from the forms with JS, and then receive and do something with the data with Node. I understand that there are frameworks and libraries that can handle this stuff, but I would like to build it from scratch so that I have a better understanding of what is happening.
I currently have a section of JS (see below) that is taking the form data, and sending it as a POST request to the node script, but I can't seem to wrap my head around what is happening with node, or how to receive the data with the node script. Any help in pointing me in the right direction is greatly appreciated.
const name = $(".name");
const email = $(".email");
const message = $(".message");
const submitButton = $(".submitButton");
const nameRegex = /([a-zA-Z\s-])/g;
const emailRegex = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/g;
const messageRegex = /([a-zA-Z\s.,?!$%&])/gm;
const url = "../node/contactMeSubmissionHandler.js"
submitButton.click(function(){
let nameContents = name.val().match(nameRegex).join("");
let emailContents = email.val().match(emailRegex).join("");
let messageContents = message.val().match(messageRegex).join("");
// if (emailRegex.test(emailContents) == true) {
// let emailValid = emailContents;
// } else {
// console.log("Email is invalid");
// };
const data = {
email: emailContents,
name: nameContents,
message: messageContents
}
$.post(url, data, function(data, status){
console.log(`${data} and status is ${status}`);
})
})
I like to write from scratch too. Here is working code which is called from a command line to get a token.
// clientEx.js
var http = require('http');
var fs = require('fs');
const _SERVER = "dcsmail.net"; /* dcsmail.net */
// Callback function is used to deal with response
//
var callback = function (response)
{
// update stream with data
var body = '';
response.on('data', function(data) {
body += data;
});
response.on ('end', function()
{
// Data received completely.
fs.writeFileSync ("temp.lst", body, 'utf8');
// console.log ("clientEx.js received: " + body);
});
}
if ((process.argv[2] == null) || (process.argv[3] == null) || (process.argv[4] == null) || (process.argv[5] == null))
{
console.log ("clientEx.js usage:<user email> <user password> <destination> <GUID>");
}
else
{
var Ef_email = encodeURI (process.argv[2]);
var Ef_pass = encodeURI (process.argv[3]);
var Ef_dest = encodeURI (process.argv[4]);
var Ef_guid = encodeURI (process.argv[5]);
var post_data = ("f_email=" + Ef_email +
"\&" + "f_pass=" + Ef_pass +
"\&" + "f_dest=" + Ef_dest +
"\&" + "f_guid=" + Ef_guid);
// Options to be used by request
var options = {
host: _SERVER,
port: '80',
path: '/DCSM/tokenP10.php',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength (post_data)
}
};
// console.log ("clientEx.js using " + _SERVER + ":" + options.port + options.path);
// request the token from the host
try
{
var req = http.request (options, callback);
req.write (post_data);
req.end();
}
catch (error)
{
fs.writeFileSync ("temp.lst", "Host access failed\n", 'utf8');
}
}
You should be able to adapt that to your needs.
Use this code to create a server and check the log in console for different request attributes.
const http = require('http');
http
.createServer((request, response) => {
console.log(request);
response.end();
})
.listen(3000);
Make GET and POST request to http://localhost:3000/ and look for method, headers etc.
See more here and here.
My receive() function parses through data from a backend server and I use that data to create a renderHTML() function which displays the parsed data as an HTML string. I get the data to display and can also attach checkboxes perfectly fine. I am trying to get the value of questionid so that when the user clicks on the checkbox, I can use Ajax to send the values of which question was selected, which can be done by questionid. I am not sure on how to get the value of the questionid, store it, and send it through Ajax.
function receive() {
var text = document.getElementById("text").value;
var data = {
'text': text
};
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
var ourData = xhr.responseText;
var parsedData = JSON.parse(ourData);
console.log(parsedData);
renderHTML(parsedData);
}
};
xhr.open("POST", "URL", true);
xhr.send(JSON.stringify(data));
}
var questionid;
function renderHTML(data) {
var htmlString = "";
for (i = 0; i < data.length; i++) {
htmlString += "<p><input type='checkbox' value='data[i].questionid'>" +
data[i].questionid + "." + "\n";
htmlString += '</p>';
}
response.insertAdjacentHTML('beforeend', htmlString);
var t = this;
var checkboxes = document.querySelectorAll('input[type="checkbox"]');
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].onclick = function() {
if (this.checked) {
console.log(this.questionid.value);
}
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
var Data = xhr.responseText;
console.log(Data);
var parseData = JSON.parse(Data);
};
xhr.send(JSON.stringify(data));
}
}
}
There are many ways in which you can achieve what you are looking for. For that, you will need to understand one of two concepts:
bind
closures
None of them is easy to understand for beginners but will help you vastly improve your coding skills once you get them. You can read about them here and here respectively.
The problem with your code (amongst other details) is that the value of i is global, and so by the time the DOM is rendered and the user can click in one of the checkboxes, all the checkboxes have the same value of i (the last one).
bind helps you solve this by setting an argument to the function that will always remain the same.
closures help you solve this by storing the value of a variable declared in a scope that is accessible only from a function that stores a reference to that variable.
Here is some code I wrote that does what you want using a most modern syntax, which I would highly recommend.
Specially, I would recommend you to read about the fetch api; which is a much cleaner way to make http request.
This code does what you are looking for:
function receive() {
const text = document.getElementById('text').value;
const options = {
method: 'POST',
body: JSON.stringify({ text })
}
fetch("<the url here>", options)
.then( response => response.json())
.then( data => {
renderHTML(JSON.parse(data));
})
}
function renderHTML(data){
for (const x of data) {
const content = x.questionid;
// i'm asuming that the response html element already exists
response.insertAdjacentHTML('beforeend', `<p><input value="${content}" type="checkbox">${content}</p>`);
}
document.querySelectorAll('input[type="checkbox"]').forEach( input => {
input.addEventListener((e) => {
const options = {
method: 'POST',
body: JSON.stringify(e.target.value)
};
fetch('<the second url here>', options).then( response => response.json())
.then( data => {
// 'data' is the response you were looking for.
})
})
})
}
I am writing a test and would like for prototypejs to read from a text file and store variables. Is this possible and what am I doing wrong?
Selenium.prototype.doLoadData = function(dataFile) {
new Ajax.Request('dataFile', {
method:'get',
onSuccess: function(data) {
var lines = data.split("\n");
lines.each(lines, function(i) {
var line = lines[i].split(' = ');
window[line[0]] = line[1];
globalStoredVars[line[0]] = line[1];
});
}
}
);
};
PrototypeJS passes the AJAXTransport object to the success callback, not just the data. Try this
onSuccess: function(resp){
var data = resp.responseText;
//or if your response contains JSON
//and the Content-Type: application/json header was sent in the response
var data = resp.responseJSON;
}
Firstly, here is my code as I've progressed so far:
var http = require("http");
// Utility function that downloads a URL and invokes
// callback with the data.
function download(url, callback) {
http.get(url, function(res) {
var data = "";
res.on('data', function (chunk) {
data += chunk;
});
res.on("end", function() {
callback(data);
});
}).on("error", function() {
callback(null);
});
}
var cheerio = require("cheerio");
var url = "http://www.bloglovin.com/en/blogs/1/2/all";
var myArray = [];
var a = 0;
var getLinks = function(){download(url, function(data) {
if (data) {
// console.log(data);
var $ = cheerio.load(data);
$(".content").each(function(i, e) {
var blogName = $(e).find(".blog-name").text();
var followLink = $(e).find("a").attr("href");
var blogSite = $(e).find(".description").text();
myArray[a] = [a];
myArray[a]["blogName"] = blogName;
myArray[a]["followLink"] = "http://www.bloglovin.com"+followLink;
myArray[a]["blogSite"] = blogSite;
a++;
console.log(myArray);
});
}
});
}
getLinks();
As you can see, followLinks is concatenated to followUrl, of which I'd like to pass through the 'url' download, so effectively I'll be scraping each of the pages using the same CSS rules, which will be added to the multidimensional array for the corresponding blogger.
How can I go about this?
I do something similar in one of my scraping jobs, but I use the async.js library to accomplish. Note that I'm also using the request module and cheerio.js in my scraping. I fetch and scrape rows of data from a single webpage, but suspect you could do something similar to fetch URLs and request / scrape them in the same manner.
I also admit this is quite basic coding, certainly could be optimized with a bit of refactoring. Hope it gives you some ideas at least...
First, I use request to fetch the page and call my parse function -
var url = 'http://www.target-website.com';
function(lastCallback) {
request(url, function(err, resp, body) {
if(!err) { parsePage(err, resp, body, lastCallback); }
else { console.log('web request error:' + resp.statusCode); }
}
}
Next, in my parsePage function, I load the website into Cheerio, fetch the HTML of each data row into an array, push my parseRow function and each HTML segment into another array, and use async.parallel to process each iteration -
var rows = [];
function parsePage(err, resp, body, callback1) {
var $ = cheerio.load(body);
$('div#targetTable tr').each(function(i, elem) {
rows.push($(this).html());
});
var scrRows = [];
rows.forEach(function(row) {
scrRows.push(function(callback2) {
parseRow(err, resp, row);
callback2();
});
async.parallel(scrRows, function() {
callback1();
});
}
Inside your loop, just create an object with the properties you scrape then push that object onto your array.
var blogInfo = {
blogName: blogName,
followLink: "http://www.bloglovin.com"+followLink;
blogSite: blogSite
};
myArray.push(blogInfo);
You have defined a = 0; So
myArray[a] = [a]; // => myArray[0] = [0]; myArray[0] becomes an array with 0 as only member in it
All these statements throw an error since Array can have only integer as keys.
myArray[a]["blogName"] = blogName;
myArray[a]["followLink"] = "http://www.bloglovin.com"+followLink;
myArray[a]["blogSite"] = blogSite;
Instead try this:
var obj = {
index: a,
blogName: blogName,
followLink: "http://www.bloglovin.com" + followLink,
blogSite: blogSite
}
myArray.push(obj);
console.log(myArray);
I'm a newb to back-end code and I'm trying to create a function that will respond to me a JSON string. I currently have this from an example
function random(response) {
console.log("Request handler 'random was called.");
response.writeHead(200, {"Content-Type": "text/html"});
response.write("random numbers that should come in the form of json");
response.end();
}
This basically just prints the string "random numbers that should come in the form of JSON". What I want this to do is respond with a JSON string of whatever numbers. Do I need to put a different content-type? should this function pass that value to another one say on the client side?
Thanks for your help!
Using res.json with Express:
function random(response) {
console.log("response.json sets the appropriate header and performs JSON.stringify");
response.json({
anObject: { item1: "item1val", item2: "item2val" },
anArray: ["item1", "item2"],
another: "item"
});
}
Alternatively:
function random(response) {
console.log("Request handler random was called.");
response.writeHead(200, {"Content-Type": "application/json"});
var otherArray = ["item1", "item2"];
var otherObject = { item1: "item1val", item2: "item2val" };
var json = JSON.stringify({
anObject: otherObject,
anArray: otherArray,
another: "item"
});
response.end(json);
}
var objToJson = { };
objToJson.response = response;
response.write(JSON.stringify(objToJson));
If you alert(JSON.stringify(objToJson)) you will get {"response":"value"}
You have to use the JSON.stringify() function included with the V8 engine that node uses.
var objToJson = { ... };
response.write(JSON.stringify(objToJson));
Edit: As far as I know, IANA has officially registered a MIME type for JSON as application/json in RFC4627. It is also is listed in the Internet Media Type list here.
Per JamieL's answer to another post:
Since Express.js 3x the response object has a json() method which sets
all the headers correctly for you.
Example:
res.json({"foo": "bar"});
in express there may be application-scoped JSON formatters.
after looking at express\lib\response.js, I'm using this routine:
function writeJsonPToRes(app, req, res, obj) {
var replacer = app.get('json replacer');
var spaces = app.get('json spaces');
res.set('Content-Type', 'application/json');
var partOfResponse = JSON.stringify(obj, replacer, spaces)
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029');
var callback = req.query[app.get('jsonp callback name')];
if (callback) {
if (Array.isArray(callback)) callback = callback[0];
res.set('Content-Type', 'text/javascript');
var cb = callback.replace(/[^\[\]\w$.]/g, '');
partOfResponse = 'typeof ' + cb + ' === \'function\' && ' + cb + '(' + partOfResponse + ');\n';
}
res.write(partOfResponse);
}
const http = require('http');
const url = require('url');
http.createServer((req,res)=>{
const parseObj = url.parse(req.url,true);
const users = [{id:1,name:'soura'},{id:2,name:'soumya'}]
if(parseObj.pathname == '/user-details' && req.method == "GET") {
let Id = parseObj.query.id;
let user_details = {};
users.forEach((data,index)=>{
if(data.id == Id){
user_details = data;
}
})
res.writeHead(200,{'x-auth-token':'Auth Token'})
res.write(JSON.stringify(user_details)) // Json to String Convert
res.end();
}
}).listen(8000);
I have used the above code in my existing project.
The JSON.stringify() method converts a JavaScript object or value to a JSON string, optionally replacing values if a replacer function is specified or optionally including only the specified properties if a replacer array is specified.
response.write(JSON.stringify({ x: 5, y: 6 }));
know more