How to send javascript object to node server - javascript

Let me preface this by saying I'm sure it's something amazingly simple and stupid that I'm missing but I've been trying to solve this for over a week now and it's breaking my brain. I'm building a web app to do quoting for my workplace and most of it is working fine. I'm at a point where I need to take an object composed of a bunch of data from dynamically created user inputs and access it from the node server so that I can put that data into my mongodb database.
Through trolling through answers to similar questions I've been able to figure out that putting data into a hidden input I've named "quoteoutput" and then retrieving that using req.body.quoteoutput seems to be the way to go. As the submit function runs I do a console.log to check the variable actually has the stringified json object stored as a string, this shows up exactly as expected.
However when I get to the Node side of things the variable shows up as empty.
Hidden Input Declared in HTML:
<input type"hidden" name="quoteoutput" value="" />
Javascript to Change the Value to the stringified object:
outvalue = {customername: customer, quotelines: lines};
var output = document.getElementsByName("quoteoutput");
output.value = JSON.stringify(outvalue);
console.log("Output Value is:" + output.value);
The console in Chrome then displays exactly what is expected on the console.log
Post Request:
router.post('/addquote', function(req, res) {
var receivedobj = req.body.quoteoutput;
console.log("Object is " + receivedobj);
res.send("OBJ Is " + receivedobj)
};
The next step would be to parse the string back into a JSON object so I can start compiling it to be put into the MongoDB Database appropriately but receivedobj is just showing up as blank, there is no string to parse back in. So that the output I get in the console.log here is:
"Object Is "
And the res.send call brings up a blank page with:
"OBJ is"
And nothing else, apologies if this is a duplicate, I really tried searching for it somewhere else but couldn't find it.

By default, Express does not read the body of the post. You need some code that actually reads the body from the stream and then parses it based on its content-type. You don't show the whole client-side code to know exactly what content-type it is sending. If it's a form, then it would be probably be application/x-www-form-urlencoded which you can read and parse with express.urlencoded() like this:
router.post('/addquote', express.urlencoded(), function(req, res) {
var receivedobj = req.body.quoteoutput;
console.log("Object is " + receivedobj);
res.send("OBJ Is " + receivedobj)
});
Or you can generically install that middleware so it will work for all POST or PUT requests with that content-type:
router.use(express.urlencoded());
router.post('/addquote', function(req, res) {
var receivedobj = req.body.quoteoutput;
console.log("Object is " + receivedobj);
res.send("OBJ Is " + receivedobj)
});
Or, at the app level, you can do:
app.use(express.urlencoded());
Installing it as middleware will examine the incoming request. If it's the type of request that has a body to it (like POST or PUT) and it has a matching content-type, then the middleware will read the rest of the incoming stream to get the body contents and then parse it according to its content type and then place the results into req.body for your actual request handler, further down the line to access.
It also looks like your client code might be a bit off because document.getElementsByName() returns a collection and you have to index that collection to access one particular object:
outvalue = {customername: customer, quotelines: lines};
var output = document.getElementsByName("quoteoutput")[0]; // see the [0] here
output.value = JSON.stringify(outvalue);
console.log("Output Value is:" + output.value);
This will set the actual .value property on the first DOM element with the "quoteoutput" name attribute.

Related

node / express js, get data after query

I know it will be a trivial thing, but for this, I have not found much around, I'm using node/express js to query a database (MySQL), I'm using the following mode for queries:
index.js
exports.view= function(req, res){
var name = req.params.name;
req.getConnection(function(err,connection){
var query = connection.query('SELECT * FROM event WHERE linkname = ?',[name],function(err,rows)
{
if(err){
console.log("Error Selecting : %s ",err );
res.redirect('/');
}else{
console.log("rows: %s",rows);
var body = JSON.parse(JSON.stringify(rows));
console.log("body: %s",body);
res.render('form_payment',{page_title:"Showroom",data:rows});
}
});
});
};
I would like to view the video, or in any case be able to use part of the query data, I read that you can use JSON.stringify(), JSON.parse() or both, but I always print the empty string on the screen, even when I try to print rows:
rows:
body:
The query works perfectly, in fact, I can pass the json of rows to the next activity with res.render (), but in this function (view) I just can not get and then use this data. My idea would be to be able to easily use the contents of rows, for example, something like rows[0].name, rows[0].id or rows.name, rows.code, ...
[SOLVED]
Remember to check if the variables that are passed to the query are correct, once this problem has been solved everything is back to work correctly and access to the rows elements, can occur with rows[0].id, rows[0].name, ...
I hope you can also help you find yourself in this situation.

Trying to get a snapshot of a variable from firebase gives me an error

Problem
In a social media app I am making with react native and firebase, I am trying to grab the number of comments a post has using the snapshot function of a variable I have saved on my servers, then I am going to add one to this variable when a user adds a new comment. My code to do so is right here:
firebase.database().ref('posts').child(this.state.passKey).update({
comments: firebase.database().ref('posts/'+this.state.passKey).child('comments').snapshot.val() + 1
})
When I actually run this code, I get an error saying:
Reference.child failed: First argument was an invalid path = "undefined".
Paths must be non-empty strings and can't contain ".","#","$","[", or "["
At first I thought this might be that the "this.state.passKey" wasn't actually passing the key, but putting in a key I copied from the server didn't fix the problem.
My Server
-
To get the comments of particular post you should do like this
let postId='someId'
postRef=`/posts/${postId}`
firebase.database().ref(postRef).once("value", dataSnapshot => {
comment=dataSnapshot.val().comments
});
It looks like you're expecting this bit of code to query the database:
firebase.database().ref('posts/'+this.state.passKey).child('comments').snapshot.val() + 1
Unfortunately, it doesn't work that way. There's no snapshot property on a database Reference object returned by child() or ref().
Instead, you'll need to query the database at that reference, then when you're called back with its value, you can apply it elsewhere.
var ref = firebase.database().ref('posts/'+this.state.passKey+'/comments')
ref.once('value', function(snapshot) {
// use the snapshot here
})

Updating in vtiger from Javascript. Permission to perform the operation is denied for id

I have a node application that needs to be integrated into vtiger, and I have successfully been able to create, delete and retrieve information from my vtiger instance. If I try to update however, I get a Permission to perform the operation is denied for id error.
I have tried a couple different methods i.e. different ways of performing the request. And to test it at the moment I am pulling all of the data (result in the below code) for an id, changing one value and then calling the update using:
var requestJS = require('request');
//Real result comes stright from CRM, but an example of what is being passed through
result = {
'lastname': 'Updated last name',
'id': '12x10',
'assigned_user_id': '19x5',
}
var url = VT_URL + '?operation=update&sessionName=' + session + '&element=' + encodeURIComponent(JSON.stringify(result));
requestJS.post(url, function(err, res, body){
//stuff here
});
I have also tried by attaching the result as the body, and by not using the encodeUriComponent function. Always the same error.
where VT_URL is my vitger url and session is my session id retrieved from login.
I am using the credentials of an admin so I should have read/write access to contacts in the CRM instance.
I have been stuck on this for a while and can't find an answer
So it's not really an answer, but as I changed to a new vtiger instance it all seemed to work fine. So I'm assuming it was more to do with the installation of vtiger rather than an error in the code.
Thought I would keep this question here though because I've seen it around a fair bit
Can you check on your previous vtiger instance if there is an entry (in the database) for your module (I assume Contacts) in the vtiger_ws_entity table ?
If yes, ID is 12 ?

get method not working on Parse current User

I am making an express app with Parse. In my cloud code, I am trying to get an attribute of the current user, but it is returning me undefined. My code looks like following:
app.get('/home/subscriptions',function(req,res){
Parse.Cloud.useMasterKey();
var user = Parse.User.current();
var ifstud = user.get("isStudent");
console.log('student: ' + ifstud); // undefined
console.log('id: ' + user.id); // OK. works fine.
}
I am able to retrieve the id of the user as above but not able to call the get method on user. In their API reference, they have mentioned that Parse.User.current() returns a Parse.Object, so I think in user I have _User object and I should be able to call all methods supported by a Parse.Object.
What might be the issue here?
Thanks
I figured it out and putting this answer for future reference to users who visit this question.
The Parse.User.current() returns only a pointer to the user and not the complete user object. To get access to all fields of the user, fetch the entire object using the fetch method.
var fullUser;
Parse.User.current.fetch().then(user){
fullUser = user;
}).then(function(){
// Place your code here
});
I think it should be: var ifstud = Parse.User.get("isStudent");

Express - Send a page AND custom data to the browser in a single request?

How simultaneously to render a page and transmit my custom data to browser. As i understood it needs to send two layers: first with template and second with JSON data. I want to handle this data by backbone.
As i understood from tutorials express and bb app interact as follows:
res.render send a page to browser
when document.ready trigger jQuery.get to app.get('/post')
app.get('/post', post.allPosts) send data to page
This is three steps and how to do it by one?
var visitCard = {
name: 'John Smit',
phone: '+78503569987'
};
exports.index = function(req, res, next){
res.render('index');
res.send({data: visitCard});
};
And how i should catch this variable on the page- document.card?
I created my own little middleware function that adds a helper method called renderWithData to the res object.
app.use(function (req, res, next) {
res.renderWithData = function (view, model, data) {
res.render(view, model, function (err, viewString) {
data.view = viewString;
res.json(data);
});
};
next();
});
It takes in the view name, the model for the view, and the custom data you want to send to the browser. It calls res.render but passes in a callback function. This instructs express to pass the compiled view markup to the callback as a string instead of immediately piping it into the response. Once I have the view string I add it onto the data object as data.view. Then I use res.json to send the data object to the browser complete with the compiled view :)
Edit:
One caveat with the above is that the request needs to be made with javascript so it can't be a full page request. You need an initial request to pull down the main page which contains the javascript that will make the ajax request.
This is great for situations where you're trying to change the browser URL and title when the user navigates to a new page via AJAX. You can send the new page's partial view back to the browser along with some data for the page title. Then your client-side script can put the partial view where it belongs on the page, update the page title bar, and update the URL if needed as well.
If you are wanting to send a fully complete HTML document to the browser along with some initial JavaScript data then you need to compile that JavaScript code into the view itself. It's definitely possible to do that but I've never found a way that doesn't involve some string magic.
For example:
// controller.js
var someData = { message: 'hi' };
res.render('someView', { data: JSON.stringify(someData) });
// someView.jade
script.
var someData = !{data};
Note: !{data} is used instead of #{data} because jade escapes HTML by default which would turn all the quotation marks into " placeholders.
It looks REALLY strange at first but it works. Basically you're taking a JS object on the server, turning it into a string, rendering that string into the compiled view and then sending it to the browser. When the document finally reaches the browser it should look like this:
// someSite.com/someView
<script type="text/javascript">
var someData = { "message": "hi" };
</script>
Hopefully that makes sense. If I was to re-create my original helper method to ease the pain of this second scenario then it would look something like this:
app.use(function (req, res, next) {
res.renderWithData = function (view, model, data) {
model.data = JSON.stringify(data);
res.render(view, model);
};
next();
});
All this one does is take your custom data object, stringifies it for you, adds it to the model for the view, then renders the view as normal. Now you can call res.renderWithData('someView', {}, { message: 'hi' });; you just have to make sure somewhere in your view you grab that data string and render it into a variable assignment statement.
html
head
title Some Page
script.
var data = !{data};
Not gonna lie, this whole thing feels kind of gross but if it saves you an extra trip to the server and that's what you're after then that's how you'll need to do it. Maybe someone can think of something a little more clever but I just don't see how else you'll get data to already be present in a full HTML document that is being rendered for the first time.
Edit2:
Here is a working example: https://c9.io/chevex/test
You need to have a (free) Cloud9 account in order to run the project. Sign in, open app.js, and click the green run button at the top.
My approach is to send a cookie with the information, and then use it from the client.
server.js
const visitCard = {
name: 'John Smit',
phone: '+78503569987'
};
router.get('/route', (req, res) => {
res.cookie('data', JSON.stringify(pollsObj));
res.render('index');
});
client.js
const getCookie = (name) => {
const value = "; " + document.cookie;
const parts = value.split("; " + name + "=");
if (parts.length === 2) return parts.pop().split(";").shift();
};
const deleteCookie = (name) => {
document.cookie = name + '=; max-age=0;';
};
const parseObjectFromCookie = (cookie) => {
const decodedCookie = decodeURIComponent(cookie);
return JSON.parse(decodedCookie);
};
window.onload = () => {
let dataCookie = getCookie('data');
deleteCookie('data');
if (dataCookie) {
const data = parseObjectFromCookie(dataCookie);
// work with data. `data` is equal to `visitCard` from the server
} else {
// handle data not found
}
Walkthrough
From the server, you send the cookie before rendering the page, so the cookie is available when the page is loaded.
Then, from the client, you get the cookie with the solution I found here and delete it. The content of the cookie is stored in our constant. If the cookie exists, you parse it as an object and use it. Note that inside the parseObjectFromCookie you first have to decode the content, and then parse the JSON to an object.
Notes:
If you're getting the data asynchronously, be careful to send the cookie before rendering. Otherwise, you will get an error because the res.render() ends the response. If the data fetching takes too long, you may use another solution that doesn't hold the rendering that long. An alternative could be to open a socket from the client and send the information that you were holding in the server. See here for that approach.
Probably data is not the best name for a cookie, as you could overwrite something. Use something more meaningful to your purpose.
I didn't find this solution anywhere else. I don't know if using cookies is not recommended for some reason I'm not aware of. I just thought it could work and checked it did, but I haven't used this in production.
Use res.send instead of res.render. It accepts raw data in any form: a string, an array, a plain old object, etc. If it's an object or array of objects, it will serialize it to JSON for you.
var visitCard = {
name: 'John Smit',
phone: '+78503569987'
};
exports.index = function(req, res, next){
res.send(visitCard};
};
Check out Steamer, a tiny module made for this this exact purpose.
https://github.com/rotundasoftware/steamer
Most elegant and simple way of doing this is by using rendering engine (at least for that page of concern). For example use ejs engine
node install ejs -s
On server.js:
let ejs = require('ejs');
app.set('view engine', 'ejs');
then rename desired index.html page into index.ejs and move it to the /views directory. After that you may make API endpoit for that page (by using mysql module):
app.get('/index/:id', function(req, res) {
db.query("SELECT * FROM products WHERE id = ?", [req.params.id], (error, results) => {
if (error) throw error;
res.render('index', { title: results[0] });
});
});
On the front-end you will need to make a GET request, for example with Axios or directly by clicking a link in template index.ejs page that is sending request:
<a v-bind:href="'/index/' + co.id">Click</a>
where co.id is Vue data parameter value 'co' that you want to send along with request

Categories

Resources