web-dev-qa-db-fra.com

Envoyer FormData avec un autre champ dans Angular

J'ai un formulaire avec deux input text et un upload. Je dois l'envoyer au serveur mais j'ai un problème pour concaténer le fichier avec le texte. Le serveur attend cette réponse:

"title=first_input" "text=second_input" "file=my_file.pdf"

C'est le html:

<input type="text" ng-model="title">
<input type="text" ng-model="text">
<input type="file" file-model="myFile"/>
<button ng-click="send()">

C'est le Controller:

$scope.title = null;
$scope.text = null;

$scope.send = function(){
  var file = $scope.myFile;
  var uploadUrl = 'my_url';
  blockUI.start();
  Add.uploadFileToUrl(file, $scope.newPost.title, $scope.newPost.text, uploadUrl);
};

Ceci est le Directive fileModel:

  return {
restrict: 'A',
link: function(scope, element, attrs) {
  var model = $parse(attrs.fileModel);
  var modelSetter = model.assign;

  element.bind('change', function(){
    scope.$apply(function(){
      modelSetter(scope, element[0].files[0]);
    });
  });
}
};

Et voici le Service qui appelle le serveur:

  this.uploadFileToUrl = function(file, title, text, uploadUrl){
   var fd = new FormData();
   fd.append('file', file);
   var obj = {
     title: title,
     text: text,
     file: fd
   };
   var newObj = JSON.stringify(obj);

     $http.post(uploadUrl, newObj, {
       transformRequest: angular.identity,
       headers: {'Content-Type': 'multipart/form-data'}
     })
  .success(function(){
    blockUI.stop();
  })
  .error(function(error){
    toaster.pop('error', 'Errore', error);
  });
}

Si j'essaye d'envoyer, j'obtiens l'erreur 400 et la réponse est: Multipart form parse error - Invalid boundary in multipart: None. La charge utile de la demande est: {"title":"sadf","text":"sdfsadf","file":{}}

26
panagulis72

Ne sérialisez pas FormData avec POSTing sur le serveur. Faire ceci:

this.uploadFileToUrl = function(file, title, text, uploadUrl){
    var payload = new FormData();

    payload.append("title", title);
    payload.append('text', text);
    payload.append('file', file);

    return $http({
        url: uploadUrl,
        method: 'POST',
        data: payload,
        //assign content-type as undefined, the browser
        //will assign the correct boundary for us
        headers: { 'Content-Type': undefined},
        //prevents serializing payload.  don't do it.
        transformRequest: angular.identity
    });
}

puis utilisez-le:

MyService.uploadFileToUrl(file, title, text, uploadUrl).then(successCallback).catch(errorCallback);
60
Kyle

Voici la solution complète

code HTML,

créer les champs de texte et de téléchargement de fichier comme indiqué ci-dessous

    <div class="form-group">
        <div>
            <label for="usr">User Name:</label>
            <input type="text" id="usr" ng-model="model.username">
        </div>
        <div>
            <label for="pwd">Password:</label>
            <input type="password" id="pwd" ng-model="model.password">
        </div><hr>
        <div>
            <div class="col-lg-6">
                <input type="file" file-model="model.somefile"/>
            </div>


        </div>
        <div>
            <label for="dob">Dob:</label>
            <input type="date" id="dob" ng-model="model.dob">
        </div>
        <div>
            <label for="email">Email:</label>
            <input type="email"id="email" ng-model="model.email">
        </div>


        <button type="submit" ng-click="saveData(model)" >Submit</button>

code de directive

créer une directive filemodel pour analyser le fichier

.directive('fileModel', ['$parse', function ($parse) {
return {
    restrict: 'A',
    link: function(scope, element, attrs) {
        var model = $parse(attrs.fileModel);
        var modelSetter = model.assign;

        element.bind('change', function(){
            scope.$apply(function(){
                modelSetter(scope, element[0].files[0]);
            });
        });
    }
};}]);

Code de service

ajoutez le fichier et les champs pour former les données et faites $ http.post comme indiqué ci-dessous, n'oubliez pas de garder 'Content-Type': undefined

 .service('fileUploadService', ['$http', function ($http) {
    this.uploadFileToUrl = function(file, username, password, dob, email, uploadUrl){
        var myFormData = new FormData();

        myFormData.append('file', file);
        myFormData.append('username', username);
        myFormData.append('password', password);
        myFormData.append('dob', dob);
        myFormData.append('email', email);


        $http.post(uploadUrl, myFormData, {
            transformRequest: angular.identity,
            headers: {'Content-Type': undefined}
        })
            .success(function(){

            })
            .error(function(){
            });
    }
}]);

Dans le contrôleur

Maintenant, dans le contrôleur, appelez le service en envoyant les données requises à ajouter dans les paramètres,

$scope.saveData  = function(model){
    var file = model.myFile;
    var uploadUrl = "/api/createUsers";
    fileUpload.uploadFileToUrl(file, model.username, model.password, model.dob, model.email, uploadUrl);
};
6
JpG

Vous envoyez des données au format JSON à un serveur qui n'attend pas ce format. Vous avez déjà fourni le format requis par le serveur. Vous devrez donc le formater vous-même, ce qui est assez simple.

var data = '"title='+title+'" "text='+text+'" "file='+file+'"';
$http.post(uploadUrl, data)
3
Dr. Cool

En utilisant $resource dans AngularJS vous pouvez faire:

task.service.js

$ngTask.factory("$taskService", [
    "$resource",
    function ($resource) {
        var taskModelUrl = 'api/task/';
        return {
            rest: {
                taskUpload: $resource(taskModelUrl, {
                    id: '@id'
                }, {
                    save: {
                        method: "POST",
                        isArray: false,
                        headers: {"Content-Type": undefined},
                        transformRequest: angular.identity
                    }
                })
            }
        };
    }
]);

Et ensuite, utilisez-le dans un module:

task.module.js

$ngModelTask.controller("taskController", [
    "$scope",
    "$taskService",
    function (
        $scope,
        $taskService,
    ) {
    $scope.saveTask = function (name, file) {
        var newTask,
            payload = new FormData();
        payload.append("name", name);
        payload.append("file", file);
        newTask = $taskService.rest.taskUpload.save(payload);
        // check if exists
    }
}
1
regiea

Cela ne marchera jamais, vous ne pouvez pas stringifier votre objet FormData.

Vous devriez faire ceci:

this.uploadFileToUrl = function(file, title, text, uploadUrl){
   var fd = new FormData();
   fd.append('title', title);
   fd.append('text', text);
   fd.append('file', file);

     $http.post(uploadUrl, obj, {
       transformRequest: angular.identity,
       headers: {'Content-Type': undefined}
     })
  .success(function(){
    blockUI.stop();
  })
  .error(function(error){
    toaster.pop('error', 'Errore', error);
  });
}
1
scyrizales