Can't get a specific property of js object - javascript

I am working with ejs, mongodb and express. In ejs file, I have set value of an Edit button to the the js object passed into the ejs file so that I can query required data after in express after the Edit button makes a post request to a route.
EJS edit button code:
<% listOfRecords.forEach((singleRecord)=>{ %>
<div class="card card-body">
<form method="post">
<button formaction="/edit" class="btn btn-success btn-sm" name="editBtn" value="<%=singleRecord%>">Edit</button>
</form>
</div>
<% }); %>
However, I am able console log the js object by the following code in express:
app.post('/edit', (req, res)=>{
console.log(req.body.editBtn);
});
The output of the above code is:
{
_id: 60605148a1fba61fd8f2446f,
title: 'asdf',
author: 'sadf',
class_section: 'asfd',
dateIssued: 2021-03-01T00:00:00.000Z,
__v: 0
}
But when I try doing this:
console.log(req.body.editBtn.title);
it shows the error, undefined
What am I doing wrong in this?

I don't think we have enough information. The code from my perspective looks fine. It should work.
What you could try doing is getting the attribute by doing console.log(req.body.editBtn['title']); instead of console.log(req.body.editBtn.title);.
You could also try destructuring the title : const { title } = req.body.editBtn.
Although these should theoretically not work !
Maybe something else in your code is wrong ?
Edit:
If req.body.editBtn is a string then try JSON.parse(req.body.editBtn); then get the attribute you want.

The real problem was that req.body.editBtn was in String format. So to make this work, change in EJS file would be:
<button formaction="/edit" class="btn btn-success btn-sm" name="editBtn" value="<%=JSON.stringify(singleRecord)%>">Edit</button>
This shall convert js object into a string properly and then in express file, the change is:
let editBtn = req.body.editBtn;
let info = JSON.parse(editBtn);
Now I can access any property of the object because it was converted to and from string properly.

you should get attributes from JSON.parse method's output, rather than req.body.editBtn which is still string.
app.post('/edit', (req, res)=>{
const data = JSON.parse(req.body.editBtn);
// console.log(req.body.editBtn);
console.log(data.title);
console.log(data.author);
// ....
});

Related

Why is EJS replacing " with &#34 when sending JSON string to Javascript Variable in html code [duplicate]

I'm working on a Node.js app (it's a game). In this case, I have some code set up such that when a person visits the index and chooses a room, he gets redirected to the proper room.
Right now, it's being done like this with Express v2.5.8:
server.get("/room/:name/:roomId, function (req, res) {
game = ~databaseLookup~
res.render("board", { gameState : game.gameState });
}
Over in board.ejs I can access the gameState manner with code like this:
<% if (gameState) { %>
<h2>I have a game state!</h2>
<% } %>
Is there a way for me to import this into my JavaScript logic? I want to be able to do something like var gs = ~import ejs gameState~ and then be able to do whatever I want with it--access its variables, print it out to console for verification. Eventually, what I want to do with this gameState is to display the board properly, and to do that I'll need to do things like access the positions of the pieces and then display them properly on the screen.
Thanks!
You could directly inject the gameState variable into javascript on the page.
<% if (gameState) { %>
<h2>I have a game state!</h2>
<script>
var clientGameState = <%= gameState %>
</script>
<% } %>
Another option might be to make an AJAX call back to the server once the page has already loaded, return the gameState JSON, and set clientGameState to the JSON response.
You may also be interested in this: How can I share code between Node.js and the browser?
I had the same problem. I needed to use the data not for just rendering the page, but in my js script. Because the page is just string when rendered, you have to turn the data in a string, then parse it again in js. In my case my data was a JSON array, so:
<script>
var test = '<%- JSON.stringify(sampleJsonData) %>'; // test is now a valid js object
</script>
Single quotes are there to not be mixed with double-quotes of stringify. Also from ejs docs:
"<%- Outputs the unescaped value into the template"
The same can be done for arrays. Just concat the array then split again.
I feel that the below logic is better and it worked for me.
Assume the variable passed to the ejs page is uid, you can have the contents of the div tag or a h tag with the variable passed. You can access the contents of the div or h tag in the script and assign it to a variable.
code sample below : (in ejs)
<script type="text/javascript">
$(document).ready(function() {
var x = $("#uid").html();
alert(x); // now JS variable 'x' has the uid that's passed from the node backend.
});
</script>
<h2 style="display:none;" id="uid"><%=uid %></h2>
In the EJS template:
ex:- testing.ejs
<html>
<!-- content -->
<script>
// stringify the data passed from router to ejs (within the EJS template only)
var parsed_data = <%- JSON.stringify(data) %>
</script>
</html>
In the Server side script:
ex: Router.js
res.render('/testing', {
data: data // any data to be passed to ejs template
});
In the linked js (or jquery) script file:
ex:- script.js
In JavaScript:
console.log(parsed_data)
In JQuery:
$(document).ready(function(){
console.log(parsed_data)
});
Note:
1. user - instead of = in <% %> tag
2. you can't declare or use data passed from router to view directly into the linked javascript or jquery script file directly.
3. declare the <% %> in the EJS template only and use it any linked script file.
I'm not sure but I've found it to be the best practice to use passed data from router to view in a script file or script tag.
This works for me.
// bar chart data
var label = '<%- JSON.stringify(bowlers) %>';
var dataset = '<%- JSON.stringify(data) %>';
var barData = {
labels: JSON.parse(label),
datasets: JSON.parse(dataset)
}
You can assign backend js to front end ejs by making the backend js as a string.
<script>
var testVar = '<%= backEnd_Var%>';
</script>
This should work
res.render("board", { gameState : game.gameState });
in frontend js
const gameState = '<%- JSON.stringify(gameState) %>'
Well, in this case you can simply use input text to get data. It is easy and tested when you use it in firebase.
<input type="text" id="getID" style="display: none" value="<%=id%>">
I know this was answered a long time ago but thought I would add to it since I ran into a similar issue that required a different solution.
Essentially I was trying to access an EJS variable that was an array of JSON objects through javascript logic like so:
<script>
// obj is the ejs variable that contains JSON objects from the backend
var data = '<%= obj %>';
</script>
When I would then try and use forEach() on data I would get errors, which was because '<%= obj %>' provides a string, not an object.
To solve this:
<script>
var data = <%- obj %>;
</script>
After removing the string wrapping and changing to <%- (so as to not escape html going to the buffer) I could access the object and loop through it using forEach()
Suppose you are sending user data from the node server.
app.get("/home",isLoggedIn,(req,res)=>{
res.locals.pageTitle="Home"
res.locals.user=req.user
res.render("home.ejs");
})
And now you can use the 'user' variable in the ejs template. But to use the same value using client-side javascipt. You will have to pass the data to a variable in the tag.
Passing ejs variable to client-side variable:
<script>
let user= '<%- JSON.stringify(user) %>';
</script>
<script>home.js</script>
Now you can access the user variable at home.js

send data from server to client nodejs

I have this code that allows me to get all the posts that the user made in my DB. The problem is that I tried to send that data to the front end (client). But I didn't succeed and I don't know what I'm missing,
The code that extracts the user's info from mongoDB is below. Tthe code is working perfectly, no issue with it,
User.find({}).lean(true).exec((err, users) => {
let userMap = [];
userMap.push({ user: users[i], posts: users[i].posts[j] });
//all the data are stored to userMAP :[{user : xxxxx ,posts : {the posts are here}}]
}
}
}
console.log(userMap);
User.findOne({ userName: req.user.userName }, (error, req_user) => {
console.log(req.user.lastLogin)
let lastSeen = ta.ago(req.user.lastLogin);
//console.log(posts)
res.render('home', { // this part for rendering the homePage and send data
user: req_user,
people: users,
userMap: userMap.reverse()
});
});
What I tried in my client side code is this:
<div class="container">
<% for(var x=0;x<user.posts.length;x++) { %>
<div class="jumbotron">
<div>by
<b>{{ user.posts[x].author }}</b>
on
<small>{{ user.posts[x].createdAt }}</small>
</div>
<div>
<p>{{ user.posts[x].caption }}</p>
</div>
<div class="row">
<button onclick="actOnPost(event);"
data-post-id="{{ this.id }}">Like
</button>
<span id="likes-count-{{ this.id }}">{{ this.likes_count }}</span>
</div>
</div>
<% } %>
For the error part I don't get anything,
this is the image of my stored data in the database
and this is the image of the homepage
The scenario for my code :
1- I'm using a EJS view engine and when the user login in the home.ejs is showing up and in the server side I use the code above to prepare the data that I need to display
2- Everything works perfectly except for displaying the data on the client side home.ejs
3- to call that page from my server I used this statement with the mix of the above code
router.get('/home', (req, res) => {
if (req.user.id) {
console.log(req.user.id)
User.find({}).lean(true).exec((err, users) => {
let userMap = [];
Any help or a better solution for showing data at the client side,
Best Regards,
That's not the syntax to display data in ejs ,try this.See these docs
<%= Outputs the value into the template (HTML escaped)
<% for(var x=0;x<user.posts.length;x++) { %>
<div class="jumbotron">
<div>by
<b><%= user.posts[x].author %></b>
on
<small><%= user.posts[x].createdAt %></small>
</div>
<div>
<p><%= user.posts[x].caption %></p>
</div>
<div class="row">
<button onclick="actOnPost(event);"
data-post-id="<%= this.id %>">Like
</button>
<span id="likes-count-<%= this.id %>"><%= this.likes_count %></span>
</div>
</div>
<% } %>
The source code for the template is being rendered in the browser. This means that the view engine is not parsing it.
The default view engine is Jade, but you aren't using Jade.
Probably you forgot to configure the view engine:
app.set('view engine', 'whatever template engine you are trying to use')
Hi #odegeek what show us so far is how are you getting the data from the database and an idea of how to show it in your view. But we are missing a few pieces of information here. For example:
Which frontend framework are you using if any?
Where are you calling the backend endpoint?
Which view engine are you using?
A typical flow for this scenario would be:
You frontend makes a request to your backend asking for the data
Once the response gets to the browser you do some kind of parsing/mapping to adapt it to your needs
Then you pass it to your view for rendering. Now depending on the frontend framework/view engine you are using. The code to render the data will vary
I hope this can give you a idea of what you need to provide/do .. thanks

Why does a data value logged to the console work, but not when assigned to a variable?

Javascript newbie here. Trying to set up the new Stripe checkout V3. I need to get a session id from HTML to my Javascript in Rails.
HTML file:
<%= content_tag :div, id: "temp_information", data: {temp: #session.id} do %>
<% end %>
<div data-stripe="<%= #session.id %>">
<button id="checkout-button">Pay</button>
</div>
Javascript file:
var ses_id = $('#temp_information').data('temp');
alert(ses_id);
stripe.redirectToCheckout({
// Make the id field from the Checkout Session creation API response
// available to this file, so you can provide it as parameter here
// instead of the {{CHECKOUT_SESSION_ID}} placeholder.
sessionId: ses_id
}).then(function (result) {
// If `redirectToCheckout` fails due to a browser or network
// error, display the localized error message to your customer
// using `result.error.message`.
});
I get undefined for ses_id.
When i do
$('#temp_information').data('temp');
in the console it shows the correct output. But when I do:
var a = $('#temp_information').data('temp');
Then I get undefined in the console. What am I doing wrong here?
Thanks for your help!
$.data(parameter) is used to store information and $.data() is used to get all data stored, so you just need to remove 'temp to get data.
var a = $('#temp_information').data();
Reference: https://api.jquery.com/data/
Turns out I needed to use:
$( document ).ready(function() {
*my code*
)};
To wait for everything to load before trying to access values. I think this is because of Rails or Turbolinks. Not totally sure which.

NodeJS - AngularJS Send JSON object and render templat at same time?

I have some problems with my api.
I use NodeJS with ExpressJS Routing and AngularJS.
What I want to do is to render a template (ejs) and at the same time send a json object.
In my routes folder I have the index.js file with this (a little part) :
router.get('/data', function(req, res, next){
Planning.getPlanningM(function(resultat){
res.json(resultat);
res.render('index');
});
});
About the variable resultat I'm sure that it contains that I want. But I can't do the res.json and the res.render. Because of the two invoke of send function.
And in my angular I have this in a function :
var resultat = []
$http.get('/data')
.success(function(res){
angular.extend(resultat, res.data);
})
.error(function(res){
console.log('err');
})
return resultat;
The goal is to render my index.ejs and to show my planning in this page. But I find no solution to do this.
This is my first ask on stackoverflow, english is not my native language. Please don't be rude with me :)
I'm not familiar with EJS, I use handlebars, but you should be able to pass data in the render function like so-
...
res.render("index", { data:resultat });
...
Then access it in the template in whatever format EJS uses. For hbs it would look something like
...
<div>My data looks like this: {{data}}</div>
...
Again, EJS is sure to do it differently, refer to the doc to ensure you have the correct format.
Thanks for your answer MPawlak !It helped me !
That I want is to send the data with the render like you do yes.
But I want to grab/take this data in my angular Factory (my factory fills the controller, this part works) that I show before :
var resultat = []
$http.get('/data')
.success(function(res){
angular.extend(resultat, res.data);
})
.error(function(res){
console.log('err');
})
return resultat;
With your method, I can take this data into my view directly your right and it's works ! Thanks !
<pre> <%= data %> </pre>
So I was thinking about a dirty temporaly solution to do this:
<textarea ng-model="planning"> <%= data %> </textarea>
But when I want to show this planning it don't work and stay empty... I don't understand why.
But to get a good and clean solution I think this is not a good idea, so my ask is the same... how to take this data in my angular factory directly ?

Accessing EJS variable in Javascript logic

I'm working on a Node.js app (it's a game). In this case, I have some code set up such that when a person visits the index and chooses a room, he gets redirected to the proper room.
Right now, it's being done like this with Express v2.5.8:
server.get("/room/:name/:roomId, function (req, res) {
game = ~databaseLookup~
res.render("board", { gameState : game.gameState });
}
Over in board.ejs I can access the gameState manner with code like this:
<% if (gameState) { %>
<h2>I have a game state!</h2>
<% } %>
Is there a way for me to import this into my JavaScript logic? I want to be able to do something like var gs = ~import ejs gameState~ and then be able to do whatever I want with it--access its variables, print it out to console for verification. Eventually, what I want to do with this gameState is to display the board properly, and to do that I'll need to do things like access the positions of the pieces and then display them properly on the screen.
Thanks!
You could directly inject the gameState variable into javascript on the page.
<% if (gameState) { %>
<h2>I have a game state!</h2>
<script>
var clientGameState = <%= gameState %>
</script>
<% } %>
Another option might be to make an AJAX call back to the server once the page has already loaded, return the gameState JSON, and set clientGameState to the JSON response.
You may also be interested in this: How can I share code between Node.js and the browser?
I had the same problem. I needed to use the data not for just rendering the page, but in my js script. Because the page is just string when rendered, you have to turn the data in a string, then parse it again in js. In my case my data was a JSON array, so:
<script>
var test = '<%- JSON.stringify(sampleJsonData) %>'; // test is now a valid js object
</script>
Single quotes are there to not be mixed with double-quotes of stringify. Also from ejs docs:
"<%- Outputs the unescaped value into the template"
The same can be done for arrays. Just concat the array then split again.
I feel that the below logic is better and it worked for me.
Assume the variable passed to the ejs page is uid, you can have the contents of the div tag or a h tag with the variable passed. You can access the contents of the div or h tag in the script and assign it to a variable.
code sample below : (in ejs)
<script type="text/javascript">
$(document).ready(function() {
var x = $("#uid").html();
alert(x); // now JS variable 'x' has the uid that's passed from the node backend.
});
</script>
<h2 style="display:none;" id="uid"><%=uid %></h2>
In the EJS template:
ex:- testing.ejs
<html>
<!-- content -->
<script>
// stringify the data passed from router to ejs (within the EJS template only)
var parsed_data = <%- JSON.stringify(data) %>
</script>
</html>
In the Server side script:
ex: Router.js
res.render('/testing', {
data: data // any data to be passed to ejs template
});
In the linked js (or jquery) script file:
ex:- script.js
In JavaScript:
console.log(parsed_data)
In JQuery:
$(document).ready(function(){
console.log(parsed_data)
});
Note:
1. user - instead of = in <% %> tag
2. you can't declare or use data passed from router to view directly into the linked javascript or jquery script file directly.
3. declare the <% %> in the EJS template only and use it any linked script file.
I'm not sure but I've found it to be the best practice to use passed data from router to view in a script file or script tag.
This works for me.
// bar chart data
var label = '<%- JSON.stringify(bowlers) %>';
var dataset = '<%- JSON.stringify(data) %>';
var barData = {
labels: JSON.parse(label),
datasets: JSON.parse(dataset)
}
You can assign backend js to front end ejs by making the backend js as a string.
<script>
var testVar = '<%= backEnd_Var%>';
</script>
This should work
res.render("board", { gameState : game.gameState });
in frontend js
const gameState = '<%- JSON.stringify(gameState) %>'
Well, in this case you can simply use input text to get data. It is easy and tested when you use it in firebase.
<input type="text" id="getID" style="display: none" value="<%=id%>">
I know this was answered a long time ago but thought I would add to it since I ran into a similar issue that required a different solution.
Essentially I was trying to access an EJS variable that was an array of JSON objects through javascript logic like so:
<script>
// obj is the ejs variable that contains JSON objects from the backend
var data = '<%= obj %>';
</script>
When I would then try and use forEach() on data I would get errors, which was because '<%= obj %>' provides a string, not an object.
To solve this:
<script>
var data = <%- obj %>;
</script>
After removing the string wrapping and changing to <%- (so as to not escape html going to the buffer) I could access the object and loop through it using forEach()
Suppose you are sending user data from the node server.
app.get("/home",isLoggedIn,(req,res)=>{
res.locals.pageTitle="Home"
res.locals.user=req.user
res.render("home.ejs");
})
And now you can use the 'user' variable in the ejs template. But to use the same value using client-side javascipt. You will have to pass the data to a variable in the tag.
Passing ejs variable to client-side variable:
<script>
let user= '<%- JSON.stringify(user) %>';
</script>
<script>home.js</script>
Now you can access the user variable at home.js

Categories