AngularJS: upload dei file in Node.js

AngularJS: upload dei file in Node.js

Esiste una procedura precisa per l'upload dei file con AngularJS e Node.js.

Installiamo multer per la negoziazione e gestione dei file in upload:


npm install multer

Quindi lo usiamo in questo modo:


var express = require('express');
var app  = express();
var multer  = require('multer');
var port = process.env.PORT || 8000;

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'uploads/'); // Le immagini verranno uploadate qui
  },
  filename: function (req, file, cb) {
    cb(null, file.originalname); // Vogliamo che l'immagine salvata mantenga il nome originale
  }
});

var upload = multer({ storage: storage });

// 'image' è il valore dell'attributo name dell'input

app.post('/api/upload', upload.single('image'), function(req,res, next) {
    var output = {};
    output.file = req.file;
    res.header('Content-Type', 'application/json');
    res.end(JSON.stringify(output));
});

app.listen(port);

In Angular creiamo un servizio che usi le API HTML5 per la gestione dei dati dei form. In pratica la variabile fd conterrà il nome del file e i contenuti dello stesso:


angular.module('MyApp').factory('FileUploader', ['$http', function ($http) {

    return {
        upload: function(file, url, callback) {
            var fd = new FormData();
            fd.append('image', file);
            $http.post(url, fd, {
                transformRequest: angular.identity,
                headers: {'Content-Type': undefined}
            }).then(function(response){
                callback(response);
            }, function(errorResponse){
	            // Gestione errore
            });    
        }
    };
}]);

A questo punto dobbiamo leggere il file scelto sull'input creando una direttiva personalizzata che acceda alle API HTML5 quando il valore dell'input cambia:


angular.module('MyApp').directive('fileModel', ['$parse', function ($parse) {
    return {
        restrict: 'A', // Come attributo
        link: function(scope, element, attrs) {
            var model = $parse(attrs.fileModel);
            var modelSetter = model.assign;
            
            element.bind('change', function(){ // Evento change sull'input file
                scope.$apply(function(){
                    modelSetter(scope, element[0].files[0]); // Usiamo le API HTML5 per ottenere il file selezionato
                });
            });
        }
    };
}]);

Il nostro form di upload mostrerà un messaggio quando l'upload è terminato. Notate come la nostra direttiva vengaa usata come attributo sull'input del file:


<div id="image-upload" ng-controller="UploadCtrl">
	<form id="upload" enctype="multipart/form-data" ng-submit="upload(image)">
		<p><input class="form-control" type="file" file-model="image" name="image" /></p>
		<p><input type="submit" class="btn btn-primary" value="Upload" /></p>
		<div ng-show="uploaded" class="bg-success">Uploaded {{uploadedImage}}</div>
	</form>
</div>

L'ultimo step è creare il controller associato:


angular.module('MyApp').controller('UploadCtrl', ['$scope', 'FileUploader', function($scope, FileUploader) {
	
	$scope.uploaded = false;
    $scope.uploadedImage = '';
    
    $scope.upload = function(image) {
        FileUploader.upload(image, '/api/upload', function(resp) {
            if(resp && resp.file) {
              $scope.uploadedImage = resp.file.originalname;
              $scope.uploaded = true;
            } else {
	         	// Gestione errore   
            }
        });    
    };
	
}]);

Torna su