ng-file-upload send array into database - angularjs

i want to upload array of data that i have by using ng-file-upload, but if i repeat it, my database only got last image, can anyone know what's wrong with my code?
Here is my code
$scope.send = function () {
console.log("aaa " + $scope.file);
console.log("files total: " + $scope.portfolio_images_array.length);
if ($scope.file && $scope.file1 && $scope.portfolio_images_array.length > 0) {
Upload.upload({
url: 'upload_url',
data: {
user_id: 7,
profile_photo: $scope.file,
id_card_photo: $scope.file1,
name: $scope.name,
introduction: $scope.introduction,
portfolio_image: $scope.portfolio_images_array
}
}).then(function (resp) {
console.log('Success ');
}, function (resp) {
console.log('Error status: ' + resp.status);
}, function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + progressPercentage + '% ');
});
}
};
portfolio_image should get all the images, but now it only get the last image from portfolio_images_array.
For adding the data to portolio_image_array, i use this code:
$scope.addFiles = function (file) {
console.log(file);
$scope.portfolio_images_array.push(file);
}
Please help me with this, Thanks

i found an answer, we just need to add arrayKey, here is the code
$scope.send = function () {
if ($scope.file && $scope.file1 && $scope.portfolio_images_array.length > 0) {
Upload.upload({
url: 'uploadURL',
arrayKey: '',
data: {
user_id: 7,
profile_photo: $scope.file,
id_card_photo: $scope.file1,
name: $scope.name,
introduction: $scope.introduction,
portfolio_image: $scope.portfolio_images_array
}
}).then(function (resp) {
console.log('Success ');
}, function (resp) {
console.log('Error status: ' + resp.status);
}, function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + progressPercentage + '% ');
});
}
};

Upload.upload is in fact a http request.
What you are doing is looping through all your array and make a http request for each file.
This is already really bad, and you should send the array directly with a syntax like this :
Upload.upload({
url: storageService.Address_of_your_server + '/your/route',
file: file,
arrayKey: '',
data: data,
}).success(function (resp) {
cbfun(resp);
});
}
Where file is your array of files and data your json of data you want to send in the same time.
The fact you are receiving only the last image is a bit weird.
Two ideas comes to my mind :
Upload service stop the request if he is called another time while the request is not finished.
As you are looping in a synchronous way while using asynchronous functions into your loop. Consequently, the javascript excecutes very quickly the loop and the i is incremented before even sending the requests.
But I don't really think this is the second possibility, as this case should only happen if you use the i variable in the callback of your promise (then).
EDIT :
Why you need to use ArrayKey :
This is to accommodate server implementations expecting array data object keys in '[i]' or '[]' or ''(multiple entries with same key) format.
So if you are not using it, the server part won't understand the format of the request.
According to the official doc.
Also, if you are using NodeJS, it is almost sure you are using the multer middleware in the back-end.
Consequently, you should have a route like this in the back :
router.post('/your/route', upload.array('file'), function(req, res){
//Your files are in this variable
var files = req.files
}

Related

NodeJS & Angular Image upload

Tried lot of available Internet tutorials, but I still can't make it functional. I use multer module in NodeJS and ng-file-upload in AngularJS. I made two helpers with multer settings( because I have two scenarios and both uploads must go to different folders). Backend files are in APP/APP_BACK/ folder, so in destination path I go back one folder and enter APP_FRONT/images/header. Here is one helper snippet (/helpers/uploadHeader.js):
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, '../APP_FRONT/images/header/');
},
filename: function (req, file, callback) {
var ext = filename.slice((filename.lastIndexOf(".") - 1 >>> 0) + 2);
callback(null, file.fieldname + '-' + '.' + ext);
}
});
var upload = multer(
{storage: storage}
);
var helper = {
upload: upload
};
module.exports = helper;
Here is router file:
var headerHelper= require('../helpers/uploadHeader');
router.post('/header', headerHelper.upload.single('header'), function(req, res, next) {
headerHelper.upload(req, res, function(err){
if(err){
res.status(400).send(err);
console.log(err);
return;
}
res.status(200).send({ code:200, message:'Header upload successful!' });
});
});
"header" would be name of input form or key value in Postman.
In Angular, I injected 'ngFileUpload' module in app, and injected 'Upload' service into desired controller and used it inside uploadHeader() function which is bound on button inside form on clientside:
$scope.uploadHeader = function (file) {
Upload.upload({
url: 'http://localhost:3003/upload/header',
method: 'POST',
file: file
}).then(function (response) {
console.log('Success ' + response.config.data.file.name + 'uploaded. Response: ' + response.data);
}, function (error) {
console.log('Error status: ' + error.status);
}, function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + progressPercentage + '% ' + evt.config.data.file.name);
});
I tried with Postman:
Postman request SS
And get this error:
"Error: ENOENT: no such file or directory, open 'c:\Users\Username\Desktop\APP\APP_FRONT\images\header\header.jpg'"
When I try from clientside, I get these errors:
"Error: Unexpected field at makeError "
and
"TypeError: dbg is undefined"
I already consulted Google, tried some of tutorials but got stuck on this.
In your router, you are telling multer to look for an object called "header" in the mulitpart form data. Your angularJS code is adding it as an object called 'file'.
If you change the line in your router from:
router.post('/header', headerHelper.upload.single(**'header'**), function(req, res, next) {
//.....
}
to:
router.post('/header', headerHelper.upload.single(**'file'**), function(req, res, next) {
//....
}
It should do the trick.
EDIT: solution found
Actually, it was problem in filename function in multer's storate settings. In above post, I appended datetimestamp and file extension to fieldname:
filename: function (req, file, callback) {
var datetimestamp = moment().format('DD-MM-YY_HH:mm:ss');
var filename = file.originalname;
var ext = filename.slice((filename.lastIndexOf(".") - 1 >>> 0) + 2);
callback(null, file.fieldname + '-' + datetimestamp + '.' + ext);
}
For some reason, it couldn't finish upload and I got error.
I changed filename function to return only file's originalname :
filename: function (req, file, callback) {
callback(null, file.originalname);
}
and now everything is OK. But now, question is, why custom filename doesn't work?

nodejs write simple image blob - Upload.dataUrltoBlob

Simple question. How do I save a image blob in Nodejs from angular.
AngularSide:
$scope.upload = function (dataUrl, picFile) {
Upload.upload({
url: 'http://test.dev:3000/register/user/uploads',
data: {
file: Upload.dataUrltoBlob(dataUrl, picFile.name)
},
}).then(function (response) {
$timeout(function () {
$scope.result = response.data;
});
}, function (response) {
if (response.status > 0) $scope.errorMsg = response.status
+ ': ' + response.data;
}, function (evt) {
$scope.progress = parseInt(100.0 * evt.loaded / evt.total);
});
}
nodejs side: Do I need middleware here? if so which one should I use?
router.post('/user/uploads', multipartMiddleware, function(req, resp) {
var newPath = "/Users/testUser/test_hold_files/" + req.files.file.originalFilename;
fs.writeFile(newPath, req.files.file, function(err) {
if (err) {
console.log("Data Error ");
return console.error(err);
}
});
res.status(200).jsonp({status: "status: success "});
});
right now this just writes out the file with correct name but its empty.
You used to be able to access the uploaded file through req.files.imageName and then you would fs.readFile from tmp and write it permanently, which is no longer the case in express 4.0
In Express 4, req.files is no longer available on the req object by default. To access uploaded files on the req.files object, use multipart-handling middleware like busboy, multer, formidable, multiparty, connect-multiparty, or pez.
Soooooooo, you can feel free to use which ever one of those middlewares names above and then follow their API for dealing with uploaded files like images. Hope this helps, enjoy.
Ok,
After a long time of messing with this stuff. I found an answer. It does load the file in my folder.
I feel this is only partial since it does not resize the actual file smaller. It is what is selected with https://github.com/danialfarid/ng-file-upload. I used the
Upload.upload({
url: 'http://test.dev:3000/register/user/uploads',
data: {
file: Upload.dataUrltoBlob(dataUrl, picFile.name)
},
This did zoom into the file on selected image. It did not make the actual file size smaller. I am still looking into this issue.
var formidable = require('formidable'),
util = require('util'),
fs_extra = require('fs-extra');
This is my post to accept images.
router.post('/user/uploads', function (req, res){
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
res.end(util.inspect({fields: fields, files: files}));
});
form.on('end', function(fields, files) {
/* Temporary location of our uploaded file */
var temp_path = this.openedFiles[0].path;
/* The file name of the uploaded file */
var file_name = this.openedFiles[0].name;
/* Location where we want to copy the uploaded file */
var new_location = "/Users/testUser/test_hold_files/";
fs_extra.copy(temp_path, new_location + file_name, function(err) {
if (err) {
console.error(err);
} else {
console.log("success!")
}
});
});
});
I have also noticed that I can view the file in chrome but not load it into gimp. Gimp gives me a file error.
Small steps I guess.
Maybe Datsik can give us some insight on what is going on here.
https://stackoverflow.com/users/2128168/datsik
Phil

How to reset global Basic Authentication header in AngularJS?

In my angular app the global $http headers are defined for every request, like this:
function useBasicAuth(username, hash) {
var encoded = btoa(username + ':' + hash);
$http.defaults.headers.common.Authorization = 'Basic ' + encoded;
}
How to disable sending this information, when for example the user logs out, and the authentication is no longer required?
What I found as a working solution was to redeclare the $http.defaults.headers.common Object so it won't contain the headers.
Example:
function useBasicAuth(username, hash) {
var encoded = btoa(username + ':' + hash);
$http.defaults.headers.common.Authorization = 'Basic ' + encoded;
}
This, however won't delete the cached credentials from the browser. To overcome this, I've made a simple - and not asynch call to generate a bad request on purpose.
This is the function for this in my accountServices factory:
function checkAuth(username, hash) {
var encoded = btoa(username + ':' + hash);
var result = false;
$.ajax({
type: "POST",
beforeSend: function (request) {
request.setRequestHeader("Authorization", 'Basic ' + encoded);
},
url: "user/current",
statusCode: {
401: function () {
result = false;
},
200: function (response) {
result = response;
}
},
async: false
});
return result;
}
To log the user out, I call this function:
function useBasicWithoutAuth() {
accountServices.checkAuth('logout','logout');
$http.defaults.headers.common = {Accept: "application/json, text/plain, */*"};
}
So what this does, is it first sends a request to a protected URL, with a fake and non-existant user, so it's basically the same, as if the prompt would appear to you, and you'd click cancel.
After this has been done, there's no cached data in the browser, we can simply remove the headers from Angular, so it won't send any Authorization information, where it's not needed.

How do I use $resource to post to a web-service?

I'm not very good with angular. I want to post to a web service, sending some xml with my search parameters. I don't want to send the parameters in the query string. I've read the official documentation, but I'm still confused. I'm mostly hung up on how to define the $resource to be able to post the way I want.
The error I get is: POST 'https://someWebservice/searchnet'::ERR_INSECURE_RESPONSE
My code is below:
'use strict';
angular.module('app').controller('inventorySearchController', inventorySearchController);
inventorySearchController.$inject = ['$scope','$http', '$resource'];
function inventorySearchController($scope, $http, $resource) {
console.log("controller initialized...");
$scope.callService = function(){
console.log("callService function called...");
var urlSearchService = 'https://someWebservice/search';
var skuVal = $scope.skuField;
var mVenVal = $scope.mVendorField;
//need to somehow specifiy that xml is a #FormParam
var xmlItemSearchRequest = "<ItemSearchRequest>"
+"<skuid>" + skuVal + "</skuid>"
+"<mvendor>" + mVenVal + "</mvendor>"
+"</ItemSearchRequest>";
console.log('calling: ' + urlSearchService + 'sending xml: ' + xmlItemSearchRequest);
var Results = $resource(urlSearchService, {
save: {
method: 'POST',
isArray: true
}
});
var result = Results.save();
console.log('Results: ' + Results);
console.log('result: ' + result);
var successfunction = function(){
$scope.searchResults = data;
console.log('call to ' + urlSearchService + ", was a success.");
};
var errorfunction = function(){
console.error('Calling error', status, data);
};
};
};
The error shown is not about how you posted data. Instead, response was not signed by a valid SSL certificate (or the certificate could not be accepted). That is due to the use of HTTPS protocol. You should consider using HTTP instead.
You can try the approach suggested here to confirm that this is the case.

Using Node Buffer or fileStream with formData file upload

Update: I have more or less solved the problem using multipart (app.use(multipart({uploadDir: __dirname + '/../uploads'}))from these instructions), but still don't know why my original code (below) fails.
There have been numerous variations on this question, and I have tried the ideas there without success. I'm using a file uploading directive (and have since tried another open source alternative) to send a binary file to a node server, that runs the following code (based on an SO answer I can't now refind):
exports.receive = function(req, res) {
var fitFileBuffer = new Buffer('');
// req.setEncoding("binary"); //doesn't help
req.on('data', function(chunk) {
fitFileBuffer = Buffer.concat([fitFileBuffer, chunk]);
});
req.on('end', function() {
fs.writeFileSync(
"today2.fit",
fitFileBuffer,
'binary');
res.send(200);
});
};
If I upload today.fit and compare to today2.fit, they have the same Kb of data, but are not identical, and subsequent code fails to process the file. Given that this happens with two pieces of third party code I suspect the problem lies with my code.
Here are the details from the client side of the POST being made
In the end, when I realised that I wanted to avoid saving to disk, I modified generalhenry's code with some stuff from busyboy's site and my own use of a Buffer:
exports.receive = function (req, res, next) {
var busboy = new Busboy({ headers: req.headers });
var fileBuffer = new Buffer('');
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
file.on('data', function(data) {
console.log('File [' + fieldname + '] got ' + data.length + ' bytes');
fileBuffer = Buffer.concat([fileBuffer, data]);
});
file.on('end', function() {
console.log('File [' + fieldname + '] Finished');
genXmlFromString(fileBuffer.toString(), function(data) {
res.json(data);
});
});
});
busboy.on('finish', function() {
console.log("'finish'");
});
req.pipe(busboy);
};
UPDATE: the client post details helped. You're not posting a file stream (which would have worked) you're posting a form stream. The good news is there are good modules for handling form streams.
You'll need to pipe the request stream into a form handling stream (such as busboy) which will handle the ------WebKitFormBoundary. . . part and them give you the file(s) as stream(s)
https://github.com/mscdex/busboy
var Busboy = require('busboy');
exports.receive = function(req, res, next) {
var busboy = new Busboy({ headers: req.headers });
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
var fileWriteStream = fs.createWriteStream('today2.fit');
file.pipe(fileWriteStream);
});
busbody.on('finish', function() {
res.send(201);
});
req.pipe(busboy);
};

Resources