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);
};
}
Hay otras soluciones que puede consultar en http://ngmodules.org/modules/ngUpload como se explica aquí . Integración del cargador de archivos para angularjs
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 />