Convert JSON String to Object nodejs - node.js

products.json: {"model": "PLM-7-P-21","category":["classic","new"],"fabric":["white","beech","glass"], "shine": "false","size": "45x25","bulb": 2, "id": "5cfa55c5"},`
and then I want to use category and fabric as data-category:const layout = require('../layout');module.exports = ({ products }) => {const renderedProducts = products.map(product => {return <div class="image shopProduct" data-category=${product.category}><img src="data:image/png;base64, ${product.image}"/><h3 class="subtitle">${product.title} ${product.model}</h3><h5>${product.price} zł</h5><form action="/cart/products" method="POST"><input hidden value="${product.id}" name="productId" /><button class="button has-icon is-inverted">Dodaj do<i class="fa fa-shopping-cart"></i></button></form></div>;}).join('\n');`
but then I have got a string data-category="classic, new" but I want to get data-category="classic new" without comma...
I would be grateful for your help.

I think you are looking for JSON.parse which will convert string data directly to a JSON object, so long as the string is in valid syntax.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse

Instead of
data-category=${product.category}
do
data-category=${product.category.join(' ')}
You are getting the comma because the default serialization of an array separates elements with a comma.

Related

Ejs form, send array of data that can be converted into postgresql update queries

My app includes a scoresheet grid where each cell represents a student's score in one topic. The teacher can enter scores in each cell before clicking a submit button that sends them all at once.
Here is the ejs form that I have right now:
scoresheet.ejs
<tbody>
<% students.forEach((student, i) => { %>
<tr>
<td class="student-cell right">
<%= student.last_name %>, <%= student.first_name[0] %>
</td>
<% topics.forEach(topic=> { %>
<td class="score-cell center">
<input type="text" class="score-input" name="scores_<%= student.id %>_<%= topic.id %>">
</td>
<% }); %>
</tr>
<% }) %>
</tbody>
This form produces a req.body that looks something like this:
scores_1_2: '75',
scores_1_3: '92',
scores_1_4: '100',
scores_1_5: '100',
scores_1_6: '',
scores_2_1: '65',
scores_2_2: '60',
scores_2_3: '50',
scores_2_4: '35',
I'm trying to take this data and convert it into Postgresql query (or mutiple queries).
For example, the line scores_2_4: '35' would become
UPDATE scores SET points = 35 WHERE student_id = 2 AND topic_id = 4
The scores table is a many-to-many join table to connect students and topics.
I suspect that I still have a bit of work to do with my form. I'm probably not sending this data in an ideal way. This is my best solution so far to include a student_id and topic_id along with the teacher's score input.
If this approach is acceptable, then I also need a hint about how to convert all of this data into an update statement.
I'm using current versions of postgresql, nodejs, express, ejs and the node-postgres package.
Thank you in advance for any insight.
This is my best solution so far to include a student_id and topic_id along with the teacher's score input.
Yes, it's fine. You just have to parse the scores_${student_id}_${topic_id} format on the server back into the data structure you expect.
A more customary encoding is to use bracket notation instead of underscores though. Many parsers for application/x-www-form-urlencoded POST bodies can automatically transform this into a nested object, see e.g. Can not post the nested object json to node express body parser and How to get nested form data in express.js?.
<input type="text" class="score-input" name="scores[<%= student.id %>][<%= topic.id %>]">
I also need a hint about how to convert all of this data into an update statement.
Use multiple UPDATE statements for simplicity:
const { scores } = req.body;
for (const studentId in scores) {
const studentScores = scores[studentId];
for (const topicId in studentScores) {
const points = studentScores[topicId];
// TODO: check for permission (current user is a teacher who teaches the topic to the student)
await pgClient.query(
'UPDATE scores SET points = $3 WHERE student_id = $1 AND topic_id = $2',
[studentId, topicId, points]
);
}
}
You might want to throw in a parseInt or two with proper input validation for the studentId, topicId and points if you need them to be integers instead of strings; otherwise postgres will throw an exception.

Component attributes do not support complex content (mixed C# and markup) error message

I am working on validation on a form in a blazor server application.
I created the component below that I am using
#* Inherits from the original InputText component *#
#inherits InputText
#* Bind the oninput event *#
<input #attributes="AdditionalAttributes"
class="#CssClass"
value="#CurrentValue"
#oninput="EventCallback.Factory.CreateBinder<string>(this, __value => CurrentValueAsString = __value, CurrentValueAsString)" />
#code {
}
I am using the inputTextOnInput in this form
<EditForm EditContext="#EditContext">
<DataAnnotationsValidator />
<div class="mb-5">
<label for="projectnameinput" class="form-label">Name your project*</label>
<InputTextOnInput class="form-control form-control-lg cust #pNameValidation" id="projectnameinput" #bind-value="projectModel.ProjectName" #onkeyup=KeyboardEventHandler />
</div>
</EditForm>
since I created this I started getting the error message below
Component attributes do not support complex content (mixed C# and markup). Attribute: 'class', text: 'form-controlform-control-lgcustpNameValidation
Do you have an idea of what this implies?
You cannot use the class attribute in your new component if you have declared a specific parameter for that.
<InputTextOnInput class="form-control form-control-lg cust #pNameValidation" id="projectnameinput" #bind-value="projectModel.ProjectName" #onkeyup=KeyboardEventHandler />
you need to remove class from above and pass it via CssClass.
For some reason Blazor/Razor don't let you mix text literals and variables within an attribute value. So when you try and do
<InputTextOnInput class="form-control form-control-lg cust #pNameValidation" id="projectnameinput" #bind-value="projectModel.ProjectName" #onkeyup=KeyboardEventHandler />
the class statement is invalid because it contains literals "form-control", "form-control-lg" and "cust" and also a variable "#pNameValidation".
My solution to this problem was to create a little method on a component base class which allows mixing the two things.
public string Class(string classStr, params string[] objStrs)
{
var output = new StringBuilder();
output.Append(classStr);
output.Append(' ');
output.AppendJoin(' ', objStrs);
return output.ToString();
}
now all I have to do is to write my line like this
<InputTextOnInput class="#Class("form-control form-control-lg cust", pNameValidation)" id="projectnameinput" #bind-value="projectModel.ProjectName" #onkeyup=KeyboardEventHandler />
and by using params, you can also just add as many string variables as you want.

returning or looking up object from html input in node express

I have an html/handlebars form set up with a Node/Express backend. the form offers options populated from a database. I am able to get the form to return a single user selected value and save it to my mongodb, but I really need the whole object.
{{#each proxyObj}}
<p>
<label>
<input type="radio" name="proxyTitle" value="{{title}}"/>
<span>{{title}}</span>
</label>
</p>
{{/each}}
and this is the express:
router.post("/proxies/:id", ensureAuthenticated, (req, res) => {
Project.findOne({
_id: req.params.id
}).then(project => {
const newProxy = {
proxyTitle: req.body.proxyTitle
// I need the other object values to go here, or to be able to retrieve them later
};
// Add to proxy array on the Project object in the collection
project.proxies.push(newProxy);
project.save().then(project => {
res.redirect(`/projects/stakeholders/${project.id}`);
});
});
});
Is it more sensible to try to load in the entire object as a value in the input field, or to return the id of the object, and look it up in the db? I need to display some of the returned object information on the same page, and also to use it later. Which is more efficient, and what is the best way to achieve it?
If I'm getting it right, the problem is that you're trying to put multiple inputs with the same name on one form in <input type="radio" name="proxyTitle" value="{{title}}"/>, which gives you something like
<input type="radio" name="proxyTitle" value="Title 1"/>
<input type="radio" name="proxyTitle" value="Title 2"/>
<input type="radio" name="proxyTitle" value="Title 3"/>
As explained here, the browsers will chew it, but the server-side handling may require some adjustments.
In your case, the easiest fix would be to add index to the names of parameters. So, your form would be looking like this:
{{#each proxyObj}}
<p>
<label>
<input type="radio" name="proxies[{{#key}}]" value="{{this}}"/>
<span>{{this}}</span>
</label>
</p>
{{/each}}
(note that if proxyObj is an array, you would have to use #index instead of #key; also, depending on the proxyObj fields' structure, you may have to use this.title as the values to display and whatnot).
As for your server-side handling, you'll have to loop through the proxies you receive and handle them one by one, e.g.
router.post("/proxies/:id", ensureAuthenticated, (req, res) => {
Project.findOne({
_id: req.params.id
}).then(project => {
project.proxies = []; // this is only in case you wanna remove the old ones first
const proxies = req.body.proxies;
for(let i = 0; i < proxies.length; i++) {
// Add to proxy array on the Project object in the collection
project.proxies.push({ proxyTitle: proxies[i].title });
}
project.save().then(project => {
res.redirect(`/projects/stakeholders/${project.id}`);
});
});
});

How to reference data from vue,js pug template?

Basically I am trying to make a permalink from an event name. When I get the value from the event name using v-model it works but how do I put the converted permalink back in another input box in pug?
This works:
"P {{message}}",textarea(rows="2") {{message}}
but when i try the following:
input(value="{{message}}"),input(value={{message}}),input(value=#{{message}}),input(value=#{{message}}),input(value=#{message})
Pug does not render it & shows an indent error.
My question is how do I bind or reference data from Vue in input values ?
Pug template:
.col-md-12(style="padding:0px;")
.col-md-2.labelcont
label.labeltext Event Name :
.col-md-10
input(
type="text"
class="form-control"
placeholder="Event Name"
v-model="eventname"
)
.col-md-12(style="padding:0px;")
.col-md-2.labelcont
label.labeltext Permalink :
.col-md-10
textarea(
type="text"
class="form-control"
placeholder="Event Permalink"
) {{eventpermalink}}
Vue.js code:
var basicinfo = new Vue({
el: '#basic',
data: {
eventname: '',
eventpermalink: '',
}
})
basicinfo.$watch('eventname', function (newValue, oldValue) {
basicinfo.eventpermalink = basicinfo.eventname.replace(/[^a-zA-Z0-9 ]/g,'').replace(/ +/g,'-').toLowerCase();
})
You can use the v-bind directive. This way, you can bind any HTML element's attribute to a value whether it's calculated or a reference to your props or data.
In your case, it would be something like this:
input(type="text" class="form-control" placeholder="Event Name"
v-model="eventname" v-bind:value="YOUR-DATA-OR-WHATEVER")
Look the official documentation for further reading:
https://v2.vuejs.org/v2/guide/syntax.html

How does one parse nested elements using express.bodyParser/node-formidable?

I'm using express.js with the bodyParser middleware (which, is technically node-formidable, behind the scenes).
I'd like to take and create a form that represents inputs for each of the data elements listed here:
{
"name" : "asdf",
"children" : [
{
"child_name" : "xyz1234",
"size" : 12
},
{
"child_name" : "1234aszds"
"size": 14
}
]
}
The number of children here will be dynamic, but I'd like to be able to add additional fields client-side, and have them map into req.body on the server.
Note, I'm looking for how to name the inputs in the client in order for the raw POST body to have the correct encoding to allow node-formidable to parse them out into an array.
The general way to achieve this is as follows (excluding non-essential attributes for clarity):
<input name="name"/>
<input name="children[0[child_name]"/>
<input name="children[0[size]"/>
<input name="children[1[child_name]"/>
<input name="children[1[size]"/>
Note that the square brackets are not balanced, this is required due to a "bug" in the "querystring" package (or, at least it would seem so, as of August 20th, 2013).
But, if the square brackets are left unbalanced, as above, the result is that this will be parsed into the object structure requested in my original question (i.e. this will be made available as "req.body").
The benefit of this is that it does not require any Javascript to do any "pre-flighting" on form submission.
Using an HTML form with input fields will be problematic since there is no easy way to define the structure without parsing each field name to determine its place in the structure.
For instance, if you posted the following:
<form action="/post" method="post">
<input type="text" name="data[name]">
<input type="text" name="data[children][][child_name]">
<input type="text" name="data[children][][size]">
<input type="text" name="data[children][][child_name]">
<input type="text" name="data[children][][size]">
<input type="submit" value="Submit">
</form>
Formidable would interpret into this JSON structure:
[ [ 'data[name]', 'name' ],
[ 'data[children][][child_name]', [ 'cname1', 'cname2' ] ],
[ 'data[children][][size]', [ 'csize1', 'csize2' ] ] ]
To post deep structures this way, I would recommend using AJAX and posting a complete JSON object instead, which I have outlined below.
The following should allow you to copy all of the fields directly into req.body. I elected to use the .mixin() helper from the utile library.
var utile = require('utile')
var form = new formidable.IncomingForm()
, fields = {}
form
.on('field', function (field, value) {
fields[field] = value
})
.on('end', function () {
req.body = utile.mixin(req.body, fields)
})
Based on your JSON in the question itself, you could then access your values like this:
console.log(req.body.children[0].child_name)
If you are looking for a native way of merging the objects, see Combine or merge JSON on node.js without jQuery for a way to do this.
Hopefully this answers the question and helps you out!

Resources