AngularJs: Bagaimana cara memeriksa perubahan di bidang input file?

281

Saya baru di bidang sudut. Saya mencoba membaca jalur file yang diunggah dari bidang 'file' HTML setiap kali 'perubahan' terjadi di bidang ini. Jika saya menggunakan 'onChange' itu berfungsi tetapi ketika saya menggunakannya dengan cara sudut menggunakan 'ng-ubah' itu tidak berfungsi.

<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 () tidak pernah menelepon. Firebug juga tidak menunjukkan kesalahan.

Manish Kumar
sumber

Jawaban:

240

Tidak ada dukungan yang mengikat untuk kontrol Unggah File

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>

dari pada

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

dapatkah kamu mencoba

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

Catatan: ini membutuhkan aplikasi bersudut untuk selalu dalam mode debug . Ini tidak akan berfungsi dalam kode produksi jika mode debug dinonaktifkan.

dan dalam fungsi Anda berubah bukannya

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

dapatkah kamu mencoba

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

Di bawah ini adalah salah satu contoh pengunggahan file dengan unggahan file drag drop semoga bermanfaat http://jsfiddle.net/danielzen/utp7j/

Informasi Upload File Sudut

URL untuk Upload File AngularJS di ASP.Net

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

Unggahan multi-file asli AngularJs dengan kemajuan dengan NodeJS

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

ngUpload - Layanan AngularJS untuk mengunggah file menggunakan iframe

http://ngmodules.org/modules/ngUpload

JQuery Guru
sumber
2
onchange = "angular.element (this) .scope (). fileNameChaged (this)" $ scope.fileNameChaged = fungsi (elemen) {console.log ('file:', element.files); } Bisakah Anda berubah di dua tempat dan memeriksa? tergantung pada browser Anda akan mendapatkan path file lengkap saya telah memperbarui biola di bawah ini adalah file upload url dan periksa konsol jsfiddle.net/utp7j/260
JQuery Guru
13
Metode ini menghindari pemrosesan AngularJS default, jadi $ scope. $ Digest () tidak disebut (binding tidak diperbarui). Panggil 'angular.element (this) .scope (). $ Digest ()' sesudahnya atau panggil metode lingkup yang menggunakan $ apply.
Ramon de Klein
113
Ini jawaban yang mengerikan. Memanggil angular.element (blah) .scope () adalah fitur debug yang hanya digunakan untuk debugging. Angular tidak menggunakan fitur .scope. Itu hanya ada untuk membantu pengembang melakukan debug. Saat Anda membangun aplikasi dan menggunakan untuk produksi, Anda seharusnya mematikan info debug. Ini mempercepat semua BANYAK !!! Jadi, menulis kode yang bergantung pada elemen.scope () panggilan adalah ide yang buruk. Jangan lakukan ini. Jawaban tentang membuat arahan khusus adalah cara yang tepat untuk melakukan ini. @JQueryGuru Anda harus memperbarui jawaban Anda. Karena memiliki suara terbanyak, orang akan mengikuti saran buruk ini.
sangat dingin
7
Solusi ini akan merusak aplikasi ketika info debug dinonaktifkan. Menonaktifkan itu untuk produksi adalah rekomendasi resmi docs.angularjs.org/guide/production . Silakan lihat juga blog.thoughtram.io/angularjs/2014/12/22/…
wiherek
4
SOLUSI BURUK ... ... baca komentar lain tentang 'mematikan debugging' ... ... ... dan lihat sqrensolusinya ... ... ... @ 0MV1
dsdsdsdsd
477

Saya membuat arahan kecil untuk mendengarkan perubahan input file.

Lihat JSFiddle

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

    }
  };
});
sqren
sumber
4
Ini bekerja dengan baik jika file yang berbeda dipilih setiap kali. Apakah mungkin untuk mendengarkan ketika file yang sama juga dipilih?
JDawg
12
Ini memiliki satu "bug" yang sangat disayangkan - controller tidak terikat sebagai "ini" di customOnChange, tetapi input file! Itu membuat saya pergi untuk waktu yang lama dan saya tidak dapat menemukan bug yang sebenarnya. Saya belum yakin bagaimana sebenarnya menyebutnya dengan mengatur "this" dengan benar.
Karel Bílek
4
biola tidak bekerja untuk saya, baik di Chrome atau Firefox, seperti hari ini.
seguso
2
Jawaban ini cacat seperti yang dinyatakan oleh @ KarelBílek. Saya tidak bisa mengatasinya dan memutuskan untuk menggunakan angular-file-upload.
Gunar Gessner
2
Ini benar-benar cara melakukannya, bekerja seperti pesona. Selain itu, mengapa Anda menggunakan fitur debug dalam produksi?
Justin Kruse
42

Ini adalah penyempurnaan dari beberapa yang lain di sekitar, data akan berakhir dalam model-ng, yang biasanya apa yang Anda inginkan.

Markup (cukup buat file data atribut sehingga direktif dapat menemukannya)

<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();
            });
        }
    };
});
Stuart Axon
sumber
1
Apakah $scope.$apply();wajib? ng-changeAcara saya sepertinya masih menyala tanpa itu.
row1
1
@ row1 Anda hanya perlu memecat aplikasi secara manual jika Anda memiliki hal-hal sudut lain yang perlu diketahui tentang hal itu selama operasi itu.
Scott Sword
27

Cara bersih adalah menulis arahan Anda sendiri untuk mengikat "perubahan" acara. Hanya untuk memberi tahu Anda bahwa IE9 tidak mendukung FormData sehingga Anda tidak dapat benar-benar mendapatkan objek file dari acara perubahan.

Anda dapat menggunakan perpustakaan ng-file-upload yang sudah mendukung IE dengan FileAPI polyfill dan menyederhanakan posting file ke server. Ini menggunakan arahan untuk mencapai ini.

<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);
      }); 
    }
  }
}];
danial
sumber
Contoh ini sudah usang. Dapatkan yang baru dari dokumen di sini .
Gunar Gessner
26

Saya telah memperluas ide @Stuart Axon untuk menambahkan penjilidan dua arah untuk input file (yaitu mengizinkan pengaturan ulang input dengan mengatur ulang nilai model kembali ke nol):

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("");
                }
            });
        }
    };
}]);

Demo

JLRishe
sumber
@JLRishe terima kasih. Satu catatan, sebenarnya data-ng-click="vm.theFile=''"berfungsi dengan baik, tidak perlu menulisnya ke metode pengontrol
Sergey
20

Mirip dengan beberapa jawaban baik lainnya di sini, saya menulis arahan untuk menyelesaikan masalah ini, tetapi implementasi ini lebih dekat mencerminkan cara sudut melampirkan peristiwa.

Anda dapat menggunakan arahan seperti ini:

HTML

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

Seperti yang Anda lihat, Anda dapat menyuntikkan file yang dipilih ke pengatur acara Anda, karena Anda akan menyuntikkan objek $ event ke pengatur acara apa pun.

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);
      }
    };
  }]);
Simon Robb
sumber
berjuang selama beberapa hari dengan ini sampai saya mencoba jawaban Anda. Terima kasih!
Michael Tranchida
Bagaimana saya bisa meneruskan parameter tambahan ke fileChangeekspresi? Saya menggunakan arahan ini di dalam ng-repeatdan $scopevariabel yang diteruskan ke attrHandleradalah sama untuk setiap catatan. Apa solusi terbaik?
16

Arahan ini meneruskan file yang dipilih juga:

/**
 *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, bagaimana menggunakannya:

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

Di controller saya:

$scope.onFilesSelected = function(files) {
     console.log("files - " + files);
};
ingaham
sumber
Bagaimana $ scope.onFilesSelected terlihat di controller Anda?
ingaham
Jika file dibuka dan ketika kami mencoba mengunggah dalam file di browser Microsoft Edge. Tidak ada yang terjadi. Bisakah kamu menolong?
Naveen Katakam
Ya, itu berfungsi baik dengan browser lain. Saya menghadapi masalah di microsoft edge @ingaham
Naveen Katakam
8

Saya merekomendasikan untuk membuat arahan

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

        };
    }]);

arahan ini dapat digunakan berkali-kali, ia menggunakan ruang lingkupnya sendiri dan tidak bergantung pada ruang lingkup orang tua. Anda juga dapat memberikan beberapa params ke fungsi penangan. Fungsi handler akan dipanggil dengan objek lingkup, yang aktif ketika Anda mengubah input. $ apply perbarui model Anda setiap kali acara perubahan dipanggil

Julia Usanova
sumber
4

Versi jqLite Angular paling sederhana.

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()">
Jonáš Krutil
sumber
Jika file dibuka dan ketika kami mencoba mengunggah dalam file di browser Microsoft Edge. Tidak ada yang terjadi. Bisakah kamu menolong?
Naveen Katakam
2

Demo Demo "input-file" yang Bekerja dengan ng-change1

Untuk membuat suatu <input type=file>elemen bekerja dengan direktif perubahan-ng , diperlukan perintah kustom yang bekerja dengan direktif model-ng .

<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>

georgeawg
sumber
Hebat tapi direktif hanya disebut sekali! Jika saya mengubah file yang dipilih maka arahan tidak disebut yang kedua kalinya! Apakah Anda tahu tentang perilaku ini?
hugsbrugs
DEMO tidak memiliki masalah itu. Buat pertanyaan baru dengan contoh yang dapat direproduksi untuk diperiksa pembaca.
georgeawg
ya itu punya masalah log konsol "perubahan input" hanya menampilkan sekali bahkan jika Anda mengubah file yang dipilih berkali-kali!
hugsbrugs
setelah pengujian, ini bekerja pada chromium tetapi tidak pada versi firefox terbaru ... kompatibilitas browser sialan !!!
hugsbrugs
0

Solusi yang terlalu lengkap berdasarkan:

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

Cara sederhana untuk menyembunyikan bidang input dan menggantinya dengan gambar, di sini setelah solusi, yang juga memerlukan peretasan pada sudut tetapi yang melakukan pekerjaan [TriggerEvent tidak bekerja seperti yang diharapkan]

Solusinya:

  • letakkan bidang input di layar: tidak ada [bidang input ada di DOM tetapi tidak terlihat]
  • letakkan gambar Anda tepat setelah Di gambar gunakan nb-klik () untuk mengaktifkan metode

Ketika gambar diklik, simulasikan tindakan DOM 'klik' pada bidang input. Dan lagi!

 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!!!
    };
Fulup
sumber
1
Anda tidak dapat menggunakan angular.element (this) .scope (), ini adalah fitur debug!
Cesar
0

Saya telah melakukannya seperti ini;

<!-- 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");
}
Ali Sakhi
sumber
0

Cara lain yang menarik untuk mendengarkan perubahan input file adalah dengan mengawasi atribut ng-model dari file input. Tentu saja FileModel adalah arahan khusus.

Seperti ini:

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

Kode JS ->

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

Semoga bisa membantu seseorang.

halbano
sumber
0

Elemen sudut (seperti elemen root dari direktif) adalah objek jQuery [Lite]. Ini berarti kami dapat mendaftarkan pendengar acara seperti:

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

Ini adalah delegasi acara jQuery. Di sini, pendengar dilampirkan ke elemen root dari direktif. Ketika acara dipicu, itu akan muncul ke elemen terdaftar dan jQuery akan menentukan apakah acara tersebut berasal dari elemen dalam yang cocok dengan pemilih yang ditentukan. Jika ya, pawang akan menembak.

Manfaat dari metode ini adalah:

  • pawang terikat pada elemen $ yang akan secara otomatis dibersihkan ketika ruang lingkup direktif dihancurkan.
  • tidak ada kode di templat
  • akan berfungsi walaupun delegasi target (input) belum diberikan saat Anda mendaftarkan event handler (seperti ketika menggunakan ng-ifatau ng-switch)

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

Matt S
sumber
-1

Anda cukup menambahkan kode di bawah ini dalam pertukaran dan itu akan mendeteksi perubahan. Anda dapat menulis fungsi pada klik X atau sesuatu untuk menghapus data file ..

document.getElementById(id).value = "";
Jijo Thomas
sumber
Ini adalah praktik yang buruk dan tidak seperti sudut.
Sebastian