node.js - tutorial - MEAN Apilar archivos cargados
node js tutorial (4)
Recientemente comencé a programar con MEAN Stack y actualmente estoy implementando algún tipo de red social. He estado utilizando el marco MEAN.io para hacerlo. Mi principal problema ahora es hacer que la carga del archivo funcione, porque lo que quiero hacer es recibir el archivo del formulario en el Controlador AngularJS y pasarlo junto con más información a ExpressJS para que finalmente pueda enviar todo a MongoDB. (Estoy construyendo un formulario de registro de nuevo usuario).
No quiero almacenar el archivo en la base de datos, pero quiero almacenar un enlace a él.
He buscado docenas de páginas en google con diferentes consultas de búsqueda pero no pude encontrar nada que pudiera entender o que funcionara. He estado buscando durante horas sin ningún resultado. Por eso he venido aquí.
Puede alguien ayudarme con esto?
Gracias :)
EDIT: Tal vez un poco del código ayudaría a entender.
El controlador Angular de los Usuarios de MEAN.io predeterminado que estoy usando como base tiene esto:
$scope.register = function(){
$scope.usernameError = null;
$scope.registerError = null;
$http.post(''/register'', {
email: $scope.user.email,
password: $scope.user.password,
confirmPassword: $scope.user.confirmPassword,
username: $scope.user.username,
name: $scope.user.fullname
})//... has a bit more code but I cut it because the post is the main thing here.
};
Lo que quiero hacer es: Recibir un archivo desde un formulario, a este controlador y pasarlo junto con el correo electrónico, la contraseña, el nombre, etc., y poder usar el json en expressjs, que se encuentra en el lado del servidor. El ''/ register'' es una ruta de nodejs, por lo que un controlador de servidor crea al usuario (con el esquema del usuario) y lo envía a MongoDB.
La carga media ha sido obsoleta y ahora se llama "subir". Se gestiona en - git.mean.io/orit/upload
Recientemente hice algo como esto. Utilicé angular-file-upload . También querrá node-multiparty para que su punto final analice los datos del formulario. Entonces podrías usar s3 para subir el archivo a s3.
Aquí hay algo de mi código [editado].
Plantilla angular
<button>
Upload <input type="file" ng-file-select="onFileSelect($files)">
</button>
Controlador angular
$scope.onFileSelect = function(image) {
$scope.uploadInProgress = true;
$scope.uploadProgress = 0;
if (angular.isArray(image)) {
image = image[0];
}
$scope.upload = $upload.upload({
url: ''/api/v1/upload/image'',
method: ''POST'',
data: {
type: ''profile''
},
file: image
}).progress(function(event) {
$scope.uploadProgress = Math.floor(event.loaded / event.total);
$scope.$apply();
}).success(function(data, status, headers, config) {
AlertService.success(''Photo uploaded!'');
}).error(function(err) {
$scope.uploadInProgress = false;
AlertService.error(''Error uploading file: '' + err.message || err);
});
};
Ruta
var uuid = require(''uuid''); // https://github.com/defunctzombie/node-uuid
var multiparty = require(''multiparty''); // https://github.com/andrewrk/node-multiparty
var s3 = require(''s3''); // https://github.com/andrewrk/node-s3-client
var s3Client = s3.createClient({
key: ''<your_key>'',
secret: ''<your_secret>'',
bucket: ''<your_bucket>''
});
module.exports = function(app) {
app.post(''/api/v1/upload/image'', function(req, res) {
var form = new multiparty.Form();
form.parse(req, function(err, fields, files) {
var file = files.file[0];
var contentType = file.headers[''content-type''];
var extension = file.path.substring(file.path.lastIndexOf(''.''));
var destPath = ''/'' + user.id + ''/profile'' + ''/'' + uuid.v4() + extension;
var headers = {
''x-amz-acl'': ''public-read'',
''Content-Length'': file.size,
''Content-Type'': contentType
};
var uploader = s3Client.upload(file.path, destPath, headers);
uploader.on(''error'', function(err) {
//TODO handle this
});
uploader.on(''end'', function(url) {
//TODO do something with the url
console.log(''file opened:'', url);
});
});
});
}
Cambié esto de mi código, por lo que puede que no funcione fuera de la caja, ¡pero espero que sea útil!
Recientemente, se agregó un nuevo paquete a la lista de paquetes en mean.io. ¡Es una belleza!
Simplemente ejecute:
$ significa instalar mean-upload
Esto instala el paquete en la carpeta del nodo pero tiene acceso a las directivas en sus paquetes.
http://mean.io/#!/packages/53ccd40e56eac633a3eee335
En su vista de formulario, agregue algo como esto:
<div class="form-group">
<label class="control-label">Images</label>
<mean-upload file-dest="''/packages/photos/''" upload-file-callback="uploadFileArticleCallback(file)"></mean-upload>
<br>
<ul class="list-group">
<li ng-repeat="image in article.images" class="list-group-item">
{{image.name}}
<span class="glyphicon glyphicon-remove-circle pull-right" ng-click="deletePhoto(image)"></span>
</li>
</ul>
</div>
Y en tu mando:
$scope.uploadFileArticleCallback = function(file) {
if (file.type.indexOf(''image'') !== -1){
$scope.article.images.push({
''size'': file.size,
''type'': file.type,
''name'': file.name,
''src'': file.src
});
}
else{
$scope.article.files.push({
''size'': file.size,
''type'': file.type,
''name'': file.name,
''src'': file.src
});
}
};
$scope.deletePhoto = function(photo) {
var index = $scope.article.images.indexOf(photo);
$scope.article.images.splice(index, 1);
}
¡Disfrutar!
Sé que este post es viejo. Lo encontré y @kentcdodds tuvo una respuesta que realmente me gustó, pero las bibliotecas que usó ahora están desfasadas y no pude hacer que funcionen. Entonces, después de algunas investigaciones, tengo una nueva solución similar que quiero compartir.
HTML usando ng-upload
<form >
<div style="margin-bottom: 15px;">
<button type="file" name="file" id="file" ngf-select="uploadFiles($file, $invalidFiles)" accept="image/*" ngf-max-height="1000" ngf-max-size="1MB">Select File</button>
</div>
</form>
INCLUYE el módulo ng-upload
Descárgalo, referencia los archivos e incluye el módulo.
var app = angular.module(''app'', [''ngFileUpload'']);
Esto le dará acceso al servicio de Upload
.
Código del controlador
$scope.uploadFiles = function(file, errFiles) {
$scope.f = file;
$scope.errFile = errFiles && errFiles[0];
if (file) {
file.upload = Upload.upload({
url: ''you-api-endpoint'',
data: {file: file}
});
//put promise and event watchers here if wanted
}
};
NODE código api
Todo el código a continuación se encuentra en un archivo de route
separado que se required
en mi archivo principal server.js.
require(''./app/app-routes.js'')(app, _);
var fs = require(''fs'');
var uuid = require(''uuid'');
var s3 = require(''s3fs''); // https://github.com/RiptideElements/s3fs
var s3Impl = new s3(''bucketname'', {
accessKeyId: ''<your access key id>'',
secretAccessKey: ''< your secret access key >''
});
var multiparty = require(''connect-multiparty'');
var multipartyMiddleware = multiparty();
module.exports = function(app, _) {
app.use(multipartyMiddleware);
app.post(''/your-api-endpoint'',function(req, res){
var file = req.files.file; // multiparty is what allows the file to to be accessed in the req
var stream = fs.createReadStream(file.path);
var extension = file.path.substring(file.path.lastIndexOf(''.''));
var destPath = ''/'' + req.user._id + ''/avatar/'' + uuid.v4() + extension;
var base = ''https://you-bucket-url'';
return s3Impl.writeFile(destPath, stream, {ContentType: file.type}).then(function(one){
fs.unlink(file.path);
res.send(base + destPath);
});
});
Todo lo que estaba tratando de hacer era cargar un avatar único para un usuario. ¡¡Espero que esto ayude!!