Sails.js req.files is empty and req.body.image is undefined - javascript

I've been trying to understand this since yesterday but I can't find any solutions, even by asking Google and StackOverFlow.
The problem is that I'm building a project inside which I have "Product" Model, Controller, and Views. On the new.ejs view, I have a form which contains a file tag (named image). So, on the controller, I try to get the image path by logging req.files.image.path in the console but req.files is empty. I also tried to display req.body.image which is undefined.
Here is the client-side code (views/product/new.ejs) :
(This is a Sails.js app)
Here is the client-side code (views/product/new) :
<div class='container'>
<form action='/product/create' role='form' class='form-signin' enctype="multipart/form-data" id='product-form'>
<div class='form-group'>
<label class='sr-only' for='name'>Name of the product</label>
<input type="text" class='form-control' placeholder="Name" name='name' id='name' />
</div>
<div class='form-group'>
<label class='sr-only' for='image'>Image of the product</label>
<input type="file" name='image' id='image' />
</div>
.
.
.etc...
and here is the server-side (api/controllers/ProductController.js) :
'create': function(req, res, next) {
// Include the node file module
var fs = require('fs');
console.log(req.files); //This logs : { } in the console
console.log(req.body.image); //This logs : undefined in the console
//Readfile with fs doesn't work cause req.files is empty
// fs.readFile(req.files.image.path, function(error, data) {
// //get image name
// var imageName = req.files.data.name;
// //if enable to get name
// if (!imageName) {
// console.log('error uploading image');
// res.redirect('/product/new');
// //Else if we have an image
// } else {
// //change the path to our own
// var newPath = __dirname + '/assets/images/products/fullsize/' + imageName;
// fs.writeFile(newPath, data, function(error) {
// console.log(newPath);
// //res.redirect('/product' + imageName);
// });
// }
// });
}
Thanks for your help.
Mat.
Also available here : https://github.com/balderdashy/sails/issues/1127

use method=post in your html form

Related

Save HTML form data to text file using node js

I am using node js and my requirement is save HTML form values which is sent by user, and store those values in text file using node js, and each time data should be save to next lines instead of saving to same line.I got stuck how to do this process.
HTML Code:
<form method="POST" action="/users/contact">
<select name="car" size="1" required id="rankx">
<option value="" selected disabled hidden>Option</option>
<option value="volvo">volvo</option>
<option value="swift">swift</option>
</select>
<br />
<select name="model" size="1" required>
<option value="" selected disabled hidden>Rank</option>
<option value="c500">c500</option>
<option value="Ta66">Ta66</option>
</select>
<input type="submit" value="Submit" name="submit" id="submit"/>
Node js Code:
var express = require('express');
var fs = require ('fs');
router.post("/contact",function(req,res){
let car = req.body.car;
let model = req.body.model;
var form_data = {
car: car,
model: model
}
fs.appendFileSync('./message.txt',form_data.toString());
});
Required outpt: // store in text file userData.txt
id carname carmodel
1 abc abc_1
2 xyz xyz_1
The solution what happens to me was first create a JSON file to save the data and next put this information in a text file. Following four steps:
Step 1: First you need read the existing data from JSON file.
Step 2: Add new car using push method.
Step 3: Write the new and old data in JSON file.
Step 4: Write the new info in the a text file.
Here is the code:
app.js
const express = require('express');
const app =express()
var fs = require ('fs');
// middleware
app.use(express.urlencoded({extended:true}))
// STEP 1: Read the existing data from json file
let users= require("./message.json")
// API routes
app.get('/', (req, res) => {
res.sendFile(__dirname + '/public/index.html');
})
app.post("/",function(req,res){
let car = req.body.car;
let model = req.body.model;
// new car
let formData = {
car: car,
model: model
}
res.send(formData)
// STEP 2: add new user data to users object using push method
users.push(formData)
// STEP 3: Writing data in a JSON file
fs.writeFile('message.json', JSON.stringify(users), err =>{
if(err) throw err
console.log("Done writting JSON file")
})
// STEP 4: Write the new info in the text file named message
fs.writeFile('./message.txt',JSON.stringify(users), err =>{
if(err) throw err
console.log("Done writting text file")
});
});
app.listen(3000, function(){
console.log("server started on port 3000")
})
You need create a JSON file to save data like this:
message.json
[]
and a empty message.txt to storage the data, this file overwrite when save the data.
Leave screenshots.
I hope help you.

ReCaptcha validation on Node.js

on my express server, g-recaptcha-response always return nothing. This is my code at the moment:
<div class=container-fluid id=mcenter>
<form id='monitstart' action="/monitstart" method="POST">
<input type="text" class="form-control" aria-label="..." name=>
<button class="g-recaptcha" data-sitekey="SITEKEYHERE" data-callback="onSubmit"></button>
</form>
</div>
and on my server
var express = require('express')
var router = express.Router()
var request = require('request')
router.post('/monitstart', function (req, res) {
request({url: "https://www.google.com/recaptcha/api/siteverify?secret=SECRETHERE&response=" + req.body['g-recaptcha-response']} + '&remoteip=' + req.connection.remoteAddress, function (err, response, body) {
req.send(body)
})
})
module.exports = router
And when I try to validate it, it give me a code 500 and say TypeError: Cannot read property 'g-recaptcha-response' of undefined
The correct answer, accepted by the OP during the short discussion below the question involves adding the body parsing middleware (the body-parser) to the pipeline so that the body property of the request object is correctly initialized before a value is read from there.

Uploading file from form to server

I am currently working on a dashboard, and have been stuck for some couple of hours now... What I like to do is to have a form including 3 <input type="file"> (two of them allow multiple files, one not), and each of them posting to 3 different post-methods in the server. When I try to console log the request on the server side the data is empty ({}) . I do not understand why, can someone please help me solve this issue?
I am using angularjs, and nodejs btw.
This is what my current code is : (files and paths are dummy-names)
HTML:
<form role="form" enctype="multipart/form-data">
<div class="form-group">
<label for="file1">File1:</label>
<input type="file" id="file1" accept=".txt, .json" multiple>
</div>
<div class="form-group">
<label for="file2">File2:</label>
<input type="file" id="file2" accept=".json">
</div>
<div class="form-group">
<label for="file3">File3:</label>
<input type="file" id="file3" multiple>
</div>
<button type="button" ng-click="save()" class="btn btn-default"> Save</button>
</form>
JS:
module.exports = function($scope, $http) {
$scope.save = function () {
file1(document.getElementById('file1').files);
file2(document.getElementById('file2').files);
file3(document.getElementById('file3').files);
};
function file1(files) {
$http.post('/file1', {f: files}).success(function (res) {
//todo
});
};
function file2(files) {
$http.post('/file2', {f: files}).success(function (res) {
//todo
});
};
function file3(files) {
$http.post('/file3', {f: files}).success(function (res) {
//todo
});
};
}
Server.js
var express = require("express"),
fs = require("fs"),
bodyParser = require('body-parser'),
app.use(express.static("build"));
app.use(bodyParser());
app.post('/file1', function (req, res) {
console.log(req.body.f) // returns empty: {}
// like to move files to path: a/b/c
});
app.post('/file2', function (req, res) {
// like to move files to path: a/d/e
});
app.post('/file3', function (req, res) {
// like to move files to path: a/f/g
});
Update:
after receiving the answer from GrimurD, I have modified the server.js, but still struggling. Any takers?
var express = require("express"),
fs = require("fs"),
bodyParser = require('body-parser'),
multer = require('multer'), //<-- updated
upload = multer({ dest: './uploads/' }) //<-- updated
app.use(express.static("build"));
app.use(bodyParser());
app.use(multer({ dest: './uploads/' }).array()); // <-- updated
app.post('/file1', upload.array('file1'), function (req, res) {
console.log(req.body.f) // returns empty: {}
console.log(req.files); // returns undefined // <-- updated
// like to move files to path: a/b/c
});
app.post('/file2', upload.single('file2'), function (req, res) {
console.log(req.file); // returns undefined // <-- updated
// like to move files to path: a/d/e
});
app.post('/file3', upload.array('file3'), function (req, res) {
console.log(req.files); // returns undefined // <-- updated
// like to move files to path: a/f/g
});
When uploading a file the form must use multipart/form-data which body-parser doesn't support. You must use a specialized middleware to handle this type. Multer is one such that I have used with success.
You can get around this using FileReader.readAsDataURL(..) on the File objects in the input fields. I often like to use the multi-select ability on the file input type so that I can upload a bunch of files and do this async.
So what I normally do is access the files property on the input element and loop through them, then I use the FileReader.readAsDataURL to get the base64 of the binary for the files then passing the base64 to a webserivce method with a signature that accepts that a string param for the base64, convert the b64 to binary and you're back in business.
var fileRunner = {
files: [],
run: function(el) {
this.files = el.files;
this.read();
},
read: function() {
// begin the read operation
console.log(this.files.length);
for (var i = 0; i <= this.files.length - 1; i++) {
var reader = new FileReader();
reader.readAsDataURL(this.files[i]);
reader.onload = this.process
}
},
process: function(evt) {
var result = evt.target.result
if (result.length > 0) {
var parts = result.split(',')
var dataBsf = parts[parts.length - 1];
console.log(dataBsf);
//call method to pass the base 64 here.
}
}
};
<body>
<input id="fup" type="file" multiple="multiple" onchange="fileRunner.run(this)" />
</body>
I did not include a server side component to this because I think that should be agnostic and slightly out of scope here.
I am only logging the output to the console, but you would take the output and pump it to the web service.
Additionally, I referenced the input element in the event handler for the onchange using "this" because I had no idea how you wanted to handle it. Allowing the passing of an element provided a bit of loose assumptions on my part.

jquery Return to same screen without refreshing screen

I have an upload view that needs to be used to upload three attachments. Now I used this code for the UI part in the view:
<div id="theDeliveryNoteContent">
<form action='Order/Save' method="post" enctype="multipart/form-data" id="deliveryNoteForm">
<div >
<label style="text-align: left;">Delivery note:</label>
<input type="file" name="DeliveryNoteFile" id="DeliveryNote" style="width: 400px;" />
<div style="margin-top:4px;margin-bottom:4px" >
<input type="submit" value="Upload" id="btnAddAttachment" />
</div>
</div>
</form>
</div>
Now the method that I want to call is situated inside my Orders controller. Here is the method I'm using. The code works fine until the return part.
[HttpPost]
public ActionResult Save(HttpPostedFileBase DeliveryNoteFile)
{
try
{
string customer = GetCustomerLinkedToPortalUser();
var uploadPath = "C:\\Attachments\\" + customer;
if (!Directory.Exists(uploadPath))
{
Directory.CreateDirectory(uploadPath);
}
if (DeliveryNoteFile != null)
{
var fileName = Path.GetFileName(DeliveryNoteFile.FileName);
var physicalPath = Path.Combine(uploadPath, fileName);
DeliveryNoteFile.SaveAs(physicalPath);
}
return RedirectToAction("Index");
}
catch (Exception)
{
throw;
}
}
The problem is that when the method returns to the screen it refreshes the screen and all the entered information is lost. I want to save the file to that directory and come back to the order screen and upload the next file. Now how I'm supposed to do that I'm not sure so that is what I need help with.
A colleague mentioned that I could use jQuery.Form script to do an ajax call so what I did is I added the jquery.form.js script to my project, did the referencing and I also added this to my javascript:
$("#deliveryNoteForm").ajaxForm({
target: "#theDeliveryNoteContent"
});
So now it returns to my screen, but it messes up the layout and refreshes the screen (seems) anyway. Is there any other easy way to return to the previous screen with the method which I used without losing all the entered information?
you need async file upload. Use this. Read some docs it is all simple.
Example:
Javascript initialize:
$(function () {
$('#DeliveryNote').fileupload({
dataType: 'json',
done: function (e, data) {
$.each(data.result.files, function (index, file) {
$('<p/>').text(file.name).appendTo(document.body);
});
}
});
});
Html:
<input id="DeliveryNoteFile" type="file" name="files[]" data-url="yourUploadController/Save/" style="width: 400px;" />
and remove submit button.

Set input values dynamically

I'm new to javascript, I'm working on a project that will using and enjoying the API of Last.fm.
But my question is the following:
I will make 2 fields:
First: Band name
Second: For fans of
When entering the name of the band I'll be sending a request to the last.fm API, but even there I am doing well.
The problem is that when I receive the request I want it automatically puts in the "For fans of" field.
I tried using the events onkeypress, onkeydown .. but have not had much success.
Anyone have any suggestions?
The request is made ​​through these files:
github.com/fxb/javascript-last.fm-api
My code is as follows:
Javascript:
/* Create a cache object */
var cache = new LastFMCache();
/* Create a LastFM object */
var lastfm = new LastFM(
{
apiKey : 'XXXXX',
apiSecret : 'XXXXXX',
cache : cache
});
function getName()
{
var bandname = $('#bandname').val();
var forfansof = $('#forfans').val();
forfansof = bandname;
/* Load some artist info. */
lastfm.artist.getSimilar(
{
artist: bandname
},
{
success: function(data)
{
/* Pega os 3 nomes das bandas similares */
for(var i = 0 ; i < 3 ; i++)
{
var artist = data.similarartists.artist[i].name;
$('#forfans').val($('#forfans').val() + artist + ", ");
}
},
error: function(code, message)
{
$('#forfans').val("Nenhum artista encontrado.");
}
});
}
HTML:
<form action="" method="post">
<input name="bandname" id="bandname" value="" onkeypress="javascript:getName();">
<input name="forfansof" id="forfans" style="width:300px;" value="">
</form>
I've have put the code that you have from GitHub into a fiddle, but I don't know anything about the API to say what needs to happen next.
Changes I made to fix immediate error that was shown in console.log
HTML
<form action="" method="post">
<input name="bandname" id="bandname" value="">
<input name="forfansof" id="forfans" style="width:300px;" value="">
</form>
JavaScript
document.getElementById("bandname").addEventListener("keypess", getName, false);
On jsfiddle

Categories