NodeJS: Dynamic form - node.js

How do I create a dynamic form with NodeJS, Express and Mongoose?
Right now my contents are hardcoded for the sake of the question.
This is how my page creation looks like:
app.post('/create', function(req, res) {
var page;
var b = req.body;
page = new Page({
title: b.title,
url: '/' + Func.stringToUrlSlug(b.title) + '/',
headline: b.headline,
contents: [{
body: b.content1_body,
class: 'CLASS1'
},{
body: b.content2_body,
class: 'CLASS2'
},{
body: b.content3_body,
class: 'CLASS3'
}],
border: b.border,
target: b.target,
hidden: b.hidden,
externUrl: b.externUrl,
order: 700
});
page.save(function(err, page) {
if (!err)
res.send(page);
else
res.send(err);
});
});
And my Jade frontend creation:
....
div
label Content
textarea(name='content1_body')
div
label Content
textarea(name='content2_body')
div
label Content
textarea(name='content3_body')
....
And my mongoose schema contents are of Array type.
My question here is: How can I have these documents to being dynamic in my route depending on how many extra content fields I add?
Do I need to push these extra fields inside my page array somehow?
Say if something is unclear. Thanks in advance.

There are multiple approaches how to implement "dynamic forms". The easiest would be using the single page application features that you do not load the page at all when you move between the forms. The result could be stored in document.localStorage and when the user has finished send the results to server.
When you do not use the client side possibilities, you have to store the each form results in temporary database "table/document", also you have to keep track on what form the user is. When user reaches end, insert all the data from previous steps to table/document.

Alright after aaaaa lot of trying I solved it myself.
I ended up creating my form elements that should be dynamic this way:
div
label Class
input(name='content[1][class]')
label Content
textarea(name='content[1][body]')
div
label Class
input(name='content[2][class]')
label Content
textarea(name='content[2][body]')
....
That way I could reach the content fields, wether it was the class or the body field. And I ended up pushing these into my page array:
b.content.forEach(function(item) {
page.contents.push({ class: item.class, body: item.body });
});
I end up adding more form fields with jQuery.

If you enable the extended parsing of the Express body-parser
var app = express();
...
app.use(bodyParser.urlencoded({ extended: true }));
Express will use the qs library. This library has automated parsing for converting query parameters to array or objects.
Example (source: qs docs)
var withIndexes = qs.parse('a[1]=c&a[0]=b');
assert.deepEqual(withIndexes, { a: ['b', 'c'] });
After correctly parsing your inputs, it's a matter of sending this info to mongoose.

Related

Can one field have many value?

For example, I have a Scheme like this:
var User_schema = new Schema({
name: string,
image:{
avartar_image: String,
thumbnai_image: String,
story_image: String
}
});
Is it possible to create one field have many value like that in nodejs and mongoose? And one more, how can I store the image into mongodb and can push back to client using mongoose?, I store image on mongodb with Buffer, like this :
var Imgschema = new Schema({
img: Buffer;
});
And if send it to the user when user request a link on server, I do like this:
app.get('/', function (req, res, next) {
Imgschema.findById('5cdnjwjadhad_ad14', function (err, object) {
res.contentType('image/png');
res.send(object.image, {imageToClient: object.image});
});
});
It will send the image to the user with full screen, but I want the image display inside the tag with view engine, something like this:
<img src="{{imageToClient}}">
Any one help please, Thanks.
Of course you can. There are two ways to store a nested object with mongoose. You can use a subdocument, or just nest the object like you did. The difference between two methods is only a middleware and autogenerated _id field. Here is a good answer: Mongoose subdocuments vs nested schema
Storing images as a buffer in a document is not a good idea, but if you want, you can use base64 decoding to show image in browser.
<img src="{{ 'data:image/png;base64,' + imageBuffer.toString('base64') }}" />

Return the value from a mongoose find

I'm trying to render a template when i check the link for view a profile (for example going to http://localhost:3000/user/testuser`), all ok going to the routes but the values don't being showed on the page. This is my code:
Account.find({ username: req.params.username }, function(err, userWatch){
res.render('account/profile',{
title : userWatch.username,
user : req.user,
watchUser : userWatch,
});
You are using Account.find() that returns the array of objects. You should use Account.findOne() to fetch data, if you want either one or none objects.

Why is my buffer automatically converted to a nested array

My buffer format is being changed while trying to retrieve it from the MongoDB database, I'm not sure which step of the process is changing it.
I defined the mongoose schema as a buffer:
var mealSchema = mongoose.Schema({
picture: Buffer,
It looks like a what I expected in the database, a normal buffer:
{ "_id" : ObjectId("5691d1f73131c0db2b056447"), "picture" : BinData(0,"/9j/4TcORXhpZgAASUkqAKw2AA....
This is the code I used to send the buffer back to the client:
findAllMeals({})
.then(function(meals) {
res.send(200, meals);
This is how the client is receiving it back :
Object {type: "Buffer", data: Array[86690]}
[0 … 9999]
[10000 … 19999]
[20000 … 29999]
[30000 … 39999]
[40000 … 49999]
[50000 … 59999]
[60000 … 69999]
[70000 … 79999]
[80000 … 86689]
length: 86690
It became an array of arrays, it's being stored as a buffer, and being send back an nested arrays.
I also tried converting it to base64 in angular to see if it would convert it, it didn't.
I changed the storage data type in the schema to string, it didn't change anything, There's isn't much else I can think of changing to troubleshoot.
It's not an array of arrays, it's a Buffer object with a big data array (console.log splits it to ease the logging). One solution would be to exclude the pictures and then have a different route to fetch the picture for a specific meal (because express can deal with buffers automatically):
// first route, exclude pictures
app.get('/meals', function(req, res, next) {
findAllMeals({}, {
picture: 0
})
.then(function(meals) {
res.send(200, meals);
});
});
// second route to fetch the picture of a meal
app.get('/meal_picture/:mealId', function(req, res, next) {
findOneMeal({
_id: req.params.mealId
}).then(function(meal) {
res.status(200).send(meal.picture);
});
});
Then, in your html, you can simply write:
<img src='/meal_picture/5691d1f73131c0db2b056447'></img>
Side note, res.send(200, meals) is deprecated, use res.status(200).send(meals).
so I got it to work by changing the data type in the schema to
picture: {data: Buffer, contentType: String},
then in the client side I converted the base
<img ng-src="data:image/JPEG;base64,{{meal.picture}}"/>
and I managed to keep everything in the same REST request !

Display data in Jade with Mongoose

I've been trying to grab my data that's stored in mongodb and display it with a simple Jade template. I'm kinda new to this and I'm totally lost at this point.
Here's my output when I render my collection on /yfirlit
The express router for /yfirlit looks like this
apiRouter.get('/yfirlit', function(req, res){
apiUser.find(function(err, users) {
if(err) res.send(err);
res.render('yfirlit', {title: 'Yfirlit', users: users});
});
});
My simple Jade Template
html
head
title!= title
body
div #{users}
p
| API
When I run the test the whole mongodb collection is displayed on the site. What I'm looking for is to be able to display only a portion of the documents in the collections. For example: I tried to display only the name property in the Jade template but was unable to get it right.
html
head
title!= title
body
div #{users.name}
p
| API
Any help would be greatly appreciated, I'm so lost and I would love to be able to render out only the properties that I wanted instead of the whole thing like in the picture.
Cheers!
As Sgnl said, within the route you'll need to render the Jade view and include the data just like you have, but by using res.render:
apiRouter.get('/yfirlit', function(req, res){
apiUser.find(function(err, users) {
if (err) return next(err);
res.render('index', {
title: 'yfirlit',
users: users
})
});
});
...And I think you'll also need a loop to display the data from within your Jade view, because it contains multiple values:
if users
each user in users
div #{user.name}

Fetching only few attributes of a document in couchdb

I have a site where I have documents that are around 1MB in size. To avoid any kind of conceptual joins I have put all related data in a single document.
Now I often need to fetch only one or two attributes of a document. Each document has over 10 attributes many of which are pretty large. I can not go on writing views for every single combination of the attributes.
How should I do it ? The only way I see is creating views on the fly and then using those views. OR is there any better method ?
http://wiki.apache.org/couchdb/Document_Update_Handlers
While it seems strange to call a update feature, couch allows you to return information from the document without updating it. See the xml example.
Here might be an example you could extend:
Add jsonpath to your ddoc, ( https://github.com/s3u/JSONPath)
function(doc, req) {
var jsonpath = require('jsonpath');
var path = req.query.path;
var target = jsonpath(doc, path);
var json = JSON.stringify(target);
var resp = { 'headers' : { 'Content-Type' : 'application/json' }, 'body' : json };
return [doc, resp];
}

Resources