AngularJS: Çok parçalı form ile basit bir dosya yükleme nasıl uygulanır?


144

AngularJS bir node.js sunucusuna basit bir çok bölümlü form sonrası yapmak istiyorum, form bir bölümünde bir JSON nesnesi ve diğer bölümünde bir görüntü içermelidir, (şu anda sadece $ kaynak ile JSON nesnesi gönderiyorum)

Ben girdi türü = "dosya" ile başlamak gerektiğini düşündüm, ama sonra AngularJS buna bağlanamıyor öğrendim ..

bulabildiğim tüm örnekler jQuery eklentilerini sürükle ve bırak için sarmak içindir. Bir dosyanın basit bir şekilde yüklenmesini istiyorum.

AngularJS'de yeniyim ve kendi yönergelerimi yazarken hiç rahat hissetmiyorum.


1
Sanırım bu yardımcı olabilir: noypi-linux.blogspot.com/2013/04/…
Noypi Gilas

1
Şu cevaba bakın: stackoverflow.com/questions/18571001/… Zaten çalışan sistemler için birçok seçenek var.
Anoyz

Yanıtlar:


188

Angularjs'den başka bağımlılığı olmayan gerçek bir çalışma çözümü (v.1.0.6 ile test edilmiştir)

html

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

Angularjs (1.0.6) , "girdi dosyası" etiketlerinde ng-modelini desteklemediğinden , kullanıcıdan seçilen tüm (sonunda) dosyaları geçiren bir "yerel" yolla yapmanız gerekir.

kontrolör

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

};

Serin kısım, tanımlanmamış içerik türü ve $ http'de doğru "içerik türü" seçme ve çok parçalı verileri kullanırken gereken sınırı yönetme yeteneği veren transformRequest: angular.identity .


2
@Fabio u plz bu transformRequest'in ne yaptığını bana açıklayabilir mi? açısal. kimlik nedir? Ben sadece çok parçalı dosya yükleme gerçekleştirmek için gün boyunca başımı beceriyor.
agpt

1
@RandomUser bir java dinlenme uygulamasında, bunun gibi bir şey mkyong.com/webservices/jax-rs/file-upload-example-in-jersey
Fabio Bonfante 12:14

2
vay, sadece parlak, çok teşekkürler. Burada birden fazla görüntü ve diğer bazı verileri de yüklemek zorundayım, bu yüzden fd.append("file", files[0]); fd.append("file",files[1]); fd.append("name", "MyName")
fd'yi

1
console.log (fd) formun boş olduğunu mu gösterir? bu şekilde mi
J Bourne

4
Hata ayıklama devre dışı bırakılmışsa (önerildiği gibi) bunun işe yaramayacağını unutmayın
Bruno Peres

42

Basit / hafif ng-dosya-karşıya yükleme yönergesini kullanabilirsiniz. FileAPI flash shim ile HTML5 olmayan tarayıcılar için sürükle bırak, dosya ilerleme ve dosya yüklemeyi destekler

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

}];

Bu, her dosya için bir seferde tek bir POST isteği gerçekleştirmiyor mu?
Anoyz

Evet öyle. Github sorun izleyicide dosyaları tek tek yüklemenin neden daha iyi olduğu konusunda tartışmalar var. Flash API, dosyaların birlikte gönderilmesini desteklemez ve AFAIK Amazon S3 de desteklemez.
danial

Yani, genel daha doğru yaklaşımın bir seferde bir dosya POST isteği göndermesi olduğunu mu söylüyorsunuz? Bunun çeşitli avantajlarını görebiliyorum, aynı zamanda sunucu tarafı dinlendirici bir destek yaparken daha fazla sorun yaşıyorum.
Anoyz

2
Uygulamam, her dosyayı kaynak tasarrufu olarak karşıya yüklemektir ve sunucu dosyayı yerel dosya sistemine (veya veritabanına) kaydeder ve o dosya için benzersiz bir kimlik (yani rastgele klasör / dosya adı veya db kimliği) döndürür. Daha sonra tüm yüklemeler tamamlandığında, istemci bu istek için yüklenen dosyaların ek verilerini ve kimliklerini içeren başka bir PUT / POST isteği gönderir. Ardından sunucu kaydı ilişkili dosyalarla kaydeder. Dosyaları yükleyip e-postayı gönderdiğinizde gmail gibidir.
danial

1
Bu "basit / hafif" değildir. Örnekler bölümünde yalnızca bir dosya yükleme örneği bile yoktur.
Chris

9

Bir dosyayı doğrudan göndermek daha etkilidir.

Kodlayan base64 arasında Content-Type: multipart/form-datailave bir% 33 yükü ekler. Sunucu destekliyorsa , dosyaları doğrudan göndermek daha etkilidir:

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

Bir File nesnesiyle bir POST gönderirken , ayarlamak önemlidir 'Content-Type': undefined. XHR gönderme yöntemi sonra algılar Dosya nesnesini ve otomatik içerik türünü ayarlayın.

Birden çok dosya göndermek için, bkz. Doğrudan Dosya Listesinden Birden Çok $http.postİstek Yapma


Ben girdi türü = "dosya" ile başlamak gerektiğini düşündüm, ama sonra AngularJS buna bağlanamıyor öğrendim ..

<input type=file>Eleman ile varsayılan çalışmalarından değil ng model direktifi . Bu bir ihtiyacı , özel yönergesi :

Çalışır "select-ng-dosyaları" Yönergesi Çalışma Demo ng-model1

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.post içerik türü ile multipart/form-data

Kişinin göndermesi gerekiyorsa 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 ile bir POST gönderirken , ayarlamak önemlidir 'Content-Type': undefined. XHR gönderme yöntemi daha sonra algılar FormDatanesne ve otomatik içerik tipi başlığı ayarlamak çok parçalı / form-verileri ile uygun sınır .


filesInputYönergesi açısal 1.6.7 ile çalışıyor gibi görünmüyor, ben dosyaları görebilirsiniz ng-repeatama aynı $scope.variabledenetleyicisi boştur? Ayrıca örnek kullanımlarından file-modelbiri ve birifiles-input
Dan

@ Test ettim ve işe yarıyor. Kodunuzla ilgili bir sorun yaşıyorsanız, Minimal, Complete, Doğrulanabilir bir örnekle yeni bir soru sormalısınız . Yönerge adı olarak değiştirildi select-ng-files. Açısal JS ile test edilmiştir 1.7.2.
georgeawg

5

Sadece bu sorunu yaşadım. Yani birkaç yaklaşım var. Birincisi, yeni tarayıcıların

var formData = new FormData();

Desteğin modern tarayıcılarla nasıl sınırlı olduğu hakkında bilgi içeren bir blogun bu bağlantısını takip edin , ancak aksi takdirde bu sorunu tamamen çözer.

Aksi takdirde, target özelliğini kullanarak formu bir iframe'e gönderebilirsiniz. Formu gönderirken, hedefi display özelliği none olarak ayarlanmış bir iframe olarak ayarladığınızdan emin olun. Hedef, iframe'in adıdır. (Sadece biliyorsun.)

Umarım bu yardımcı olur


AFAIK FormData IE ile çalışmaz. belki görüntü dosyasının base64 kodlaması yapmak ve JSON göndermek daha iyi bir fikir? Seçilen dosya yolunu almak için AngularJS ile bir girdi türü = "dosya" ya nasıl bağlanabilirim?
Gal Ben-Haim

3

Bunun geç bir giriş olduğunu biliyorum ama basit bir yükleme yönergesi oluşturdum. Hangi zaman içinde çalışma alabilirsiniz!

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

ng-simple- Web API kullanan bir örnekle Github'a daha fazla yükleyin .


2
dürüst olmak gerekirse, proje benioku kodunu kopyala yapıştır önermek büyük bir kara leke olabilir. projenizi npm veya bower gibi yaygın paket yöneticileriyle entegre etmeyi deneyin.
Stefano Torresi

2

$resourceAşağıdaki actionsgibi , kaynağın params özniteliğine veri atayarak yükleyebilirsiniz :

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.