Does nodejs have a form helper similar to that of ruby's to generate CSRF tokens? - node.js

In ruby one can do something like <%= form_tag(:action => '/submit') do %> ... <% end %> to get a form including CSRF tokens.
Is there an existing function in node and how is it implemented?

You can use caolan-forms plugin for node.js. After that install express-csrf plugin.
Then you can merge these two, something like:
// initializing express
var express = require('express'),
// initializing express-csrf
csrf = require('express-csrf');
app = express.createServer();
app.dynamicHelpers({
csrf: csrf.token
});
var forms = require('forms'),
fields = forms.fields,
validators = forms.validators;
var reg_form = forms.create({
username: fields.string({required: true, id: csrf, name: csrf}),
});
// finally render the form
reg_form.toHTML();
It would produce:
<div class="field required">
<label for="id_username">Username</label>
<input type="text" name="[csrf-value]" id="[csrf-value]" value="test" />
</div>
Note: The caolan-forms' author wrote:
You'll notice you have to provide your own form tags and submit button, its more flexible this way ;)
Edit
Since express-csrf is depriciated, instead use connect bundle and follow this simple example. Eventually, you would be able to integrate it with caolan-forms like:
var reg_form = forms.create({
'_csrf':fields.hidden({value: 'req.session._csrf'}),
...
})

Related

Checkbox value is refreshed after page reload in node JS

"I am creating TODO list using Node as backend. after adding every new item, a checkbox is also generating in front of them so I can apply "CSS line-through" to let user know that item is done or of no use. But when I add another item, the page refreshes and that checkbox is unchecked as I am not storing that value anywhere. Can you tell me how to store the value of that checkbox in the backend?
HTML -
<div class="box" >
<% for (var i=0; i<newListItems.length; i++) { %>
<div class="item">
<input type="checkbox" id="checkBox">
<p> <%= newListItems[i] %> </p>
</div>
<% } %>
<form action="/" method="post" class="item">
<input class="inputBox" type="text" name="newItem" placeholder="New item" autocomplete="off" required="required">
<button type="submit" name="list" value=<%= listTitle%>> +</button>
</form>
</div>
Node JS -
const items = [];
app.post("/", function(req, res){
let item = req.body.newItem;
items.push(item);
res.redirect("/");
});
The answer involves a lot of code, so I will give you a set of steps that can help in your case.
You need to change your data scheme. Currently looks like you are just storing the string in an array of items. You need to change it to be array of objects. Each object should have the field task and done. So you could know which task is done or not.
app.post("/", function(req, res) {
let item = req.body.newItem;
items.push({ name: item, done: false });
res.redirect("/");
});
Next step will be adding an endpoint that will be changing the done field of an array item to true.
Then on a front-end you will need to write some JS code that will be sending an HTTP request to the endpoint that marks the task as done. You need to use AJAX call for that, for example, NPM package axios.
Change the template to reflect the changes to the data. e.g. instead of <%= newListItems[i] %> do <%= newListItems[i].name %> and add logic to render checked checkbox based on done property.
It worth to mention, that you should not store data in memory, because once the process is done, you will lose your data. It is okay for learning purposes, but in production, you should use a database.

Express: POST does not send data - var is not defined

In a view, i am trying to get the data that a user sent, via a form, from another view.
This is the view with the form (i have omitted some EJS stuff to avoid confusion):
<form action="/renderer" method="POST" id="sc-form">
<label for="model">Choose a model:</label>
<select name="model" id="model">
<% data.forEach(function(dat) { %>
<option value="<%= dat %>"> <%= dat %> </option>
<% }); %>
</select>
<input type="submit" value="Render the model!" />
</form>
As you can see, the user selects from a dropdown, and then data is POSTed on /renderer.
So, let's handle this POST request on routes.js:
app.post('/renderer', function(req, res) {
var myModel = req.body.model;
res.render('renderer.ejs', {data: myModel});
});
Pretty basic, we get the data that the form sent and we send it to renderer.ejs as parameters.
Finally, let's grab the data on /renderer.ejs (this is inside a <script> tag):
var modelName = <%- JSON.stringify(data) %>;
And i get this error:
data is not defined
But why is that? Data is the name of the variable that the router sent to the view, as parameter.
This is the third day that i am trying to make POST data appear on another view. If anyone could help i would really appreciate it.
I finally found this.
The form has to contain role="form", or else it wouldn't work.

Passing data from one page to another using Node, Express & EJS

I've got the following routes set up:
router.get('/', function(req, res) {
res.render('index', {});
});
router.post('/application', function(req, res) {
res.render('application', {twitchLink : req.query.twitchLink});
});
I've got the two views set up properly.
This is what I've got in the 'index' view:
<form class="form-horizontal" action="/application", method="post", role="form">
<input type="url" name="twitchLink" required>
<button class="btn btn-success">Submit</button>
</form>
Submitting this form does take me to the application view.
<script>var twitchLink = <%- JSON.stringify(twitchLink) %></script>
<script>console.log(twitchLink)</script>
This should log out the link that I submitted, right?
However, I get these two lines:
Uncaught SyntaxError: Unexpected end of input
Uncaught ReferenceError: twitchLink is not defined
I think you need to put quotes around <%- JSON.stringify(twitchLink) %>, like this:
var twitchLink = '<%- JSON.stringify(twitchLink) %>'
In your example, it will come out as:
var twitchLink = foo.bar.com
What you want is:
var twitchLink = 'foo.bar.com'

Upload a file with ServiceStack ss-utils.js

I have a job application form as part of a site built on ServiceStack. I am attempting to use the included ss-utils.js to leverage built-in Fluent Validation, but my form doesn't post the user's file upload. Here's the relevant snippet of the form:
<form id="form-careerapplication" action="#(new CreateCareerApplication().ToPostUrl())" method="post">
<div class="error-summary"></div>
<div class="form-group">
<label>
Upload Resume
</label>
<input type="file" id="Resume" name="Resume" />
<span class="help-block"></span>
</div>
<input type="hidden" name="Id" value="#Model.Id" />
<input type="submit" value="Submit Application" />
</form>
<div id="success" class="hidden">
Thank you for your application.
</div>
$("#form-careerapplication").bindForm({
success: function (careerApplicationResponse) {
$("#form-careerapplication").addClass("hidden");
$("#success").removeClass("hidden");
},
...
Is there something I'm missing in ss-utils.js? Or is there a way of overriding / supplementing the submit behavior to use FormData?
Uploading files via a HTML FORM requires a enctype="multipart/form-data", e.g:
<form id="form-careerapplication" action="#(new CreateCareerApplication().ToPostUrl())"
method="post" enctype="multipart/form-data">
...
</form>
If you want to change support multiple file uploads or change the appearance of the UI Form I recommend the Fine Uploader, there's an example showing how to use Fine Uploader on the HTTP Benchmarks Example.
Whilst Imgur has a simple client HTML and Server example.
Turned out I can use the beforeSend option as part of the configuration passed into bindForm to override the data being sent. Its a bit of a hack, but it worked and I keep the original ss-utils.js fluent validation!
$("#form-careerapplication").bindForm({
success: function (careerApplicationResponse) {
....
},
error: function (error) {
....
},
contentType: false,
processData: false,
beforeSend: function (x, settings) {
var fd = new FormData();
// Tweaked library from https://github.com/kflorence/jquery-deserialize/blob/master/src/jquery.deserialize.js
// Used to translate the serialized form data back into
// key-value pairs acceptable by `FormData`
var data = $.fn.deserialize(settings.data);
$.each(data, function (i, item) {
fd.append(item.name, item.value);
});
var files = $('#form-careerapplication').find("input:file");
$.each(files, function (i, file) {
fd.append('file', file.files[0], file.files[0].name);
});
settings.data = fd;
}
});

meteor-typeahead: Listing and selecting

I have installed meteor-typeahead via npm. https://www.npmjs.org/package/meteor-typeahead
I have also installed
meteor add sergeyt:typeahead
from https://atmospherejs.com/sergeyt/typeahead
I am trying to get the data-source attribute example to function so I can display a list of countries when the user begins to type. I have inserted all countries into the collection :-
Country = new Meteor.Collection('country');
The collection is published and subscribed.
When I type into the input field, no suggestions appear. Is it something to do with activating the API? if so how do I do this? Please reference the website https://www.npmjs.org/package/meteor-typeahead
My form looks like this:
<template name="createpost">
<form class="form-horizontal" role="form" id="createpost">
<input class="form-control typeahead" name="country" type="text" placeholder="Country" autocomplete="off" spellcheck="off" data-source="country"/>
<input type="submit" value="post">
</form>
</template>
client.js
Template.createpost.helpers({
country: function(){
return Country.find().fetch().map(function(it){ return it.name; });
} });
In order to make your input to have typeahead completion you need:
Activate typeahead jQuery plugin using package API
Meteor.typeahead call in template rendered event handler.
Meteor.typeahead.inject call to activate typeahead plugin for elementes matched by CSS selector available on the page (see demo app).
Write 'data-source' function in your template understandable by typeahead plugin. It seems your 'data-source' function is correct.
Add CSS styles for typeahead input(s)/dropdown to your application. See example here in demo app.
Try this way in your template:
<input type="text" name="country" data-source="country"
data-template="country" data-value-key="name" data-select="selected">
Create template like country.html (for example /client/templates/country.html) which contains:
<template name="country">
<p>{{name}}</p>
</template>
In your client javascript:
Template.createpost.rendered = function() {
Meteor.typeahead.inject();
}
and
Template.createpost.helpers({
country: function() {
return Country.find().fetch().map(function(it){
return {name: it.name};
});
},
selected: function(event, suggestion, datasetName) {
console.log(suggestion); //or anything what you want after selection
}
})

Resources