AngularJs: Dosya giriş alanlarındaki değişiklikler nasıl kontrol edilir?


281

Açısal için yeniyim. Bu alanda bir 'değişiklik' olduğunda HTML 'dosya' alanından yüklenen dosya yolunu okumaya çalışıyorum. Ben 'onChange' kullanırsanız çalışır ama 'ng-change' kullanarak açısal bir şekilde kullandığınızda çalışmıyor.

<script>
   var DemoModule = angular.module("Demo",[]);
   DemoModule .controller("form-cntlr",function($scope){
   $scope.selectFile = function()
   {
        $("#file").click();
   }
   $scope.fileNameChaged = function()
   {
        alert("select file");
   }
});
</script>

<div ng-controller="form-cntlr">
    <form>
         <button ng-click="selectFile()">Upload Your File</button>
         <input type="file" style="display:none" 
                          id="file" name='file' ng-Change="fileNameChaged()"/>
    </form>  
</div>

fileNameChaged () hiçbir zaman çağrılamaz. Firebug ayrıca herhangi bir hata göstermez.



Yanıtlar:


240

Dosya Yükleme kontrolü için bağlayıcı destek yok

https://github.com/angular/angular.js/issues/1375

<div ng-controller="form-cntlr">
        <form>
             <button ng-click="selectFile()">Upload Your File</button>
             <input type="file" style="display:none" 
                id="file" name='file' onchange="angular.element(this).scope().fileNameChanged(this)" />
        </form>  
    </div>

onun yerine

 <input type="file" style="display:none" 
    id="file" name='file' ng-Change="fileNameChanged()" />

deneyebilir misin

<input type="file" style="display:none" 
    id="file" name='file' onchange="angular.element(this).scope().fileNameChanged()" />

Not: Bu, açısal uygulamanın her zaman hata ayıklama modunda olmasını gerektirir . Hata ayıklama modu devre dışıysa üretim kodunda çalışmaz.

ve işlevinizde yerine

$scope.fileNameChanged = function() {
   alert("select file");
}

deneyebilir misin

$scope.fileNameChanged = function() {
  console.log("select file");
}

Aşağıda sürükle bırak dosya yükleme ile dosya yükleme bir çalışma örneği http://jsfiddle.net/danielzen/utp7j/ yardımcı olabilir

Açısal Dosya Yükleme Bilgileri

ASP.Net'te AngularJS Dosya Yüklemesi için URL

http://cgeers.com/2013/05/03/angularjs-file-upload/

NodeJS ile devam eden AngularJs yerel çoklu dosya yüklemesi

http://jasonturim.wordpress.com/2013/09/12/angularjs-native-multi-file-upload-with-progress/

ngUpload - iframe kullanarak dosya yüklemek için bir AngularJS Hizmeti

http://ngmodules.org/modules/ngUpload


2
onchange = "angular.element (this) .scope (). fileNameChaged (this)" $ scope.fileNameChaged = function (element) {console.log ('dosyalar:', element.files); } İki yerde değişip kontrol edebilir misiniz? tarayıcıya bağlı olarak ben aşağıdaki keman güncelleme var tam yol dosyayı alacak url yükleme dosyası ve kontrol konsolu jsfiddle.net/utp7j/260
JQuery Guru

13
Bu yöntem varsayılan AngularJS işlemeyi engeller, bu yüzden $ scope. $ Digest () çağrılmaz (bağlar güncellenmez). Daha sonra 'angular.element (this) .scope (). $ Digest ()' çağırın ya da $ Apply kullanan bir kapsam yöntemini çağırın.
Ramon de Klein

113
Bu korkunç bir cevap. Angular.element (blah) .scope () öğesini çağırmak, yalnızca hata ayıklama için kullanmanız gereken bir hata ayıklama özelliğidir. Angular .scope özelliğini kullanmaz. Sadece geliştiricilerin hata ayıklamasına yardımcı olmak için var. Uygulamanızı oluşturup üretime dağıtırken hata ayıklama bilgilerini kapatmanız gerekir. Bu tüm A LOT hızlandırır !!! Bu nedenle, element.scope () çağrılarına bağlı kod yazmak kötü bir fikirdir. Bunu yapma. Özel yönerge oluşturma ile ilgili cevap, bunu yapmanın doğru yoludur. @JQueryGuru cevabınızı güncellemelisiniz. En çok oyu aldığı için insanlar bu kötü tavsiyeye uyacaktır.
soğuk

7
Hata ayıklama bilgisi devre dışı bırakıldığında bu çözüm uygulamayı kıracaktır. Üretim için devre dışı bırakmak resmi bir öneri niteliğindedir docs.angularjs.org/guide/production . Ayrıca bkz. Blog.thoughtram.io/angularjs/2014/12/22/…
wiherek

4
KÖTÜ ÇÖZÜM ... ... 'hata ayıklamayı kapatma' hakkındaki diğer yorumları okuyun ... ... ... ve sqrençözümünü görün ... ... ... @ 0MV1
dsdsdsdsd

477

Dosya girişi değişikliklerini dinlemek için küçük bir yönerge hazırladım.

JSFiddle'ı görüntüle

view.html:

<input type="file" custom-on-change="uploadFile">

controller.js:

app.controller('myCtrl', function($scope){
    $scope.uploadFile = function(event){
        var files = event.target.files;
    };
});     

directive.js:

app.directive('customOnChange', function() {
  return {
    restrict: 'A',
    link: function (scope, element, attrs) {
      var onChangeHandler = scope.$eval(attrs.customOnChange);
      element.on('change', onChangeHandler);
      element.on('$destroy', function() {
        element.off();
      });

    }
  };
});

4
Her seferinde farklı bir dosya seçilirse bu işe yarar. Aynı dosya seçildiğinde de dinlemek mümkün müdür?
JDawg

12
Bu çok talihsiz bir "hata" vardır - denetleyici customOnChange, ancak dosya girişi "bu" olarak bağlı değildir! Beni uzun süre attı ve asıl hatayı bulamadım. Ben gerçekten doğru ayarlamak "bu" ile nasıl aramak emin değilim.
Karel Bílek

4
keman, bugün itibariyle Chrome veya Firefox'ta benim için çalışmıyor.
seguso

2
Bu cevap @ KarelBílek'in belirttiği gibi kusurludur. Ben bunu alamadım ve açısal dosya yükleme kullanmaya karar verdim.
Gunar Gessner

2
Bu kesinlikle nasıl yapılır, bir cazibe gibi çalıştı. Ayrıca, üretimde neden hata ayıklama özelliğini kullanasınız?
Justin Kruse

42

Bu, etrafındaki diğer bazıların ayrıntılandırılmasıdır, veriler normalde istediğiniz bir ng modeli ile sonuçlanır.

İşaretleme (yalnızca yönerge bulabilmesi için bir öznitelik veri dosyası oluşturun)

<input
    data-file
    id="id_image" name="image"
    ng-model="my_image_model" type="file">

JS

app.directive('file', function() {
    return {
        require:"ngModel",
        restrict: 'A',
        link: function($scope, el, attrs, ngModel){
            el.bind('change', function(event){
                var files = event.target.files;
                var file = files[0];

                ngModel.$setViewValue(file);
                $scope.$apply();
            });
        }
    };
});

1
Is $scope.$apply();gerekli? Benim ng-changeolay hala onsuz yangın gibi görünüyor.
row1

1
@ row1, yalnızca bu işlem sırasında bilmeniz gereken başka açısal şeyleriniz varsa bir uygulamayı manuel olarak başlatmanız gerekir .
Scott Sword

27

Temiz yol, "change" etkinliğine bağlanmak için kendi direktifinizi yazmaktır. IE9 FormData'yı desteklemediğini bildirmek için dosya nesnesini gerçekten değişiklik olayından alamazsınız.

FileAPI çoklu dolgusu ile IE'yi zaten destekleyen ng-dosya yükleme kütüphanesini kullanabilir ve dosyayı sunucuya göndermeyi basitleştirebilirsiniz. Bunu başarmak için bir direktif kullanır.

<script src="angular.min.js"></script>
<script src="ng-file-upload.js"></script>

<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) {
    //$files: an array of files selected, each file has name, size, and type.
    for (var i = 0; i < $files.length; i++) {
      var $file = $files[i];
      Upload.upload({
        url: 'my/upload/url',
        data: {file: $file}
      }).then(function(data, status, headers, config) {
        // file is uploaded successfully
        console.log(data);
      }); 
    }
  }
}];

Bu örnek eski. Burada dokümanlardan yenisini alın .
Gunar Gessner

26

@Stuart Axon'un dosya girişi için iki yönlü ciltleme ekleme fikrini genişlettim (yani model değerini null değerine sıfırlayarak girişi sıfırlamaya izin ver):

app.directive('bindFile', [function () {
    return {
        require: "ngModel",
        restrict: 'A',
        link: function ($scope, el, attrs, ngModel) {
            el.bind('change', function (event) {
                ngModel.$setViewValue(event.target.files[0]);
                $scope.$apply();
            });

            $scope.$watch(function () {
                return ngModel.$viewValue;
            }, function (value) {
                if (!value) {
                    el.val("");
                }
            });
        }
    };
}]);

gösteri


Teşekkürler @JLRishe. Bir not, aslında data-ng-click="vm.theFile=''"iyi çalışıyor, bir denetleyici yöntemine yazmaya gerek yok
Sergey

20

Buradaki diğer iyi cevaplara benzer şekilde, bu sorunu çözmek için bir direktif yazdım, ancak bu uygulama olayları eklemenin açısal yolunu daha yakından yansıtıyor.

Direktifi şu şekilde kullanabilirsiniz:

HTML

<input type="file" file-change="yourHandler($event, files)" />

Gördüğünüz gibi, herhangi bir ng olay işleyicisine bir $ olay nesnesi enjekte edeceğiniz gibi, olay işleyicinize seçilen dosyaları enjekte edebilirsiniz.

JavaScript

angular
  .module('yourModule')
  .directive('fileChange', ['$parse', function($parse) {

    return {
      require: 'ngModel',
      restrict: 'A',
      link: function ($scope, element, attrs, ngModel) {

        // Get the function provided in the file-change attribute.
        // Note the attribute has become an angular expression,
        // which is what we are parsing. The provided handler is 
        // wrapped up in an outer function (attrHandler) - we'll 
        // call the provided event handler inside the handler()
        // function below.
        var attrHandler = $parse(attrs['fileChange']);

        // This is a wrapper handler which will be attached to the
        // HTML change event.
        var handler = function (e) {

          $scope.$apply(function () {

            // Execute the provided handler in the directive's scope.
            // The files variable will be available for consumption
            // by the event handler.
            attrHandler($scope, { $event: e, files: e.target.files });
          });
        };

        // Attach the handler to the HTML change event 
        element[0].addEventListener('change', handler, false);
      }
    };
  }]);

Ben cevabınızı denedim kadar bu birkaç gün için mücadele etti. Teşekkürler!
Michael Tranchida

İfadeye nasıl ek bir parametre iletebilirim fileChange? Bu yönergeyi bir içinde kullanıyorum ng-repeatve $scopegeçirilen değişken attrHandlerher kayıt için aynıdır. En iyi çözüm nedir?

16

Bu yönerge seçilen dosyaları da iletir:

/**
 *File Input - custom call when the file has changed
 */
.directive('onFileChange', function() {
  return {
    restrict: 'A',
    link: function (scope, element, attrs) {
      var onChangeHandler = scope.$eval(attrs.onFileChange);

      element.bind('change', function() {
        scope.$apply(function() {
          var files = element[0].files;
          if (files) {
            onChangeHandler(files);
          }
        });
      });

    }
  };
});

HTML, nasıl kullanılır:

<input type="file" ng-model="file" on-file-change="onFilesSelected">

Kontrol cihazımda:

$scope.onFilesSelected = function(files) {
     console.log("files - " + files);
};

$ Scope.onFilesSelected kumandanızda nasıl görünüyor?
ingaham

Bir dosya açılırsa ve dosyayı Microsoft Edge tarayıcısında yüklemeyi denediğimizde. Hiçbir şey olmuyor. Yardım edebilir misin?
Naveen Katakam

Evet, diğer tarayıcılarla iyi çalışıyor. Microsoft Edge @ingaham sorunu yaşıyorum
Naveen Katakam

8

Bir direktif oluşturmanızı tavsiye ederim

<input type="file" custom-on-change handler="functionToBeCalled(params)">

app.directive('customOnChange', [function() {
        'use strict';

        return {
            restrict: "A",

            scope: {
                handler: '&'
            },
            link: function(scope, element){

                element.change(function(event){
                    scope.$apply(function(){
                        var params = {event: event, el: element};
                        scope.handler({params: params});
                    });
                });
            }

        };
    }]);

bu direktif birçok kez kullanılabilir, kendi kapsamını kullanır ve ebeveyn kapsamına bağlı değildir. İşleyici işlevine bazı parametreler de verebilirsiniz. İşleyici işlevi, girdiyi değiştirdiğinizde etkin olan kapsam nesnesiyle çağrılır. $ Apply, değişiklik etkinliği her çağrıldığında modelinizi günceller


4

En basit Açısal jqLite sürümü.

JS:

.directive('cOnChange', function() {
    'use strict';

    return {
        restrict: "A",
        scope : {
            cOnChange: '&'
        },
        link: function (scope, element) {
            element.on('change', function () {
                scope.cOnChange();
        });
        }
    };
});

HTML:

<input type="file" data-c-on-change="your.functionName()">

Bir dosya açılırsa ve dosyayı Microsoft Edge tarayıcısında yüklemeyi denediğimizde. Hiçbir şey olmuyor. Yardım edebilir misin?
Naveen Katakam

2

İle çalışan "dosya-girdi" Yönergesi Çalışma Demo ng-change1

Bir <input type=file>öğenin ng-change yönergesini çalışması için ng-model yönergesiyle çalışan özel bir yönerge gerekir .

<input type="file" files-input ng-model="fileList" 
       ng-change="onInputChange()" multiple />

DEMO

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

.controller("ctrl", function($scope) {
     $scope.onInputChange = function() {
         console.log("input change");
     };
})
<script src="//unpkg.com/angular/angular.js"></script>
  <body ng-app="app" ng-controller="ctrl">
    <h1>AngularJS Input `type=file` Demo</h1>
    
    <input type="file" files-input ng-model="fileList" 
           ng-change="onInputChange()" multiple />
    
    <h2>Files</h2>
    <div ng-repeat="file in fileList">
      {{file.name}}
    </div>
  </body>


Büyük ama direktif sadece bir kez çağrılır! Seçilen dosyayı değiştirirsem yönerge ikinci kez çağrılmaz! Bu davranış hakkında herhangi bir fikriniz var mı?
hugsbrugs

DEMO'nun bu sorunu yok. Okuyucuların incelemesi için tekrarlanabilir bir örnekle yeni bir soru oluşturun .
georgeawg

evet bu sorun var konsol günlüğü "giriş değişikliği" seçilen dosyaları defalarca değiştirseniz bile sadece bir kez görüntülenir!
hugsbrugs

test ettikten sonra, krom üzerinde çalışır, ancak en son firefox sürümünde ... lanet olası tarayıcı uyumluluğu!
hugsbrugs

0

Çok fazla çözüm temeli:

`onchange="angular.element(this).scope().UpLoadFile(this.files)"`

Giriş alanını gizlemenin ve onu bir çözümden sonra, açısal bir saldırı gerektiren ancak işi yapan bir görüntüyle değiştirmenin basit bir yolu [TriggerEvent beklendiği gibi çalışmıyor]

Çözüm:

  • giriş alanını ekrana yerleştirin: yok [DOM'da giriş alanı var ancak görünmüyor]
  • Resminizi hemen arkasına yerleştirin Resimde bir yöntemi etkinleştirmek için nb-click () kullanın

Resim tıklandığında, giriş alanında bir DOM eylemi 'tıklama' simülasyonu yapın. Et voilà!

 var tmpl = '<input type="file" id="{{name}}-filein"' + 
             'onchange="angular.element(this).scope().UpLoadFile(this.files)"' +
             ' multiple accept="{{mime}}/*" style="display:none" placeholder="{{placeholder}}">'+
             ' <img id="{{name}}-img" src="{{icon}}" ng-click="clicked()">' +
             '';
   // Image was clicked let's simulate an input (file) click
   scope.inputElem = elem.find('input'); // find input in directive
   scope.clicked = function () {
         console.log ('Image clicked');
         scope.inputElem[0].click(); // Warning Angular TriggerEvent does not work!!!
    };

1
Angular.element (this) .scope () kullanamazsınız, bu bir hata ayıklama özelliğidir!
Cesar

0

Ben böyle yaptım;

<!-- HTML -->
<button id="uploadFileButton" class="btn btn-info" ng-click="vm.upload()">    
<span  class="fa fa-paperclip"></span></button>
<input type="file" id="txtUploadFile" name="fileInput" style="display: none;" />
// self is the instance of $scope or this
self.upload = function () {
   var ctrl = angular.element("#txtUploadFile");
   ctrl.on('change', fileNameChanged);
   ctrl.click();
}

function fileNameChanged(e) {
    console.log(self.currentItem);
    alert("select file");
}

0

Dosya giriş değişikliklerini dinlemenin bir başka ilginç yolu da giriş dosyasının ng-model özniteliğini izlemektir. Elbette FileModel özel bir direktiftir.

Bunun gibi:

HTML -> <input type="file" file-model="change.fnEvidence">

JS Kodu ->

$scope.$watch('change.fnEvidence', function() {
                    alert("has changed");
                });

Umarım birine yardımcı olabilir.


0

Açısal elemanlar (bir direktifin kök elemanı gibi) jQuery [Lite] nesneleridir. Bu, olay dinleyicisini şu şekilde kaydedebileceğimiz anlamına gelir:

link($scope, $el) {
    const fileInputSelector = '.my-file-input'

    function setFile() {
        // access file via $el.find(fileInputSelector).get(0).files[0]
    }

    $el.on('change', fileInputSelector, setFile)
}

Bu jQuery olay temsilcisidir. Burada dinleyici, direktifin kök öğesine eklenmiştir. Olay tetiklendiğinde, kayıtlı öğeye yükselir ve jQuery, olayın tanımlanmış seçiciyle eşleşen bir iç öğeden kaynaklanıp kaynaklanmadığını belirler. Varsa, işleyici ateşleyecektir.

Bu yöntemin faydaları:

  • işleyici, yönerge kapsamı yok edildiğinde otomatik olarak temizlenecek olan $ öğesine bağlıdır.
  • şablonda kod yok
  • Eğer olay işleyicisi kayıt sırasında hedef temsilci (giriş) Henüz oluşturulmamış olsa bile çalışacaktır (örneğin kullanırken olarak ng-ifya ng-switch)

http://api.jquery.com/on/


-1

Değişimde aşağıdaki kodu basitçe ekleyebilirsiniz ve değişikliği algılar. X verilerini veya fonksiyon verilerini kaldırmak için bir şey yazabilirsiniz.

document.getElementById(id).value = "";

Bu kötü bir uygulamadır ve açısal değildir.
Sebastian
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.