Carga de archivos usando AngularJS

Aquí está mi formulario HTML:

Quiero subir una imagen de la máquina local y quiero leer el contenido del archivo cargado. Todo esto quiero hacer usando AngularJS.

Cuando bash imprimir el valor de $scope.file , aparece como indefinido.

Algunas de las respuestas aquí proponen usar FormData() , pero desafortunadamente ese es un objeto de navegador no disponible en Internet Explorer 9 y abajo. Si necesita admitir navegadores más antiguos, necesitará una estrategia de respaldo, como usar o Flash.

Ya hay muchos módulos Angular.js para realizar la carga de archivos. Estos dos tienen soporte explícito para navegadores antiguos:

Y algunas otras opciones:

Uno de ellos debe ajustarse a su proyecto, o puede darle una idea de cómo codificarlo usted mismo.

Lo más fácil es usar la API HTML5, concretamente FileReader

HTML es bastante sencillo:

   

En tu controlador, define el método ‘agregar’:

 $scope.add = function() { var f = document.getElementById('file').files[0], r = new FileReader(); r.onloadend = function(e) { var data = e.target.result; //send your binary data via $http or $resource or do anything else with it } r.readAsBinaryString(f); } 

Compatibilidad del navegador

Navegadores de escritorio

Firefox (Gecko) 3.6 (1.9.2), Chrome 7, Internet Explorer * 10, Opera * 12.02, Safari 6.0.2

Navegadores móviles

Firefox (Gecko) 32, Chrome 3, Internet Explorer * 10, Opera * 11.5, Safari 6.1

Nota: el método readAsBinaryString () está en desuso y debe usarse readAsArrayBuffer () en su lugar.

Esta es la forma de 2015, sin bibliotecas de terceros. Funciona en todos los navegadores más recientes.

  app.directive('myDirective', function (httpPostFactory) { return { restrict: 'A', scope: true, link: function (scope, element, attr) { element.bind('change', function () { var formData = new FormData(); formData.append('file', element[0].files[0]); httpPostFactory('upload_image.php', formData, function (callback) { // recieve image name to use in a ng-src console.log(callback); }); }); } }; }); app.factory('httpPostFactory', function ($http) { return function (file, data, callback) { $http({ url: file, method: "POST", data: data, headers: {'Content-Type': undefined} }).success(function (response) { callback(response); }); }; }); 

HTML:

  

PHP:

 if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) { // uploads image in the folder images $temp = explode(".", $_FILES["file"]["name"]); $newfilename = substr(md5(time()), 0, 10) . '.' . end($temp); move_uploaded_file($_FILES['file']['tmp_name'], 'images/' . $newfilename); // give callback to your angular code with the image src name echo json_encode($newfilename); } 

js fiddle (solo front-end) https://jsfiddle.net/vince123/8d18tsey/31/

A continuación se muestra un ejemplo de carga de archivos:

http://jsfiddle.net/vishalvasani/4hqVu/

En esta función llamada

 setFiles 

Desde View, que actualizará la matriz de archivos en el controlador

o

Puede verificar la carga de archivos jQuery usando AngularJS

http://blueimp.github.io/jQuery-File-Upload/angularjs.html

Puede lograr una buena carga de archivo y carpeta usando flow.js.

https://github.com/flowjs/ng-flow

Mira una demostración aquí

http://flowjs.github.io/ng-flow/

No es compatible con IE7, IE8, IE9, por lo que eventualmente tendrá que usar una capa de compatibilidad

https://github.com/flowjs/fusty-flow.js

Probé todas las alternativas que da @Anoyz (Respuesta correcta) … y la mejor solución es https://github.com/danialfarid/angular-file-upload

Algunas caracteristicas:

  • Progreso
  • Multifiles
  • Campos
  • Navegadores antiguos (IE8-9)

Funciona bien para mí. Solo debes prestar atención a las instrucciones.

En el lado del servidor, uso el middleware NodeJs, Express 4 y Multer para gestionar solicitudes de varias partes.

HTML

    
  • {{file.name}}
  • Guiones

        

    Use el evento onchange para pasar el elemento del archivo de entrada a su función.

    Por lo tanto, cuando un usuario selecciona un archivo, tiene una referencia sin que el usuario tenga que hacer clic en el botón “Agregar” o “Subir”.

     $scope.fileSelected = function (element) { var myFileSelected = element.files[0]; }; 

    Fácil con una directiva

    Html:

      

    JS:

     app.directive('fileUpload', function () { return { scope: true, //create a new scope link: function (scope, el, attrs) { el.bind('change', function (event) { var files = event.target.files; //iterate files since 'multiple' may be specified on the element for (var i = 0;i 

    En la directiva, nos aseguramos de que se cree un nuevo ámbito y luego escuchamos los cambios realizados en el elemento de entrada del archivo. Cuando se detectan cambios, se emite un evento a todos los ámbitos ancestrales (hacia arriba) con el objeto de archivo como parámetro.

    En tu controlador:

     $scope.files = []; //listen for the file selected event $scope.$on("fileSelected", function (event, args) { $scope.$apply(function () { //add the file object to the scope's files collection $scope.files.push(args.file); }); }); 

    Luego, en tu llamada ajax:

     data: { model: $scope.model, files: $scope.files } 

    http://shazwazza.com/post/uploading-files-and-json-data-in-the-same-request-with-angular-js/

    Creo que esta es la carga angular del archivo:

    ng-file-upload

    Ligera directiva Angular JS para cargar archivos.

    Aquí está la página DEMO. Características

    • Admite el progreso de la carga, cancela / aborta la carga mientras está en progreso, arrastra y suelta archivos (html5), arrastra y suelta el directorio (webkit), CORS, PUT (html5) / métodos POST, validación del tipo y tamaño del archivo, muestra una vista previa de las imágenes seleccionadas / audio / videos.
    • Carga de archivos del navegador cruzado y FileReader (HTML5 y no HTML5) con Flash polyfill FileAPI. Permite la validación / modificación del lado del cliente antes de cargar el archivo
    • Carga directa a servicios de db CouchDB, imgur, etc … con el tipo de contenido de archivo que utiliza Upload.http (). Esto habilita el evento de progreso para solicitudes angulares POST / PUT HTTP.
    • Seperate shim file, los archivos FileAPI se cargan a pedido para códigos que no sean HTML5, lo que significa que no hay carga / código adicional si solo necesitas soporte HTML5.
    • Ligero usando $ http regular para cargar (con shim para navegadores no HTML5) para que todas las características angulares $ http estén disponibles

    https://github.com/danialfarid/ng-file-upload

    Su archivo y datos JSON se cargan al mismo tiempo.

     // FIRST SOLUTION var _post = function (file, jsonData) { $http({ url: your url, method: "POST", headers: { 'Content-Type': undefined }, transformRequest: function (data) { var formData = new FormData(); formData.append("model", angular.toJson(data.model)); formData.append("file", data.files); return formData; }, data: { model: jsonData, files: file } }).then(function (response) { ; }); } // END OF FIRST SOLUTION // SECOND SOLUTION // İf you can add plural file and İf above code give an error. // You can try following code var _post = function (file, jsonData) { $http({ url: your url, method: "POST", headers: { 'Content-Type': undefined }, transformRequest: function (data) { var formData = new FormData(); formData.append("model", angular.toJson(data.model)); for (var i = 0; i < data.files.length; i++) { // add each file to // the form data and iteratively name them formData.append("file" + i, data.files[i]); } return formData; }, data: { model: jsonData, files: file } }).then(function (response) { ; }); } // END OF SECOND SOLUTION 

    El elemento no funciona de forma predeterminada con la directiva ng-model . Necesita una directiva personalizada :

    Demo de trabajo de return-files Directiva que funciona con ng-model 1

     angular.module("app",[]); angular.module("app").directive("returnFiles", function() { return { require: "ngModel", link: function postLink(scope,elem,attrs,ngModel) { elem.on("change", function(e) { var files = elem[0].files; ngModel.$setViewValue(files); }) } } }); 
       

    AngularJS Input `type=file` Demo

    Files

    {{file.name}}

    Puede usar un objeto FormData que es seguro y rápido:

     // Store the file object when input field is changed $scope.contentChanged = function(event){ if (!event.files.length) return null; $scope.content = new FormData(); $scope.content.append('fileUpload', event.files[0]); $scope.$apply(); } // Upload the file over HTTP $scope.upload = function(){ $http({ method: 'POST', url: '/remote/url', headers: {'Content-Type': undefined }, data: $scope.content, }).success(function(response) { // Uploading complete console.log('Request finished', response); }); } 

    http://jsfiddle.net/vishalvasani/4hqVu/ funciona bien en Chrome e IE (si actualiza CSS un poco en background-image). Esto se usa para actualizar la barra de progreso:

      scope.progress = Math.round(evt.loaded * 100 / evt.total) 

    pero en Firefox, los datos [porcentuales] de angular no se actualizan correctamente en DOM, aunque los archivos se cargan con éxito.

    Puede considerar IaaS para la carga de archivos, como Uploadcare . Hay un paquete angular para él: https://github.com/uploadcare/angular-uploadcare

    Técnicamente se implementa como una directiva, proporcionando diferentes opciones para cargar y manipulaciones para las imágenes cargadas dentro del widget:

      

    Más opciones de configuración para jugar: https://uploadcare.com/widget/configure/

    Sé que esta es una entrada tardía, pero he creado una directiva de carga simple. ¡Con lo cual puedes trabajar de inmediato!

      

    ng-simple-carga más en Github con un ejemplo utilizando la API web.

    Esto debería ser una actualización / comentario a la respuesta de @jquery-guru, pero como no tengo suficientes representantes irá aquí. Soluciona los errores que ahora genera el código.

    https://jsfiddle.net/vzhrqotw/

    El cambio es básicamente:

     FileUploadCtrl.$inject = ['$scope'] function FileUploadCtrl(scope) { 

    A:

     app.controller('FileUploadCtrl', function($scope) { 

    Siéntase libre de moverse a un lugar más apropiado si lo desea.

    He leído todo el hilo y la solución de API HTML5 se veía mejor. Pero cambia mis archivos binarios, corrompiéndolos de una manera que no he investigado. La solución que funcionó perfectamente para mí fue:

    HTML:

       

    JS:

     msds_update = function() { var f = document.getElementById('msds').files[0], r = new FileReader(); r.onloadend = function(e) { var data = e.target.result; console.log(data); var fd = new FormData(); fd.append('file', data); fd.append('file_name', f.name); $http.post('server_handler.php', fd, { transformRequest: angular.identity, headers: {'Content-Type': undefined} }) .success(function(){ console.log('success'); }) .error(function(){ console.log('error'); }); }; r.readAsDataURL(f); } 

    Lado del servidor (PHP):

     $file_content = $_POST['file']; $file_content = substr($file_content, strlen('data:text/plain;base64,')); $file_content = base64_decode($file_content); 
     

    En el controlador angularJS

     $scope.submit_import_csv = function(){ var formData = new FormData(document.getElementById("csv_file_form")); console.log(formData); $.ajax({ url: "import", type: 'POST', data: formData, mimeType:"multipart/form-data", contentType: false, cache: false, processData:false, success: function(result, textStatus, jqXHR) { console.log(result); } }); return false; } 

    Puedo subir archivos usando AngularJS usando el siguiente código:

    El file para el argumento que se debe pasar para la función ngUploadFileUpload es $scope.file según su pregunta.

    El punto clave aquí es usar transformRequest: [] . Esto evitará $ http con problemas con el contenido del archivo.

      function getFileBuffer(file) { var deferred = new $q.defer(); var reader = new FileReader(); reader.onloadend = function (e) { deferred.resolve(e.target.result); } reader.onerror = function (e) { deferred.reject(e.target.error); } reader.readAsArrayBuffer(file); return deferred.promise; } function ngUploadFileUpload(endPointUrl, file) { var deferred = new $q.defer(); getFileBuffer(file).then(function (arrayBuffer) { $http({ method: 'POST', url: endPointUrl, headers: { "accept": "application/json;odata=verbose", 'X-RequestDigest': spContext.securityValidation, "content-length": arrayBuffer.byteLength }, data: arrayBuffer, transformRequest: [] }).then(function (data) { deferred.resolve(data); }, function (error) { deferred.reject(error); console.error("Error", error) }); }, function (error) { console.error("Error", error) }); return deferred.promise; } 

    La respuesta arriba aceptada no es compatible con el navegador. Si alguien tiene problemas de compatibilidad prueba esto.

    Violín

    Ver código

      

    {{data}}

    Código de controlador

     var myApp = angular.module('myApp',[]); function MyCtrl($scope) { $scope.data = 'none'; $scope.add = function(){ var f = document.getElementById('file').files[0], r = new FileReader(); r.onloadend = function(e){ var binary = ""; var bytes = new Uint8Array(e.target.result); var length = bytes.byteLength; for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); } $scope.data = (binary).toString(); alert($scope.data); } r.readAsArrayBuffer(f); } } 

    HTML

      

    agrega el método ‘profileimage ()’ a tu controlador

      $scope.profileimage = function(selectimage) { console.log(selectimage.files[0]); var selectfile=selectimage.files[0]; r = new FileReader(); r.onloadend = function (e) { debugger; var data = e.target.result; } r.readAsBinaryString(selectfile); } 

    en palabras simples

    en HTML: agregue solo el código siguiente

      

    en el controlador : se llama a esta función cuando hace clic en “cargar archivo de botón” . cargará el archivo. puedes consolarlo

     $scope.uploadedFile = function(element) { $scope.$apply(function($scope) { $scope.files = element.files; }); } 

    agregue más en los controladores : debajo del código agregue a la función. Se llama a esta función cuando haces clic en el botón que se usa para presionar la API (POST)” . enviará el archivo (que se cargó) y los datos del formulario al back-end.

     var url = httpURL + "/reporttojson" var files=$scope.files; for ( var i = 0; i < files.length; i++) { var fd = new FormData(); angular.forEach(files,function(file){ fd.append('file',file); }); var data ={ msg : message, sub : sub, sendMail: sendMail, selectUsersAcknowledge:false }; fd.append("data", JSON.stringify(data)); $http.post(url, fd, { withCredentials : false, headers : { 'Content-Type' : undefined }, transformRequest : angular.identity }).success(function(data) { toastr.success("Notification sent successfully","",{timeOut: 2000}); $scope.removereport() $timeout(function() { location.reload(); }, 1000); }).error(function(data) { toastr.success("Error in Sending Notification","",{timeOut: 2000}); $scope.removereport() }); } 

    en este caso ... agregué el código siguiente como datos de formulario

     var data ={ msg : message, sub : sub, sendMail: sendMail, selectUsersAcknowledge:false }; 

    Hemos usado HTML, CSS y AngularJS. El siguiente ejemplo muestra cómo cargar el archivo usando AngularJS.

          

    Ejemplo de trabajo usando una directiva simple ( ng-file-model ):

     .directive("ngFileModel", [function () { return { $scope: { ngFileModel: "=" }, link: function ($scope:any, element, attributes) { element.bind("change", function (changeEvent:any) { var reader = new FileReader(); reader.onload = function (loadEvent) { $scope.$apply(function () { $scope.ngFileModel = { lastModified: changeEvent.target.files[0].lastModified, lastModifiedDate: changeEvent.target.files[0].lastModifiedDate, name: changeEvent.target.files[0].name, size: changeEvent.target.files[0].size, type: changeEvent.target.files[0].type, data: changeEvent.target.files[0] }; }); } reader.readAsDataURL(changeEvent.target.files[0]); }); } } }]) 

    y use FormData para cargar archivos en su función.

     var formData = new FormData(); formData.append("document", $scope.ngFileModel.data) formData.append("user_id", $scope.userId) 

    todos los créditos van por https://github.com/mistralworks/ng-file-model

    Me he enfrentado a un pequeño probelma que puedes consultar aquí: https://github.com/mistralworks/ng-file-model/issues/7

    Finalmente, aquí hay un repository bifurcado: https://github.com/okasha93/ng-file-model/blob/patch-1/ng-file-model.js

    El código ayudará a insertar el archivo

      

    Select Picture

    insert.js

     var app = angular.module('myApp',[]); app.service('uploadFile', ['$http','$window', function ($http,$window) { this.uploadFiletoServer = function(file,uploadUrl){ var fd = new FormData(); fd.append('file', file); $http.post(uploadUrl, fd, { transformRequest: angular.identity, headers: {'Content-Type': undefined} }) .success(function(data){ alert("insert successfull"); $window.location.href = ' ';//your window location }) .error(function(){ alert("Error"); }); } }]); app.controller('insert_Ctrl', ['$scope', 'uploadFile', function($scope, uploadFile){ $scope.uploadFile = function() { $scope.myFile = $scope.files[0]; var file = $scope.myFile; var url = "save_data.php"; uploadFile.uploadFiletoServer(file,url); }; $scope.uploadedFile = function(element) { var reader = new FileReader(); reader.onload = function(event) { $scope.$apply(function($scope) { $scope.files = element.files; $scope.src = event.target.result }); } reader.readAsDataURL(element.files[0]); } }]); 

    save_data.php

      

    esto funciona

    file.html

          

    controller.js

      var app = angular.module('app', []); app.service('fileUpload', ['$http', function ($http) { this.uploadFileToUrl = function(file, uploadUrl){ var fd = new FormData(); fd.append('file', file); $http.post(uploadUrl, fd, { transformRequest: angular.identity, headers: {'Content-Type': undefined} }).success(function(res){ console.log(res); }).error(function(error){ console.log(error); }); } }]); app.controller('fileCtrl', ['$scope', 'fileUpload', function($scope, fileUpload){ $scope.uploadFile = function(){ var file = $scope.myFile; console.log('file is ' ); console.dir(file); var uploadUrl = "/fileUpload.php"; // upload url stands for api endpoint to handle upload to directory fileUpload.uploadFileToUrl(file, uploadUrl); }; }]);  

    fileupload.php

       

    SUBIR ARCHIVOS

      $scope.uploadResume = function () { var f = document.getElementById('resume').files[0]; $scope.selectedResumeName = f.name; $scope.selectedResumeType = f.type; r = new FileReader(); r.onloadend = function (e) { $scope.data = e.target.result; } r.readAsDataURL(f); }; 

    DESCARGAR ARCHIVOS:

       download resume var app = angular.module("myApp", []); app.config(['$compileProvider', function ($compileProvider) { $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|local|data|chrome-extension):/); $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|local|data|chrome-extension):/); }]); 
     app.directive('ngUpload', function () { return { restrict: 'A', link: function (scope, element, attrs) { var options = {}; options.enableControls = attrs['uploadOptionsEnableControls']; // get scope function to execute on successful form upload if (attrs['ngUpload']) { element.attr("target", "upload_iframe"); element.attr("method", "post"); // Append a timestamp field to the url to prevent browser caching results element.attr("action", element.attr("action") + "?_t=" + new Date().getTime()); element.attr("enctype", "multipart/form-data"); element.attr("encoding", "multipart/form-data"); // Retrieve the callback function var fn = attrs['ngUpload'].split('(')[0]; var callbackFn = scope.$eval(fn); if (callbackFn == null || callbackFn == undefined || !angular.isFunction(callbackFn)) { var message = "The expression on the ngUpload directive does not point to a valid function."; // console.error(message); throw message + "\n"; } // Helper function to create new i frame for each form submission var addNewDisposableIframe = function (submitControl) { // create a new iframe var iframe = $(""); // attach function to load event of the iframe iframe.bind('load', function () { // get content - requires jQuery var content = iframe.contents().find('body').text(); // execute the upload response function in the active scope scope.$apply(function () { callbackFn(content, content !== "" /* upload completed */); }); // remove iframe if (content != "") // Fixes a bug in Google Chrome that dispose the iframe before content is ready. setTimeout(function () { iframe.remove(); }, 250); submitControl.attr('disabled', null); submitControl.attr('title', 'Click to start upload.'); }); // add the new iframe to application element.parent().append(iframe); }; // 1) get the upload submit control(s) on the form (submitters must be decorated with the 'ng-upload-submit' class) // 2) attach a handler to the controls' click event $('.upload-submit', element).click( function () { addNewDisposableIframe($(this) /* pass the submit control */); scope.$apply(function () { callbackFn("Please wait...", false /* upload not completed */); }); var enabled = true; if (options.enableControls === null || options.enableControls === undefined || options.enableControls.length >= 0) { // disable the submit control on click $(this).attr('disabled', 'disabled'); enabled = false; } $(this).attr('title', (enabled ? '[ENABLED]: ' : '[DISABLED]: ') + 'Uploading, please wait...'); // submit the form $(element).submit(); } ).attr('title', 'Click to start upload.'); } else alert("No callback function found on the ngUpload directive."); } }; }); 
    @RequestMapping(value = "/uploadHelpFile", method = RequestMethod.POST) public @ResponseBody String uploadHelpFile(@RequestParam(value = "file") CommonsMultipartFile[] file,@RequestParam(value = "fileName") String fileName,@RequestParam(value = "helpFileType") String helpFileType,@RequestParam(value = "helpFileName") String helpFileName) { }