AngularJS: как реализовать простую загрузку файла с помощью многострочной формы?

Я хочу сделать простой многостраничный пост из AngularJS на сервер node.js, форма должна содержать объект JSON в одной части и изображение в другой части, (В настоящее время я отправляю только объект JSON с $resource)

Я решил, что должен начать с input type="file", но потом выяснил, что AngularJS не может привязываться к этому.

все примеры, которые я могу найти, предназначены для размывания плагинов jQuery для перетаскивания. Мне нужна простая загрузка одного файла.

Я новичок в AngularJS и не чувствую себя комфортно с написанием своих собственных директив.

Ответ 1

Реальное рабочее решение без каких-либо других зависимостей, чем angularjs (проверено с v.1.0.6)

HTML

<input type="file" name="file" onchange="angular.element(this).scope().uploadFile(this.files)"/>

Angularjs (1.0.6) не поддерживает ng-модель в тегах "входного файла", поэтому вам нужно сделать это с помощью "нативного" способа, который передает все (в конечном итоге) выбранные файлы от пользователя.

контроллер

$scope.uploadFile = function(files) {
    var fd = new FormData();
    //Take the first selected file
    fd.append("file", files[0]);

    $http.post(uploadUrl, fd, {
        withCredentials: true,
        headers: {'Content-Type': undefined },
        transformRequest: angular.identity
    }).success( ...all right!... ).error( ..damn!... );

};

Прохладная часть - это тип контента undefined и идентификатор transformRequest: angular., которые дают при $http возможность выбора правильного "типа контента" и управления границей, необходимой при обработке многостраничных данных.

Ответ 2

Вы можете использовать простую/легкую ng-file-upload. Он поддерживает drag & drop, ход файла и загрузку файлов для браузеров, не поддерживающих HTML5, с помощью прошивки FileAPI flash

<div ng-controller="MyCtrl">
  <input type="file" ngf-select="onFileSelect($files)" multiple>
</div>

JS:

//inject angular file upload directive.
angular.module('myApp', ['ngFileUpload']);

var MyCtrl = [ '$scope', 'Upload', function($scope, Upload) {
  $scope.onFileSelect = function($files) {
  Upload.upload({
    url: 'my/upload/url',
    file: $files,            
  }).progress(function(e) {
  }).then(function(data, status, headers, config) {
    // file is uploaded successfully
    console.log(data);
  }); 

}];

Ответ 3

У меня была эта проблема. Таким образом, существует несколько подходов. Во-первых, новые браузеры поддерживают

var formData = new FormData();

Следуйте этой ссылке в блоге с информацией о, как поддержка ограничена современными браузерами, но в остальном она полностью решает эту проблему.

В противном случае вы можете отправить форму в iframe с использованием целевого атрибута. Когда вы публикуете форму, обязательно установите цель в iframe с свойством отображения, равным none. Цель - имя iframe. (Только чтобы вы знали.)

Я надеюсь, что это поможет

Ответ 4

Я знаю, что это поздняя запись, но я создал простую директиву загрузки. Которые вы можете получить в кратчайшие сроки!

<input type="file" multiple ng-simple-upload web-api-url="/api/post" callback-fn="myCallback" />

ng-simple-upload подробнее о Github с примером, использующим веб-API.

Ответ 5

Вы можете загрузить через $resource, назначив данные атрибуту params ресурса actions следующим образом:

$scope.uploadFile = function(files) {
    var fdata = new FormData();
    fdata.append("file", files[0]);

    $resource('api/post/:id', { id: "@id" }, {
        postWithFile: {
            method: "POST",
            params: fdata,
            transformRequest: angular.identity,
            headers: { 'Content-Type': undefined }
        }
    }).postWithFile(fdata).$promise.then(function(response){
         //successful 
    },function(error){
        //error
    });
};

Ответ 6

Эффективно отправлять файл напрямую.

base64 encoding Content-Type: multipart/form-data добавляет дополнительные 33% накладных расходов. Если сервер поддерживает его, более эффективно отправлять файлы напрямую:

$scope.upload = function(url, file) {
    var config = { headers: { 'Content-Type': undefined },
                   transformResponse: angular.identity
                 };
    return $http.post(url, file, config);
};

При отправке POST с File object важно установить 'Content-Type': undefined. метод отправки XHR затем обнаружит File object и автоматически установите тип содержимого.

Чтобы отправить несколько файлов, см. Выполнение нескольких $http.post запросов непосредственно из списка файлов


Я решил, что должен начать с input type="file", но потом выяснил, что AngularJS не может привязываться к этому.

Элемент <input type=file> по умолчанию не работает с директивой ng-model. Для этого требуется настраиваемая директива:

Рабочая демонстрация директивы "файлы-ввод", которая работает с ng-model 1

angular.module("app",[]);

angular.module("app").directive("filesInput", function() {
  return {
    require: "ngModel",
    link: function postLink(scope,elem,attrs,ngModel) {
      elem.on("change", function(e) {
        var files = elem[0].files;
        ngModel.$setViewValue(files);
      })
    }
  }
});
<script src="//unpkg.com/angular/angular.js"></script>
  <body ng-app="app">
    <h1>AngularJS Input `type=file` Demo</h1>
    
    <input type="file" files-input ng-model="fileArray" multiple>
    
    <h2>Files</h2>
    <div ng-repeat="file in fileArray">
      {{file.name}}
    </div>
  </body>

Ответ 7

Я просто написал простую директиву (из уже существующей) для простого загрузчика в AngularJs.

(Точный плагин для загрузчика jQuery https://github.com/blueimp/jQuery-File-Upload)

Простой загрузчик с использованием AngularJs (с реализацией CORS)

(Хотя серверная сторона для PHP, вы можете просто изменить ее и node)