290

タイプファイルの入力タグで ng-model を使用しようとしました:

<input type="file" ng-model="vm.uploadme" />

しかし、コントローラーでファイルを選択した後、 $scope.vm.uploadme はまだ定義されていません。

コントローラーで選択したファイルを取得するにはどうすればよいですか?

4

13 に答える 13

334

ディレクティブを使用して回避策を作成しました:

.directive("fileread", [function () {
    return {
        scope: {
            fileread: "="
        },
        link: function (scope, element, attributes) {
            element.bind("change", function (changeEvent) {
                var reader = new FileReader();
                reader.onload = function (loadEvent) {
                    scope.$apply(function () {
                        scope.fileread = loadEvent.target.result;
                    });
                }
                reader.readAsDataURL(changeEvent.target.files[0]);
            });
        }
    }
}]);

入力タグは次のようになります。

<input type="file" fileread="vm.uploadme" />

または、ファイル定義だけが必要な場合:

.directive("fileread", [function () {
    return {
        scope: {
            fileread: "="
        },
        link: function (scope, element, attributes) {
            element.bind("change", function (changeEvent) {
                scope.$apply(function () {
                    scope.fileread = changeEvent.target.files[0];
                    // or all selected files:
                    // scope.fileread = changeEvent.target.files;
                });
            });
        }
    }
}]);
于 2013-06-12T10:20:48.613 に答える
53

私はこのディレクティブを使用します:

angular.module('appFilereader', []).directive('appFilereader', function($q) {
    var slice = Array.prototype.slice;

    return {
        restrict: 'A',
        require: '?ngModel',
        link: function(scope, element, attrs, ngModel) {
                if (!ngModel) return;

                ngModel.$render = function() {};

                element.bind('change', function(e) {
                    var element = e.target;

                    $q.all(slice.call(element.files, 0).map(readFile))
                        .then(function(values) {
                            if (element.multiple) ngModel.$setViewValue(values);
                            else ngModel.$setViewValue(values.length ? values[0] : null);
                        });

                    function readFile(file) {
                        var deferred = $q.defer();

                        var reader = new FileReader();
                        reader.onload = function(e) {
                            deferred.resolve(e.target.result);
                        };
                        reader.onerror = function(e) {
                            deferred.reject(e);
                        };
                        reader.readAsDataURL(file);

                        return deferred.promise;
                    }

                }); //change

            } //link
    }; //return
});

次のように呼び出します。

<input type="file" ng-model="editItem._attachments_uri.image" accept="image/*" app-filereader />

プロパティ (editItem.editItem._attachments_uri.image) には、選択したファイルの内容が data-uri (!) として入力されます。

このスクリプトは何もアップロードしないことに注意してください。データ uri (base64) でエンコードされたファイルのコンテンツのみをモデルに取り込みます。

ここで動作するデモをチェックしてください: http://plnkr.co/CMiHKv2BEidM9SShm9Vv

于 2013-10-01T17:04:40.497 に答える
26

これは、@endy-tjahjono のソリューションの補遺です。

スコープからuploadmeの値を取得できなくなりました。HTML のuploadmeがディレクティブによって明らかに更新されたにもかかわらず、$scope.uploadme によってその値にアクセスできませんでした。ただし、スコープから値を設定することはできました。神秘的ですよね..?

結局のところ、ディレクティブによって子スコープが作成され、子スコープには独自のuploadmeがありました。

解決策は、プリミティブではなくオブジェクトを使用して、uploadmeの値を保持することでした。

私が持っているコントローラで:

$scope.uploadme = {};
$scope.uploadme.src = "";

そしてHTMLで:

 <input type="file" fileread="uploadme.src"/>
 <input type="text" ng-model="uploadme.src"/>

ディレクティブに変更はありません。

これで、すべてが期待どおりに機能します。$scope.uploadme を使用して、コントローラーからuploadme.srcの値を取得できます。

于 2013-09-20T07:31:15.863 に答える
9

ディレクティブを作成し、bower に登録しました。

このライブラリは、入力ファイルをモデリングするのに役立ちます。ファイル データを返すだけでなく、ファイル dataurl または base 64 も返します。

{
    "lastModified": 1438583972000,
    "lastModifiedDate": "2015-08-03T06:39:32.000Z",
    "name": "gitignore_global.txt",
    "size": 236,
    "type": "text/plain",
    "data": "data:text/plain;base64,DQojaWdub3JlIHRodW1ibmFpbHMgY3JlYXRlZCBieSB3aW5kb3dz…xoDQoqLmJhaw0KKi5jYWNoZQ0KKi5pbGsNCioubG9nDQoqLmRsbA0KKi5saWINCiouc2JyDQo="
}

https://github.com/mistralworks/ng-file-model/

于 2015-09-10T17:41:18.607 に答える
4

これはわずかに変更されたバージョンで、ng-model の使用法と同じように、スコープで属性の名前を指定できます。

    <myUpload key="file"></myUpload>

指令:

.directive('myUpload', function() {
    return {
        link: function postLink(scope, element, attrs) {
            element.find("input").bind("change", function(changeEvent) {                        
                var reader = new FileReader();
                reader.onload = function(loadEvent) {
                    scope.$apply(function() {
                        scope[attrs.key] = loadEvent.target.result;                                
                    });
                }
                if (typeof(changeEvent.target.files[0]) === 'object') {
                    reader.readAsDataURL(changeEvent.target.files[0]);
                };
            });

        },
        controller: 'FileUploadCtrl',
        template:
                '<span class="btn btn-success fileinput-button">' +
                '<i class="glyphicon glyphicon-plus"></i>' +
                '<span>Replace Image</span>' +
                '<input type="file" accept="image/*" name="files[]" multiple="">' +
                '</span>',
        restrict: 'E'

    };
});
于 2014-07-31T11:21:30.460 に答える
3

lodash またはアンダースコアを使用して複数のファイルを入力する場合:

.directive("fileread", [function () {
    return {
        scope: {
            fileread: "="
        },
        link: function (scope, element, attributes) {
            element.bind("change", function (changeEvent) {
                return _.map(changeEvent.target.files, function(file){
                  scope.fileread = [];
                  var reader = new FileReader();
                  reader.onload = function (loadEvent) {
                      scope.$apply(function () {
                          scope.fileread.push(loadEvent.target.result);
                      });
                  }
                  reader.readAsDataURL(file);
                });
            });
        }
    }
}]);
于 2015-03-12T19:36:14.057 に答える
2

複数の入力で同じことをしなければならなかったので、@Endy Tjahjono メソッドを更新しました。読み取ったすべてのファイルを含む配列を返します。

  .directive("fileread", function () {
    return {
      scope: {
        fileread: "="
      },
      link: function (scope, element, attributes) {
        element.bind("change", function (changeEvent) {
          var readers = [] ,
              files = changeEvent.target.files ,
              datas = [] ;
          for ( var i = 0 ; i < files.length ; i++ ) {
            readers[ i ] = new FileReader();
            readers[ i ].onload = function (loadEvent) {
              datas.push( loadEvent.target.result );
              if ( datas.length === files.length ){
                scope.$apply(function () {
                  scope.fileread = datas;
                });
              }
            }
            readers[ i ].readAsDataURL( files[i] );
          }
        });

      }
    }
  });
于 2014-03-08T22:06:05.787 に答える