touched form javascript angularjs

javascript - touched - Angularjs $ http post archivo y datos de formulario



ng-form angularjs (8)

Aquí está mi solución:

// Controller $scope.uploadImg = function( files ) { $scope.data.avatar = files[0]; } $scope.update = function() { var formData = new FormData(); formData.append(''desc'', data.desc); formData.append(''avatar'', data.avatar); SomeService.upload( formData ); } // Service upload: function( formData ) { var deferred = $q.defer(); var url = "/upload" ; var request = { "url": url, "method": "POST", "data": formData, "headers": { ''Content-Type'' : undefined // important } }; console.log(request); $http(request).success(function(data){ deferred.resolve(data); }).error(function(error){ deferred.reject(error); }); return deferred.promise; } // backend use express and multer // a part of the code var multer = require(''multer''); var storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, ''../public/img'') }, filename: function (req, file, cb) { cb(null, file.fieldname + ''-'' + Date.now() + ''.jpg''); } }) var upload = multer({ storage: storage }) app.post(''/upload'', upload.single(''avatar''), function(req, res, next) { // do something console.log(req.body); res.send(req.body); });

<div> <input type="file" accept="image/*" onchange="angular.element( this ).scope().uploadImg( this.files )"> <textarea ng-model="data.desc" /> <button type="button" ng-click="update()">Update</button> </div>

Tengo la siguiente solicitud en python

import requests, json, io cookie = {} payload = {"Name":"abc"} url = "/test" file = "out/test.json" fi = {''file'': (''file'', open(file) )} r = requests.post("http://192.168.1.1:8080" + url, data=payload, files=fi, cookies=cookie) print(r.text)

que envían un archivo y campos de formulario al backend. ¿Cómo puedo hacer lo mismo (enviar campos de formulario + archivo) con Angular $ http? Actualmente, me gusta esto, pero no estoy seguro de cómo enviar el archivo también.

var payload = {"Name":"abc"}; $http.post(''/test'', payload) .success(function (res) { //success });


En mi solución, tengo

$scope.uploadVideo = function(){ var uploadUrl = "/api/uploadEvent"; //obj with data, that can be one input or form file = $scope.video; var fd = new FormData(); //check file form on being for (var obj in file) { if (file[obj] || file[obj] == 0) { fd.append(obj, file[obj]); } } //open XHR request var xhr = new XMLHttpRequest(); // $apply to rendering progress bar for any chunking update xhr.upload.onprogress = function(event) { $scope.uploadStatus = { loaded: event.loaded, total: event.total }; $scope.$apply(); }; xhr.onload = xhr.onerror = function(e) { if (this.status == 200 || this.status == 201) { //sucess $scope.uploadStatus = { loaded: 0, total: 0 }; //this is for my solution $scope.video = {}; $scope.vm.model.push(JSON.parse(e.currentTarget.response)); $scope.$apply(); } else { //on else status } }; xhr.open("POST", uploadUrl, true); //token for upload, thit for my solution xhr.setRequestHeader("Authorization", "JWT " + window.localStorage.token); //send xhr.send(fd); };

}



No pude conseguir que la respuesta de Pavel funcionara como cuando publicaba en una aplicación Web.Api.

El problema parece ser con la eliminación de los encabezados.

headersGetter(); delete headers[''Content-Type''];

Con el fin de garantizar que los navegadores tuvieran permitido el valor predeterminado del Tipo de contenido junto con el parámetro de límite, necesitaba establecer el Tipo de contenido como no definido. Usando el ejemplo de Pavel, el límite nunca se estableció, lo que resultó en una excepción de 400 HTTP.

La clave fue eliminar el código que elimina los encabezados que se muestran arriba y establecer el tipo de contenido de los encabezados en nulo manualmente. Permitiendo así que el navegador establezca las propiedades.

headers: {''Content-Type'': undefined}

Aquí hay un ejemplo completo.

$scope.Submit = form => { $http({ method: ''POST'', url: ''api/FileTest'', headers: {''Content-Type'': undefined}, data: { FullName: $scope.FullName, Email: $scope.Email, File1: $scope.file }, transformRequest: function (data, headersGetter) { var formData = new FormData(); angular.forEach(data, function (value, key) { formData.append(key, value); }); return formData; } }) .success(function (data) { }) .error(function (data, status) { }); return false; }


Por favor, eche un vistazo a mi implementación. Puedes envolver la siguiente función en un servicio:

function(file, url) { var fd = new FormData(); fd.append(''file'', file); return $http.post(url, fd, { transformRequest: angular.identity, headers: { ''Content-Type'': undefined } }); }

Tenga en cuenta que file argumento del file es un Blob . Si tiene la versión base64 de un archivo, se puede cambiar fácilmente a Blob así:

fetch(base64).then(function(response) { return response.blob(); }).then(console.info).catch(console.error);


Recientemente escribí una directiva que soporta cargas de archivos múltiples nativas. La solución que he creado se basa en un servicio para llenar el vacío que ha identificado con el servicio $ http. También he incluido una directiva, que proporciona una API fácil de usar para el módulo angular para publicar los archivos y los datos.

Ejemplo de uso:

<lvl-file-upload auto-upload=''false'' choose-file-button-text=''Choose files'' upload-file-button-text=''Upload files'' upload-url=''http://localhost:3000/files'' max-files=''10'' max-file-size-mb=''5'' get-additional-data=''getData(files)'' on-done=''done(files, data)'' on-progress=''progress(percentDone)'' on-error=''error(files, type, msg)''/>

Puede encontrar el código en github y la documentación en mi blog

Depende de usted procesar los archivos en su marco web, pero la solución que he creado proporciona la interfaz angular para llevar los datos a su servidor. El código angular que necesitas escribir es responder a los eventos de carga.

angular .module(''app'', [''lvl.directives.fileupload'']) .controller(''ctl'', [''$scope'', function($scope) { $scope.done = function(files,data} { /*do something when the upload completes*/ }; $scope.progress = function(percentDone) { /*do something when progress is reported*/ }; $scope.error = function(file, type, msg) { /*do something if an error occurs*/ }; $scope.getAdditionalData = function() { /* return additional data to be posted to the server*/ }; });


También puedes subir usando HTML5. Puedes usar este cargador AJAX .

El código JS es básicamente:

$scope.doPhotoUpload = function () { // .. var myUploader = new uploader(document.getElementById(''file_upload_element_id''), options); myUploader.send(); // .. }

Que lee desde un elemento de entrada HTML

<input id="file_upload_element_id" type="file" onchange="angular.element(this).scope().doPhotoUpload()">


Tuve un problema similar cuando tuve que cargar un archivo y enviar información de token de usuario al mismo tiempo. transformRequest junto con FormData ayudó a:

$http({ method: ''POST'', url: ''/upload-file'', headers: { ''Content-Type'': ''multipart/form-data'' }, data: { email: Utils.getUserInfo().email, token: Utils.getUserInfo().token, upload: $scope.file }, transformRequest: function (data, headersGetter) { var formData = new FormData(); angular.forEach(data, function (value, key) { formData.append(key, value); }); var headers = headersGetter(); delete headers[''Content-Type'']; return formData; } }) .success(function (data) { }) .error(function (data, status) { });

Para obtener el archivo $scope.file usé una directiva personalizada:

app.directive(''file'', function () { return { scope: { file: ''='' }, link: function (scope, el, attrs) { el.bind(''change'', function (event) { var file = event.target.files[0]; scope.file = file ? file : undefined; scope.$apply(); }); } }; });

Html:

<input type="file" file="file" required />