i am trying to diplay binary data image in angularjs html form.i am geeting two responses.i dono how to avoid that i have enclosed my screetshot.1st one is my response again it passing bad response please some one help me out.i have enclose client and server side controller
client side controller
'use strict';
/**
* #ngdoc object
* #name test1.Controllers.Test1Controller
* #description Test1Controller
* #requires ng.$scope
*/
angular
.module('test1')
.controller('Test1Controller', [
'$scope','$http' ,'$location','$window',
function($scope,$http, $location,$window)
{
$scope.image = {};
var image="download.jpg";
$http.get('*/upload/'+image).success(function(data,status,response)
{
console.log(data);
$scope.image=data;
var testJpg = $scope.image;
document.getElementById("myimage").src = testJpg;
});
}
]);
backend controller
'use strict';
var mongoose = require('mongoose'),
_ = require('lodash');
var Grid = require('gridfs-stream');
Grid.mongo = mongoose.mongo;
var gfs = new Grid(mongoose.connection.db);
exports.create = function(req, res) {
console.log(req.files.filefield);
var part = req.files.filefield;
var writeStream = gfs.createWriteStream({
filename: part.name,
mode: 'w',
content_type:part.mimetype
});
writeStream.on('close', function() {
return res.status(200).send({
message: 'Success'
});
});
writeStream.write(part.data);
writeStream.end();
};
exports.read = function(req, res) {
gfs.files.find({ filename: req.params.filename }).toArray(function (err, files) {
if(files.length===0){
return res.status(400).send({
message: 'File not found'
});
}
res.writeHead(200, {'Content-Type': files[0].contentType});
var readstream = gfs.createReadStream({
filename: files[0].filename
});
var bufs=[];
readstream.on('data', function(data) {
// res.write(data);
bufs.push(data);
}).on('end', function() {
// res.end();
var fbuf = Buffer.concat(bufs);
var base64 = (fbuf.toString('base64'));
//console.log(base64 );
res.end('"data:image/jpeg;base64,' + base64 + '";');
});
readstream.on('error', function (err) {
console.log('An error occurred!', err);
throw err;
});
});
};
<div ng-controller="Test1Controller" >
<img ng-src="" id="myimage" />
</div>
Related
I am using ng-file-upload to upload images and its title using the MEAN stack. Currently I can save the image but I am unable to fetch the data sent along.
Controller:
module.exports = function ($scope, Upload) {
let vm = this;
vm.uploadImage = function () {
if (vm.file) {
vm.file.upload = Upload.upload({
url: '/uploads/gallery',
method: 'POST',
data: { title: vm.title },
file: vm.file
});
vm.file.upload.then(function (response) {
$timeout(function () {
vm.file.result = response.data;
});
}, function (response) {
if (response.status > 0) { }
vm.errorMsg = response.status + ': ' + response.data;
}, function (evt) {
vm.file.progress = Math.min(100, parseInt(100.0 *
evt.loaded / evt.total));
});
}
}
vm.browseImage = function (file, errFiles) {
vm.file = file;
vm.errFile = errFiles && errFiles[0];
}
}
Route:
router.post('/gallery', (req, res) => {
//multers disk storage settings
let folder = './public/assets/images/gallery/';
let filename = '';
let imageLocation = '';
let thumbLocation = '';
let response = '';
//console.log(req.form);------throws undefined
//console.log(req.body);------throws undefined
let storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, folder)
},
filename: function (req, file, cb) {
var datetimestamp = Date.now();
filename = file.fieldname + '-' + datetimestamp + '.' + file.originalname.split('.')[file.originalname.split('.').length - 1];
imageLocation = folder + filename;
thumbLocation = folder + 'thumb' + filename;
cb(null, filename)
}
});
//multer settings
let upload = multer({
storage: storage
}).single('file');
upload(req, res, function (err) {
if (err) {
res.json({ error_code: 1, err_desc: err });
return;
}
else {
response = { fileCreated: true };
}
})
});
module.exports = router;
How can I get the string in my form in the route?
upload.single(...) is an express request handler. Multiple request handlers can be used with a router matcher such as the 'router.post' function in your code.
Thus, instead of having only a single request handler as you previously did as follows:
router.post('/gallery', (req, res) => {
...
...
}
You can rewrite your router like this:
router.post('/gallery', upload.single('file'), (req, res) => {
...
...
}
..where you use multiple request handlers.
In order to establish that, you should define multer instance outside your initial router matcher and your file should eventually look like this:
//i assume you have these in your file
const express = require("express");
const multer = require("multer");
let router = express.Router();
//multers disk storage settings
const folder = './public/assets/images/gallery/';
const filename = '';
const imageLocation = '';
const thumbLocation = '';
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, folder)
},
filename: function (req, file, cb) {
var datetimestamp = Date.now();
this.filename = file.fieldname + '-' + datetimestamp + '.' + file.originalname.split('.')[file.originalname.split('.').length - 1];
this.imageLocation = folder + filename;
this.thumbLocation = folder + 'thumb' + filename;
cb(null, filename)
}
});
//multer settings
const upload = multer({
storage: storage
});
router.post('/gallery', upload.single(), (req, res) => {
console.log(res.json);
});
module.exports = router;
I'm looking to change requestHandler.value to 5 for my functional styled tests.
When running the suite, creating 1000 documents in the db is not really an option, so is it possible to change it's value programmatically before running the suite and then reset it afterwards? I can create 5 documents in db before the test to work with.
Of coarse I can stub countDocumentsInDb() in unit tests to return what I need, but I've simplified logic below for the sake of the question.
app.js:
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var requestHandler = require('./lib/requestHandler.js');
var PORT = 4000;
app.route('/validate')
.get(function(req, res) {
requestHandler.process(req, res);
});
if (!module.parent) {
server.listen(PORT, function(err) {
if (err) {
return;
}
});
}
module.exports = app;
requestHandler.js:
var requestHandler = {
value: 1000,
process: function(req, res) {
numberOfDocumentsInDb = countDocumentsInDb();
if (numberOfDocumentsInDb === this.value) {
res.send(true);
} else {
res.send(false);
}
}
};
module.exports = requestHandler;
FVT style test ..
var Promise = require('promise');
var request = require('supertest');
var chai = require('chai');
chai.should();
var server = require('../../app.js');
describe('app.js', function() {
describe('/validate', function() {
it('should return true if number of documents in db matches pre-defined value', function(done) {
var fvtPromise = new Promise(function(fulfill) {
request(server)
.get('/validate')
.expect(200)
.end(function(err, res) {
if (err) {
throw err;
}
res.body.should.equal(true);
fulfill(null);
});
});
fvtPromise.done(function() {
done();
});
});
});
});
You can play with the require.cache, that will allow you to modify the values of requestHandler.
Is just an example I hope you get the idea.
- In the before each modify the require cache and set your test values
-In the after each set back the original values
-Please notice that the const server = require('./app.js'); is inside the test, so it will take the cache vales
e.g.
describe('test with cache', function(){
require('./requestHandler');
let originalValues;
beforeEach(function() {
originalValues = require.cache[ require.resolve('./requestHandler') ].exports;
require.cache[ require.resolve('./requestHandler') ].exports = {
value:5,
process: function(req, res) {
//other stuff
}
};
});
afterEach(function() {
require.cache[ require.resolve('./requestHandler') ].exports = originalValues;
});
it('should pass', function(){
const server = require('./app.js');
var fvtPromise = new Promise(function(fulfill) {
request(server)
.get('/validate')
.expect(200)
.end(function(err, res) {
if (err) {
throw err;
}
res.body.should.equal(true);
fulfill(null);
});
});
fvtPromise.done(function() {
done();
});
expect(true).to.be.true;
});
});
New to node and trying not to do any callback hell.
I have two files
routes.js
fetch.js
//routes.js
var fetchController = require("../lib/mtl_fetcher/fetcher_controller");
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.send(fetchController.getAllTransgressor(function(results) {
return results.end();
}))
});
module.exports = router;
and
//fetch.js
var http = require('http');
var config = require('./config')
var Iconv = require('iconv').Iconv
module.exports.getAllTransgressor = function(callback) {
var req = http.get(config.urlOptions.host, function (response) {
var bufferChunk = [];
var str
if(response.statusCode == 200) {
response.on('data', function(chunk) {
bufferChunk.push(chunk);
})
response.on('end', function(callback) {
var iconv = Iconv('latin1', 'UTF-8');
str = iconv.convert(Buffer.concat(bufferChunk)).toString();
console.log(str)
});
} else {
console.log("handle this")
}
});
req.on("error", function(err) {
callback(err);
});
callback(req)
}
So the goal is to fetch and then show what has been fetch to the screen. The ressource is XML base.
Doing all of this in one block (routes.js) works, but when I try to refactor and set up some modularity my str just shows in shell stdout.
Using req.end() does not send the content back.
Firstly, you need to send inside the callback, where the result is actually available, as you can't return from an asynchronous function
router.get('/', function(req, res, next) {
fetchController.getAllTransgressor(function(error, results) {
if ( error ) {
// handle errors
} else {
res.send(results);
}
});
});
The same goes for the callback function, it has to be called when the data is available, after the request and parsing
module.exports.getAllTransgressor = function(callback) {
var req = http.get(config.urlOptions.host, function(response) {
var bufferChunk = [];
if (response.statusCode == 200) {
response.on('data', function(chunk) {
bufferChunk.push(chunk);
});
response.on('end', function() {
var iconv = Iconv('latin1', 'UTF-8');
var str = iconv.convert(Buffer.concat(bufferChunk)).toString();
callback(null, str); // here, stuff is available
});
} else {
callback('Did not return 200', err);
}
});
req.on("error", function(err) {
callback(err, null);
});
}
I’m using this tutorial, which is based on the MEAN stack.
I want to store photographs that users can upload with MongoDB on a server.
included: Angular directive to upload files
create-spot.client.view.html
<div data-ng-controller="SpotsCreateController">
<form class="form-signin" data-ng-submit="create(picFile)" novalidate>
<label>Upload an image</label>
<input type="file" id="articleimage" ng-model="picFile" ng-file-select="" ng-file-change="generateThumb(picFile[0], $files)" multiple name="file" accept="image/*">
<img ng-show="picFile[0].dataUrl != null" ng-src="{{picFile[0].dataUrl}}" class="img-thumbnail" height="50" width="100">
<span class="progress" ng-show="picFile[0].progress >= 0">
<div style="width:{{picFile[0].progress}}%" ng-bind="picFile[0].progress + '%'" class="ng-binding"></div>
</span>
<span ng-show="picFile[0].result">Upload Successful</span>
<input type="submit" class="btn btn-lg btn-primary btn-block" ng-click="uploadPic(picFile)">
<div data-ng-show="error">
<strong data-ng-bind="error"></strong>
</div>
</form>
</div>
view-spot.client.view.html
<div data-ng-controller="SpotsViewController">
<section data-ng-init="findOne()">
<img ng-src="data:image/jpeg;base64,{{spot.image}}" id="image-id" width="200" height="200"/>
</section>
</div>
application.js
var app = angular.module('newApp', ['ngAnimate', 'ngCookies', 'ngResource', 'ngRoute', 'ngSanitize', 'ngTouch', 'ui.bootstrap', 'users', 'spots']);
spots.create.client.controller.js
angular.module('spots').controller('SpotsCreateController', ['$scope', '$timeout', 'Authentication', 'Spots', '$location'
function($scope, $timeout, Authentication, Spots, $location) {
$scope.authentication = Authentication;
$scope.fileReaderSupported = window.FileReader !== null;
$scope.create = function(picFile) {
var spot = new Spots({
title: this.title,
description: this.description,
image: null
});
spot.$save(function(response) {
$location.path('spots/' + response._id);
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
$scope.doTimeout = function(file) {
$timeout( function() {
var fileReader = new FileReader();
fileReader.readAsDataURL(file);
fileReader.onload = function(e) {
$timeout(function() {
file.dataUrl = e.target.result;
});
};
});
};
$scope.generateThumb = function(file) {
if (file) {
if ($scope.fileReaderSupported && file.type.indexOf('image') > -1) {
$scope.doTimeout(file);
}
}
};
spot.server.model.js
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var SpotSchema = new Schema({
...
image: {
type: String,
default: '',
required: false
}
});
mongoose.model('Spot', SpotSchema);
spots.server.routes.js
var multiparty = require('connect-multiparty'),
multipartyMiddleware = multiparty();
module.exports = function(app) {
app.route('/api/spots')
.get(spots.list)
.post(users.requiresLogin, multipartyMiddleware, spots.create);
app.route('/api/spots/:spotId')
.get(spots.read)
.put(users.requiresLogin, spots.hasAuthorization, spots.update)
.delete(users.requiresLogin, spots.hasAuthorization, spots.delete);
app.param('spotId', spots.spotByID);
};
spots.server.controller.js
var mongoose = require('mongoose'),
fs = require('fs'),
Spot = mongoose.model('Spot');
exports.create = function(req, res) {
if (req.files.file) {
var file = req.files.file;
}
var spot = new Spot(req.body);
spot.creator = req.user;
fs.readFile(file.path, function (err,original_data) {
if (err) {
return res.status(400).send({
message: getErrorMessage(err)
});
}
var base64Image = original_data.toString('base64');
fs.unlink(file.path, function (err) {
if (err) {
console.log('failed to delete ' + file.path);
} else {
console.log('successfully deleted ' + file.path);
}
});
spot.image = base64Image;
spot.save(function(err) {
if (err) {
return res.status(400).send({
message: getErrorMessage(err)
});
} else {
res.json(spot);
}
});
});
};
What did I do wrong? Please consider that I want to limit the file sizes, and I thought using base64 is good start. The issue is that the photograph is not stored in the database because the controller doesn’t work with the rest.
What exactly is the problem you are experiencing, and at what step is it going wrong?
For Express backend apps I usually use multer middleware for handling file uploads. Also, I create separate routes/controllers for dealing with the files rather than trying to process them at the same time I'm saving the parent object. This allows me to separate the logic nicely and not worry about the parent object not being saved when the file upload fails. You could use the JS API for ng-file-upload to handle that in Angular.
Example routes in Express (we have a "club" with a "logo" image here):
router.post(
'/logo',
ensureAuthenticated, ensureAdmin,
logoCtrl.upload,
logoCtrl.save
);
router.get(
'/:clubId/logo.*',
logoCtrl.stream
);
Example controller methods:
let multer = require('multer');
module.exports = {
/**
* Upload logo
*/
save(req, res, next) {
//Get club and file
let club = req.user.club;
let file = req.file;
//Update
club.logo = {
data: file.buffer,
mimeType: file.mimetype
};
//Save
club.save()
.then(() => {
res.end();
})
.catch(next);
},
/**
* Stream logo
*/
stream(req, res, next) {
let club = req.club;
res.contentType(club.logo.mimeType);
res.send(club.logo.data);
},
/**
* Upload middleware
*/
upload(req, res, next) {
//Create upload middleware
let upload = multer({
storage: multer.memoryStorage(),
limits: {
fileSize: 50000000
}
}).single('logo');
//Use middleware
upload(req, res, next);
}
};
So as you can see, it's quite simple with multer and all you really need is one route for uploading the logo, with two controller methods, one to register the multer middleware and process the file, and the other to save it to the MongoDB (in this case attached to the club in the request).
Just make sure that ng-file-upload uses the same field name for uploading the file as multer is expecting. In the above example that's "logo". If you're unsure, check in the request what your client app is sending to the server and make sure the server app is expecting the same field name.
Let me know if you have further trouble.
You can use formidable and gridfs-stream
//controller
var mongoose = require('mongoose'),
fs = require('fs'),
Spot = mongoose.model('Spot');
exports.create = function(req, res) {
handleRequest(req, function(err, spot) {
if(err) {
return res.status(400).send({
message: getErrorMessage(err)
});
}
res.json(spot);
});
};
function handleRequest(req) {
var spot = new Spot(req.body);
spot.creator = req.user;
var formidable = require('formidable');
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
if (err) {
return done(err);
}
var file = files.qqfile;
if (file && file.name && file.name.trim !== '') {
if (file.size > 5000000) {
message = 'file is too large';
}
if (!file.type) {
message = 'file is not an image';
}
if (file.type.indexOf('image/') !== 0) {
message = 'file is not an image type';
}
}
if (message) {
logger.info('Uploading failed', file, message);
return done(message);
}
uploadFile(mongoose.connection, 'Pictures', files.qqfile, require('uuid').v1(), function(err) {
if (err) {
return done(err);
}
if (!data) return done(false, null);
if (typeof data === 'string') {
data = JSON.parse(data);
}
logger.info('[PHOTOS]', 'Uploaded', data.filename);
photo = {
unique_id: token,
name: file.name,
contentType: file.type
};
spot.photos = spot.photos || [];
spot.photos.push(photo);
spot.markModified('photos');
spot.save(done);
});
});
}
function uploadFile(DB, className, data, token, callback) {
var grid = require('gridfs-stream');
var gfs = grid(DB.db, mongoose.mongo);
var writestream = gfs.createWriteStream({
filename: token,
root: className
});
writestream.on('close', function (file) {
return callback(null, file);
});
if (data.path) {
var fs = require('fs');
if (!fs.existsSync(data.path)) {
return callback(false);
}
var pipe = false;
if (data.pipe) {
pipe = data.pipe;
} else {
var fs = require('fs');
if (!fs.existsSync(data.path)) {
return callback(false);
}
var rs = fs.createReadStream(data.path);
pipe = rs.pipe.bind(rs);
}
return pipe(writestream);
} else {
logger.error('[PHOTO] no path', data);
}
callback(false);
}
I´m storing images from my angular app in MongoDB using GridFs. But i cant figure out, how to GET the images out of the DB to the app?
I´m using a custom objectId for the query.
EDIT
It looks like the GET part now works, but then there was no media in the collection. I played a bit with the code, and now I can see fs.chunks and fs.files in the database. I think the problem is, that I try to query for metadata in the GET request. This returns no response data. Anybody got an idea how to fix this?
var fs = require('fs');
var conn = mongoose.connection;
var Grid = require ('gridfs-stream');
Grid.mongo = mongoose.mongo;
var gfs = Grid (conn.db);
var buffer = "";
app.post('/uploads/', multer({
upload: null,
onFileUploadStart: function (file, req){
this.upload = gfs.createWriteStream({
filename: file.originalname,
metadata:{"objectId" : req.body.project_id},
mode: "w",
chunkSize: 1024*4,
content_type: file.mimetype,
root: "fs",
});
},
onFileUploadData: function(file, data) {
this.upload.write(data);
},
onFileUploadComplete: function(file, res) {
done=true;
}
}), function(req, res){
res.status(200);
res.send("Success!");
});
app.route('/uploads/media/:projectId').get(function (req, res){
var readstream = gfs.createReadStream({
"metadata.objectId" : req.params.projectId
});
res.set('Content-Type', 'image/jpeg');
readstream.pipe(res);
});
You need to write the stream back out to your response. Here is another similar question. But basically you either need to pipe the stream to your response, or use the stream's end event and write the result to your response. The following code pipes to the response and sets a content-type of image/jpeg.
app.get('/uploads/:objectId', function(req, res){
var options = {
_id : req.params.objectId
};
gfs.exist(options, function(err, exists) {
if(!exists) {
res.status(404);
res.end();
} else {
var readstream = gfs.createReadStream(options);
res.set('Content-Type', 'image/jpeg');
readstream.pipe(res);
}
});
});
var pi_id = fields.pic_id;
gfs.findOne({ _id: pi_id }, function (err, file) {
console.log(file);
if (err) return res.status(400).send(err);
if (!file) return res.status(404).send('');
res.set('Content-Type', file.contentType);
res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
var readstream = gfs.createReadStream({
_id: file._id
});
readstream.on("error", function(err) {
console.log("Got error while processing stream " + err.message);
res.end();
});
readstream.pipe(res);
console.log(readstream.pipe(res))
});