Guys I am using expressjs, ejs to develop an online shopping website.
Scenario
In order to display products {name, description, imageUrl} I am iterating with the help of ejs control-flow on the webpage.
I am sending an array that contains all the details about each product in JSON format. (from server)
on the client-side when I try to access this array of jsons I get the following error.
(index):266 Uncaught SyntaxError: Invalid or unexpected token
When I opened the sources tab in google chrome it, showed me this
At line number 266. I believe that it is taking this as a string by wrapping the array in double quotes.?
Could anyone tell me what's going wrong with this code?
And by the way, is how I trying to print the array on chrome console
<script>
const data = JSON.parse("<%- products %>");
console.log(data);
</script>
where products are an array of jsons
Backend home route which is sending the JSON array is as follows
router.get("/", async (req, res) => {
let catalogInformation = {};
//getAllProducts returns array of json from the database
const products = await getAllProducts();
catalogInformation.products = products;
userData = {
email: null,
username: null,
};
catalogInformation.userData = userData;
if (req.session.userInformation != null || req.session.userInformation != undefined) {
catalogInformation.userData = req.session.userInformation;
} else {
catalogInformation.userData = {
email: null,
username: null,
};
}
// res.render("catalog", userData);
res.render("catalog", catalogInformation);
return;
});
getAllProducts() method
const getAllProducts = async () => {
const Product = mongoose.model("product", productSchema);
const allProducts = await Product.find();
return allProducts;
};
You don't need to use JSON.parse. Just output the JSON directly:
var data = <%- products %>;
I wouldn't suggest making an AJAX call because you'd be handling 2 requests instead of 1.
Related
I am trying to display some JSON data that I receive from my backend. I first have a useEffect which retrieves the JSON data:
const [backendData, setBackendData] = useState(null)
useEffect(() => {
const fetchUserData = async () => {
const response = await fetch('http://localhost:5000/api/userData/')
const json = await response.json()
// check if response is ok
if (response.ok) (
setBackendData(json)
)
}
fetchUserData()
console.log(backendData, 'hi')
}, [])
And then in my JSX code I want to display the _id of the object which has a structure that looks like this:
by using this line of code:
{backendData && backendData.map((userData) => {
<p key={userData._id}>{userData._id}</p>
})}
I am unsure as to why this line of code doesn't work though because I don't see any output on the next.js page. I am able to receive the backend data as I see the object in my console when I log it but when I try mapping it, it doesn't work. Does anyone know why?
I figured out why, you have to return a value when you map in next.js so the solution would be:
{backendData && backendData.map((userData) => {
return (
<p key={userData._id}>{userData._id}</p>
)
})}
I am building a FlashCard website using NextJs and firebase. I have a homepage which I want to render server side and so I am using getServerSideProps. InsidegetServerSideProps function, I am fetching all the documents of the current user from firestore and is stored in an array and is returned as props as below:
export const getServerSideProps = async(ctx: GetServerSidePropsContext) {
let notes: DocumentData[];
// fetch documents here and populate notes array like so [doc,doc,doc,..]
// data() method works here and returns document fields
console.log(notes[0].data());
// NextJs throws error "`object` ("[object Object]") cannot be serialized as JSON. Please only return JSON serializable data types.", so I have to JSON.stringify() the notes
return {
props: {
notes: JSON.stringify(notes),
}
}
}
Below, I have my homepage where I parse the JSON string and have access to the notes, but now the data() method on the document does not exist/works and throws method does not exist errors. If I have to access the document fields, I have to use the dot operator on every property of the document till I reach the fields property which is nested deep down in the object as follows:
export default function Home({ notes }) {
let docs = JSON.parse(notes); // can access notes
// data() method throws function does not exist error
console.log(docs[0].data());
// I am only able to access document fields as below
console.log(docs[0]._document.data.value.mapValue.fields);
return (
<Layout>
<HomeContent notes={docs}/>
</Layout>
);
}
I have searched everywhere and found nothing that helped me why data() method won't work. If I directly fetch the documents inside the page component on client side, the data() method on the document returns its' fields. I don't know how using JSON serializations affect it. I would always prefer to use data() method to access fields than to go that deep plus I am planning to fetch data on server on other pages as well.
I would really appreciate if you can shed some light on it. It took all of my days time.
EDIT: The code that gets notes from firestore:
// inside getServerSideProps
let notes: DocumentData[] = null;
const getNotes = async(ref: DocumentReference < DocumentData > , uid: string) => {
let tempNotes = [];
const categoriesSnapshot = await getDoc < DocumentData > (ref);
const categoriesObject = categoriesSnapshot.data();
// return if user doesn't have any documents
if (!categoriesObject) {
return;
}
const promises: [] = categoriesObject.categories.map((category: string) => {
const userCategoriesRef = collection(database, 'CategoryCollection', uid, category);
return getDocs(userCategoriesRef); // returns a promise
});
const allQuerySnapshots = await Promise.all < DocumentData > (promises);
allQuerySnapshots.forEach((querySnapshot) => {
tempNotes.push(...querySnapshot.docs);
});
notes = tempNotes;
}
const categoryDocRef = doc(database, "CategoryCollection", uid);
await getNotes(categoryDocRef, uid);
I'm sending data from html using a button, I have the data and I want to pass it to an internal js because I don't want to expose credentials, but when I want to use it, it gives me an undefined instead of the data, that's why I need your help :c
Thanks in advance, below I show the code
My html file:
submitBtn.addEventListener("click", function (e) {
var folder_id = location.search.slice(1).split("&")[0].split("=")[1]
var document_id = location.search.slice(1).split("&")[1].split("=")[1]
axios.post('/send-signature',{
data: {
"document_id": document_id,
"folder_id": folder_id
}
})
}
My JS file
router.post("/send-signature", (req, res) => {
const data = req.body
console.log(data)
})
The error is that my req.body is undefined, that is, I think the data is not arriving.
Im trying to display data that has been fetched. but i cannot seem to display nested objects properties in react. Any ideas? if i log the data i first get a undefined, then the correct data.
my guess is that i need to wait for the data to be loaded then display it. but it does work for the title that is not in a nested obj.
function SingleBeneficiary({ match }) {
const [data, setData] = useState({ data: []});
const id = match.params.id
useEffect(() => {
async function fetchData() {
const response = await fetch(`http://localhost:8081/v1/beneficiary/${id}`);
const jsonData = await response.json()
setData(jsonData)
}
fetchData();
}, [])
return (
{data.title} // works
{data.address.careOf} // dont work
The data
{
"title":"myTitle",
"address":{
"careOf": "my adress"
}
}
Can you try like this?
I set initial data to null, and in return I check if it is not null.
If address can be null, additional null check is required.
function SingleBeneficiary({ match }) {
const [data, setData] = useState(null);
const id = match.params.id
useEffect(() => {
async function fetchData() {
const response = await fetch(`http://localhost:8081/v1/beneficiary/${id}`);
const jsonData = await response.json()
setData(jsonData)
}
fetchData();
}, [])
return (
<div>
{data && (
<div>
<p>data.title</p>
<p>data.address.careOf</p>
</div>
)}
</div>
);
}
You should check if address has careOf property before using it because first time data will be undefined and in second render it will have the data after the api call.
{data.address && data.address.careOf}
For anyone who is having a similar issue(i.e. fetching data via api and only the first time it runs, it will show the data as undefined but after manual refreshing, it works fine), here is a quick and sketchy addition you might consider alongside with 1. "Inline If with Logical && Operator" method and 2. using useState for checking if the api loading is over. With those three, mine worked.
Try fetching the desired data in the previous page of your app; in this case, add the following lines in any page you'll see before "SingleBeneficiary".
const response = await fetch(`http://localhost:8081/v1/beneficiary/${id}`);
const jsonData = await response.json()
Maybe it has to do with npm cache, but not really sure what's going on.
replace
return (
{data.title}
{data.address.careOf}
)
with
return (
{data?.title}
{data?.address?.careOf}
)
Im using express, body-parser and moongose to build a RESTful web service with Node.js. Im getting json data in the body of a POST request, that function looks like this:
router.route('/match')
// create a match (accessed at POST http://localhost:3000/api/match)
.post(function(req, res) {
if (req._body == true && req.is('application/json') == 'application/json' ) {
var match = new Match(); // create a new instance of the match model
match.name = req.body.name; // set the match name and so on...
match.host = req.body.host;
match.clients = req.body.clients;
match.status = req.body.status;
// save the match and check for errors
match.save(function(err) {
if (err) {
//res.send(err);
res.json({ status: 'ERROR' });
} else {
res.json({ status: 'OK', Match_ID: match._id });
}
});
} else {
res.json({ status: 'ERROR', msg: 'not application/json type'});
}
});
The model Im using for storing a match in the database looks like this:
// app/models/match.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var MatchSchema = new Schema({
name: String,
host: String,
clients: { type: [String]},
date: { type: Date, default: Date.now },
status: { type: String, default: 'started' }
});
module.exports = mongoose.model('Match', MatchSchema);
But how do I validate that the json data in the body of the POST request has the key/value fields I want? For clarification, I dont want to insert data in the database that is incomplete. If I test to skip a key/value pair in the json data I get a missing field in the database and when I tries to read req.body.MISSING_FIELD parameter in my code I get undefined. All fields except date in the model is required.
Im using json strings like this to add matches in the database
{"name": "SOCCER", "host": "HOST_ID1", "clients": ["CLIENT_ID1", "CLIENT_ID2"], "status": "started"}
I use a very simple function that takes an array of keys, then loops through it and ensures that req.body[key] is not a falsy value. It is trivial to modify it to accommodate only undefined values however.
In app.js
app.use( (req, res, next ) => {
req.require = ( keys = [] ) => {
keys.forEach( key => {
// NOTE: This will throw an error for ALL falsy values.
// if this is not the desired outcome, use
// if( typeof req.body[key] === "undefined" )
if( !req.body[key] )
throw new Error( "Missing required fields" );
})
}
})
in your route handler
try{
// Immediately throws an error if the provided keys are not in req.body
req.require( [ "requiredKey1", "requiredKey2" ] );
// Other code, typically async/await for simplicity
} catch( e ){
//Handle errors, or
next( e ); // Use the error-handling middleware defined in app.js
}
This only checks to ensure that the body contains the specified keys. IT won't validate the data sent in any meaningful way. This is fine for my use case because if the data is totally borked then I'll just handle the error in the catch block and throw an HTTP error code back at the client. (consider sending a meaningful payload as well)
If you want to validate the data in a more sophisticated way, (like, say, ensuring that an email is the correct format, etc) you might want to look into a validation middle-ware, like https://express-validator.github.io/docs/