PugJS trying to use variable values on form attributes - node.js

I'm currently trying to make a quiz using PugJS. I'm trying to group the answers that are in the body when the form is posted.
Currently when I post the following form I get this data:
console.log(JSON.stringify(req.body));
returns the following: {"answer":["a","b","c","d","e","f"]}
All of the data is in the same "answer" object.
In my PugJS file I do the following:
block contents
form(action=url, method='POST')
each question in config
h1= question.question
.row.mb-3
- for (var x = 0; x < question.requiredAnswers; x++)
label.col-sm-2.col-form-label(for='answer') Antwoord #{x + 1}
.col-sm-10
input.form-control(type='text' name='answer' id='answer')
hr
button.btn.btn-primary(type='submit', value='Submit') Verzend de antwoorden
As you can see I keep using the same label(for='answer') and input(name='answer' id='answer')
I tried to use the variable x to change the objects to: label(for='answer #{x + 1}') and input(name='answer #{x + 1}' id='answer #{x + 1}')
The output I would like:
{"answer1":["a"], "answer2":["b","c"], "answer3":["d","e","f"]}
I also tried a escaping the variable using #{x + 1} but no luck!

The browser will submit form parameters only as simple key-value pairs. If there are multiple keys with the same name, they will be submitted as they are, repeatedly. I think it is the Express body-parser middleware that converts keys with the same names into an array.
In Express, req.body.someParameter is a string value if someParameter occurs only once in your form. It is an array of strings if that parameter is received more than once.
doctype html
html
body
//- Test data:
- const config = [ { requiredAnswers: 1}, { requiredAnswers: 2},{ requiredAnswers: 3}]
form(method="post")
each question,i in config
p Q#{i+1}
ul
- for (let x=0; x<question.requiredAnswers; x++)
label(for="Q"+i+"A"+x) Antwoord #{x+1}
input(name="answer"+(i+1) id="Q"+i+"A"+x)
br
input(type="submit")
The above labels when clicked will set focus to each respective input box correctly. When submitted with the same values you used, the browser sends the following in the request payload:
answer1=a&answer2=b&answer2=c&answer3=d&answer3=e&answer3=f
and req.body at the server is:
{"answer1":"a","answer2":["b","c"],"answer3":["d","e","f"]}

Related

pdfkit nodejs, one element per page from page 2

Im using pdfkit to generate pdf invoice.
When all my content fit in one page I have no issue.
However when it doesn't fit and need an extra page, I have a strange behaviour:
Instead of adding the elements in the second page, it only add one line and the rest of the page is blank.
Then on 3rd page I have another element, and the rest it blank, then 4th page, 5th etc.
Here is the code corresponding to this part:
for (let i = 0; i < data.items.length; i++) {
const item = data.items[i];
this.itemPositionY = this.itemPositionY + 20;
if (item.bio) this.containBioProduct = true;
let itemName = item.bio ? `${item.item}*` : item.item;
this.generateTableRow(
doc,
this.itemPositionY,
itemName,
"",
this.formatCurrency(item.itemPriceDf.toFixed(2)),
item.quantity,
this.formatCurrency(item.itemPriceTotalDf.toFixed(2))
);
this.generateHr(doc, this.itemPositionY + 15);
}
Basically I just iterate over an array of products. For each line my Y position has +20.
Thanks for your help.
In case someone has this issue, here is a solution:
Everywhere in the code I know that an extra page could be generated, I add this:
if (this.position > 680) {
doc.addPage();
this.position = 50;
}
It allows you to control the generation of new pages (instead of pdfkit doing it automatically with potential problems)
You just need to track the position from the initialization of "this.position".
In that way, evertime it's superior than an Y position (680 in my case, it's a bit less than a page with pdfkit), you just do "doc.addPage()", which will create another page, and you reinitialize your position to the beginning of the new page.

how do we add url parameters? (EJS + Node + Express)

I understood how we parse the url parameters in express routes, as in the example
How to get GET (query string) variables in Express.js on Node.js?
But where do the url parameters come from in the first place?
EDIT:
Apparently, I can build such a query with jquery (i.e $.get). I can append params to this query object. It s cool, but still i m trying to understand how we achieve this in the query that renders the page as a whole.
An example : when i choose the oldest tab below, how does SO add ?answertab=oldest to the url so it becomes :
https://stackoverflow.com/questions/30516497/how-do-we-add-url-parameters-ejs-node-express?answertab=oldest#tab-top
The string you're looking at is a serialization of the values of a form, or some other such method of inputing data. To get a sense of this, have a look at jQuery's built in .serialize() method.
You can construct that string manually as well, and that's pretty straight forward as well. The format is just ?var1=data1&var2=data2 etc. If you have a JSON object {"name": "Tim", "age": 22} then you could write a very simple function to serialize this object:
function serializeObject(obj) {
var str = "?";
for(var i = 0; i < Object.keys(obj).length; i++) {
key = Object.keys(obj)[i];
if (i === Object.keys(obj).length - 1)
str += encodeURIComponent(key) + "=" + encodeURIComponent(obj[key]);
else
str += encodeURIComponent(key) + "=" + encodeURIComponent(obj[key]) + "&";
}
return str;
}
Running seralizeObject({"name": "Tim", "age": 22}) will output '?name=Tim&age=22'. This could be used to generate a link or whatnot.
The page author writes them so. This is how they "come in the first place". The authors of an HTML page decide (or are told by website designers) where to take the user when he clicks on a particular anchor element on it. If they want users to GET a page with some query parameters (which their server handles), they simply add query string of their choice to the link's href attribute.
Take a look at the href attribute of the oldest tab you clicked:
<a
class="youarehere"
href="/questions/30516497/how-do-we-add-url-parameters-ejs-node-express?answertab=oldest#tab-top"
title="Answers in the order they were provided"
>
oldest
</a>
When you clicked it, the browser simply took you to path indicated in href attribute /questions/30516497/how-do-we-add-url-parameters-ejs-node-express?answertab=oldest#tab-top relative to the base URL http://stackoverflow.com. So the address bar changed.
stackoverflow.com may have its own system of generating dynamic HTML pages. Their administrators and page authors have configured their server to handle particular query parameters and have put in place their own methods to make sure that links on their pages point to the URL(including query string) they wish.
You need to provide URIs with query strings of your choice (you can build them using url.format and querystring.stringify) to your template system to render. Then make your express routes process them and generate pages depending on their value.

How to read request body dynamic attributes in express?

I am very new to express and have a small question. Actually I am a SAP developer, but learning express.
I have few form input text elements in JADE which are dynamically generated. The form elements which are generated dynamically are called optiondes1, optiondes2, optiondes3 and so on. Now, when I post the request, I can see in req.body all those input text values.
How to extract or read the dynamic text elements value from the request body (req.body). I am using body parser. Similarly, I also want to read the dynamic files elements named file1, file2, and so on from the req.files. Please advice.
for (var i = 0; i < numofoptions; i++){
var optcount = i + 1;
optdes = ('req.body.' + 'optiondes' + optcount);
// This prints req.body.optiondes1 as string, but I need the value of req.body.optiondes1
console.log(optdes);
optfile = 'file' + optcount;
origFileName = ('req.files.' + optfile + '.originalFilename');
console.log(origFileName);
};
Try:
optdes = req.body['optiondes' + optcount]
For more examples, search for things like: Converting string to variable name. (JavaScript)

How can I get the properties from a property Group of a Custom Control as an Object?

I'm working on a Custom Control that displays markers on Google Maps. I have a couple of properties like "maptype" , "zoom", etc. It is easy to access them in Javascript: I can use #{javascript:compositeData.zoom} to get the value of the zoom property.
Now this is my problem: I use a group of properties for each marker.
The name of the group is "marker" and a marker has 6 properties: "title", "layer", "infotext", "icon", "address" and "animation".
If I try to access the group with
var markers = #{javascript:compositeData.marker};
I'm getting an error in firebug:
missing : after property id var markers = [{layer=2,
address=Oldenzaal, animation=DROP, icon=/ogo_notes.png...
an arrow is pointing to the first = between layer and 2
(I am not allowed to put in an image in stackoverflow)
If I use
var markers = #{javascript:'"' + compositeData.marker + '"'};
markers is an Object, but each Object contains a string with all the propperties of the marker.
I know I can do some coding to make an object of each string, but this is not easy if not all propperties are required. If a propperty is not required than it will not show up in the string.
I guess that there must be a more easy way to get each marker as an object so I can get the value of the icon with code like:
var icon = marker.icon
How can I do this?
You can use compositeData.marker.icon to get the property icon inside the group marker. If you have checked "Allow multiple instances" for the group then to get the properties you will have to go:
compositeData.marker[0].icon
compositeData.marker[1].icon
and so on...
Update 26-Apr-2012 (Naveen)
To use it with client side javascript you can try to put the value in a hidden input field like this:
<xp:inputHidden id="hdnIcon">
<xp:this.defaultValue><![CDATA[#{javascript:var value = new Array();
for (var i=0 ; i<compositeData.marker.length ; i++) {
value.push(compositeData.marker[i].icon);
}
return #Implode(value, ",");}]]></xp:this.defaultValue>
</xp:inputHidden>
The value of this hidden input field can be read through client-side javascript like this:
var value = document.getElementById("#{id:hdnIcon}").value.split(",");
for (var i=0 ; i<value.length ; i++) {
<YOUR CODE>
}
Another way to do this can be to convert compositeData.marker and its contents to a JSON string and then run the client-side javascript on it.

how do you make a collection show up in reverse order using expressJS partials/collections?

I am using an index.jade to show:
!=partial('_blogPost.jade', blogPost)
and in _blogPost.jade:
div.row-fluid
div.span2.sider
h4.date
#{blogPost.addedOn.getDate()}/#{blogPost.addedOn.getMonth() + 1}
|#{blogPost.addedOn.getFullYear()}
h3
#{blogPost.type}
div.span9.post
h2
a(href="#{blogPost.url}") !{blogPost.title}
p !{blogPost.body}
Pretty standard blogrolling stuff.
Using a standard for loop what I'm looking for would be:
for(var i = blogPost.length-1; i >= 0; i --){
blogPost[i].body
etc...
}
The problem is, how do you make a collection show up in reverse order using expressJS partials/collections?
you can just say
blogPost.reverse();
before using it inside your jade template and the content of the array will be shown in reverse order.

Resources