web-dev-qa-db-ja.com

AngularJS:マルチパートフォームで簡単なファイルアップロードを実装する方法

AngularJSからnode.jsサーバーへの単純なマルチパートフォームの投稿を行いたいのですが、フォームには一方の部分にJSONオブジェクト、もう一方の部分に画像を含める必要があります(現在、$ resourceのJSONオブジェクトのみを投稿しています)。

私はinput type = "file"から始めるべきだと考えましたが、その後AngularJSはそれにバインドできないことがわかりました。

私が見つけることができるすべての例はドラッグ&ドロップのためにjQueryプラグインをラップするためのものです。 1つのファイルを簡単にアップロードしたいのですが。

私はAngularJSに慣れていないので、自分自身のディレクティブを書くことにまったく不安を感じません。

140
Gal Ben-Haim

Angularjs以外の依存関係のない実際の実用的なソリューション(v.1.0.6でテスト済み)

html

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

Angularjs(1.0.6)は "input-file"タグでng-modelをサポートしていないので、すべてを(最終的に)渡す "native-way"で行う必要があります。ユーザーから選択したファイル。

コントローラー

$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!... );

};

クールな部分は、未定義のcontent-typeとtransformRequest:angular.identityで、$ httpで選択することができます。マルチパートデータを処理するときに必要な境界を管理します。

182
Fabio Bonfante

単純/軽量 ng-file-upload ディレクティブを使用できます。 FileAPIフラッシュシムを備えた非HTML5ブラウザのドラッグ&ドロップ、ファイルの進行状況、およびファイルのアップロードをサポートしています。

<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);
  }); 

}];
42
danial

ファイルを直接送信するほうが効率的です。

Content-Type: multipart/form-database64エンコーディング は、さらに33%のオーバーヘッドを追加します。サーバがそれをサポートしている場合、ファイルを直接送信するほうが効率的です

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

Fileオブジェクト とともにPOSTを送信するときは、'Content-Type': undefinedを設定することが重要です。 XHR送信メソッド は、 Fileオブジェクト を検出し、自動的にコンテンツタイプ.

複数のファイルを送信するには、 FileListから直接複数の$http.post要求を行う を参照してください。


私はinput type = "file"から始めるべきだと考えましたが、その後AngularJSはそれにバインドできないことがわかりました。

<input type=file>要素は、デフォルトでは ng-modelディレクティブ では機能しません。 カスタムディレクティブ が必要です。

ng-modelで動作する "select-ng-files"ディレクティブの実用的なデモ1

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

angular.module("app").directive("selectNgFiles", 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" select-ng-files ng-model="fileArray" multiple>
    
    <h2>Files</h2>
    <div ng-repeat="file in fileArray">
      {{file.name}}
    </div>
  </body>

コンテンツタイプが$http.postmultipart/form-data

multipart/form-dataを送信しなければならない場合:

<form role="form" enctype="multipart/form-data" name="myForm">
    <input type="text"  ng-model="fdata.UserName">
    <input type="text"  ng-model="fdata.FirstName">
    <input type="file"  select-ng-files ng-model="filesArray" multiple>
    <button type="submit" ng-click="upload()">save</button>
</form>
$scope.upload = function() {
    var fd = new FormData();
    fd.append("data", angular.toJson($scope.fdata));
    for (i=0; i<$scope.filesArray.length; i++) {
        fd.append("file"+i, $scope.filesArray[i]);
    };

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

FormData API を使用してPOSTを送信する場合、'Content-Type': undefinedを設定することが重要です。 XHR送信メソッドFormDataオブジェクトを検出し、コンテンツタイプヘッダを自動的に multipart/form-dataに設定します。の適切な境界

7
georgeawg

私はこの問題を抱えています。だからいくつかのアプローチがあります。 1つ目は、新しいブラウザが

var formData = new FormData();

このリンクをたどって 現代のブラウザにどのようにサポートが制限されているかについての情報があるブログをたどってください、そうでなければそれは完全にこの問題を解決します。

それ以外の場合は、target属性を使用してフォームをiframeに投稿できます。フォームを投稿するときは、必ずdisplayプロパティをnoneに設定してターゲットをiframeに設定してください。ターゲットはiframeの名前です。 (ちょうどあなたが知っているので。)

これが役立つことを願っています

5
Edgar Martinez

私はこれが遅いエントリであることを知っていますが、私は簡単なアップロードディレクティブを作成しました。あなたはすぐに働くことができます!

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

ng-simple-upload GithubについてさらにWeb APIを使った例で説明します。

2
shammelburg

次のように、データをリソースactionsのparams属性に割り当てることで、$resource経由でアップロードできます。

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

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

私はちょうどAngularJsの簡単なアップローダのための簡単なディレクティブを(既存のものから)書いた。

(正確なjQueryアップローダープラグインは https://github.com/blueimp/jQuery-File-Upload です)

AngularJを使ったシンプルなアップローダ(CORS実装あり)

(サーバー側はPHP用ですが、ノードも簡単に変更できます)

1
sk8terboi87 ツ

代替案を追加したいと思います。角度ファイルアップロードを利用する。説明があります。

あなたはここで詳細な説明を見つけることができます: https://github.com/nervgh/angular-file-upload 例: https://github.com/nervgh/angular-file-upload/tree/master/examples/simple

0
Leo Much