AngularJs: फ़ाइल इनपुट फ़ील्ड में परिवर्तन की जाँच कैसे करें?


281

मैं कोणीय के लिए नया हूं। जब भी इस क्षेत्र में कोई 'परिवर्तन' होता है, तो मैं HTML 'फ़ाइल' फ़ील्ड से अपलोड की गई फ़ाइल पथ को पढ़ने का प्रयास कर रहा हूं। अगर मैं 'onChange' का उपयोग करता हूं तो यह काम करता है लेकिन जब मैं इसे 'ng-change' का उपयोग करके कोणीय तरीके से उपयोग करता हूं तो यह काम नहीं करता है।

<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 () कभी कॉल नहीं कर रहा है। फायरबग भी कोई त्रुटि नहीं दिखाता है।


1
मददगार हो सकता है: stackoverflow.com/q/17063000/983992
मार्सेल ग्वारडर

जवाबों:


240

फ़ाइल अपलोड नियंत्रण के लिए कोई बाध्यकारी समर्थन नहीं

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>

के बजाय

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

क्या आप इसे आजमा सकते है

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

नोट: इसके लिए कोणीय अनुप्रयोग हमेशा डिबग मोड में होना चाहिए । डिबग मोड अक्षम होने पर यह उत्पादन कोड में काम नहीं करेगा।

और इसके बजाय आपके फ़ंक्शन में परिवर्तन होता है

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

क्या आप इसे आजमा सकते है

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

नीचे ड्रैग ड्रॉप फाइल अपलोड के साथ फाइल अपलोड का एक काम करने वाला उदाहरण सहायक हो सकता है http://jsfiddle.net/danielzen/utan7//

कोणीय फ़ाइल अपलोड जानकारी

ASP.Net में AngularJS फ़ाइल अपलोड के लिए URL

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

AngularJs NodeJS के साथ प्रगति के साथ मूल बहु-फ़ाइल अपलोड

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

ngUpload - iframe का उपयोग करके फ़ाइलें अपलोड करने के लिए एक AngularJS सेवा

http://ngmodules.org/modules/ngUpload


2
onchange = "angular.element (यह) .scope ()। fileNameChaged (यह)" $ गुंजाइश.fileNameChaged = function (एलिमेंट) {कंसोल.लॉग ('फाइलें:', element.files); } क्या आप दो जगह बदल सकते हैं और चेक कर सकते हैं? ब्राउज़र पर निर्भर करते हुए आपको फ़ाइल पूर्ण पथ मिल जाएगी जिसमें मैंने नीचे दिए गए फ़िडल को अपडेट किया है वह है url अपलोड फ़ाइल और चेक कंसोल jsfiddle.net/utp7j/260
JQuery गुरु

13
यह विधि डिफ़ॉल्ट AngularJS प्रसंस्करण को रोकती है, इसलिए $ गुंजाइश। $ डाइजेस्ट () को नहीं कहा जाता है (बाइंडिंग अपडेट नहीं होती हैं)। 'Angular.element (यह) .scope ()। $ डाइजेस्ट (') को कॉल करें या स्कोप मेथड को कॉल करें जो $ अप्लाई का उपयोग करता है।
रेमन डे क्लेन

113
यह एक भयानक जवाब है। Angular.element (blah) .scope () कॉलिंग एक डीबग सुविधा है जिसका उपयोग आपको केवल डीबगिंग के लिए करना चाहिए। कोणीय .scope सुविधा का उपयोग नहीं करता है। यह केवल डेवलपर्स डिबग की मदद करने के लिए है। जब आप अपना ऐप बनाते हैं और उत्पादन के लिए तैनात करते हैं, तो आप डीबग जानकारी को बंद करने वाले हैं। यह आपके सभी ए लॉट को गति देता है !!! इसलिए, कोड लिखने के लिए जो element.scope () कॉल पर निर्भर करता है एक बुरा विचार है। यह मत करो। एक कस्टम निर्देश बनाने के बारे में जवाब यह करने का सही तरीका है। @JQueryGuru आपको अपना जवाब अपडेट करना चाहिए। क्योंकि इसमें सबसे अधिक वोट हैं, लोग इस बुरी सलाह का पालन करेंगे।
ठंढी

7
डिबग जानकारी अक्षम होने पर यह समाधान ऐप को तोड़ देगा। अक्षम करना कि उत्पादन के लिए एक आधिकारिक सिफारिश है docs.angularjs.org/guide/production । कृपया ब्लॉग
angularjs

4
BAD SOLUTION ... ... ने 'डीबगिंग बंद करना' के बारे में अन्य टिप्पणियां पढ़ीं ... ... और देखें sqren's समाधान ... ... ... @ 0MV1
dsdsdsdsd

477

मैंने फ़ाइल इनपुट परिवर्तनों को सुनने के लिए एक छोटा निर्देश दिया।

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

    }
  };
});

4
यदि हर बार एक अलग फ़ाइल चुनी जाती है तो यह अच्छी तरह से काम करता है। क्या यह संभव है कि जब उसी फ़ाइल को चुना जाए, तो क्या यह सुनना संभव है?
JDawg

12
यह एक बहुत ही दुर्भाग्यपूर्ण "बग" है - नियंत्रक कस्टमऑनचेंज में "इस" के रूप में बाध्य नहीं है, लेकिन फ़ाइल इनपुट! इसने मुझे लंबे समय तक फेंक दिया और मुझे वास्तविक बग नहीं मिला। मुझे अभी तक यकीन नहीं है कि वास्तव में इसे "यह" सही तरीके से कैसे सेट किया जाए।
कारेल बिलेक

4
फ़िडेल मेरे लिए, क्रोम या फ़ायरफ़ॉक्स पर, आज की तरह काम नहीं करता है।
सेगूसो

2
यह उत्तर त्रुटिपूर्ण है जैसा कि @ KarelBílek ने कहा है। मैं इसके आसपास नहीं पहुंच सका और कोणीय-फ़ाइल-अपलोड का उपयोग करने का निर्णय लिया।
गनर गेसनर

2
यह बिल्कुल ऐसा है कि यह कैसे करना है, एक आकर्षण की तरह काम किया। इसके अलावा, आप उत्पादन में डिबग सुविधा का उपयोग क्यों करेंगे?
जस्टिन क्रूस

42

यह आसपास के कुछ अन्य लोगों का परिशोधन है, डेटा एनजी-मॉडल में समाप्त हो जाएगा, जो कि सामान्य रूप से आप चाहते हैं।

मार्कअप (बस एक विशेषता डेटा-फ़ाइल बनाएं ताकि निर्देश इसे मिल सके)

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

जे एस

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
की $scope.$apply();आवश्यकता है? मेरी ng-changeघटना अभी भी इसके बिना आग लगती है।
row1

1
@ row1 आपको केवल एक आग लगाने की ज़रूरत है अगर आपके पास अन्य कोणीय चीजें हैं जो उस ऑपरेशन के दौरान इसके बारे में जानना आवश्यक है।
स्कॉट तलवार

27

साफ तरीका यह है कि "परिवर्तन" घटना के लिए बाध्य करने के लिए अपने स्वयं के निर्देश को लिखें। बस आपको यह बताने के लिए कि IE9 फॉर्मडैट का समर्थन नहीं करता है, ताकि आप वास्तव में परिवर्तन की घटना से फ़ाइल ऑब्जेक्ट प्राप्त न कर सकें।

आप एनजी-फाइल-अपलोड लाइब्रेरी का उपयोग कर सकते हैं जो पहले से ही फाइलएपीआई पॉलीफिल के साथ IE का समर्थन करता है और सर्वर पर फाइल पोस्ट करने को सरल करता है। इसे प्राप्त करने के लिए यह एक निर्देश का उपयोग करता है।

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

जे एस:

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

यह उदाहरण पुराना है। यहां डॉक्स से नया प्राप्त करें
गनर गेसनर

26

मैंने फ़ाइल इनपुट के लिए टू-वे बाइंडिंग जोड़ने के लिए @Stuart Axon के विचार पर विस्तार किया है (यानी मॉडल मान को वापस शून्य पर सेट करके इनपुट को रीसेट करने की अनुमति दें):

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

डेमो


साभार @JLRishe एक नोट, वास्तव में data-ng-click="vm.theFile=''"अच्छी तरह से काम करता है, इसे नियंत्रक विधि में लिखने की आवश्यकता नहीं है
सर्गेई

20

यहां कुछ अन्य अच्छे उत्तरों के समान, मैंने इस समस्या को हल करने के लिए एक निर्देश लिखा था, लेकिन यह कार्यान्वयन अधिक बारीकी से घटनाओं को संलग्न करने के कोणीय तरीके को दर्शाता है।

आप इस तरह निर्देश का उपयोग कर सकते हैं:

एचटीएमएल

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

जैसा कि आप देख सकते हैं, आप अपने ईवेंट हैंडलर में चयनित फ़ाइलों को इंजेक्ट कर सकते हैं, क्योंकि आप किसी भी एनजी इवेंट हैंडलर में $ इवेंट ऑब्जेक्ट इंजेक्ट करेंगे।

जावास्क्रिप्ट

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

इसके साथ कुछ दिनों तक संघर्ष किया जब तक कि मैंने आपके जवाब की कोशिश नहीं की। धन्यवाद!
माइकल ट्रेंकिडा 20

मैं fileChangeअभिव्यक्ति के लिए एक अतिरिक्त पैरामीटर कैसे पारित कर सकता हूं ? मैं एक के अंदर इस निर्देश का उपयोग कर रहा हूं ng-repeatऔर $scopeपारित चर attrHandlerप्रत्येक रिकॉर्ड के लिए समान है। सबसे अच्छा उपाय क्या है?

16

यह निर्देश चयनित फ़ाइलों को भी पास करता है:

/**
 *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, इसका उपयोग कैसे करें:

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

मेरे नियंत्रक में:

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

आपके नियंत्रक में $ गुंजाइश.onFilesSelected कैसा दिखता है?
इंगहैम

यदि कोई फ़ाइल खोली जाती है और जब हम फ़ाइल को Microsoft Edge ब्राउज़र में अपलोड करने का प्रयास करते हैं। कुछ नहीं हो रहा। क्या आप मदद कर सकते हैं?
नवीन कटकम

हां, यह अन्य ब्राउज़रों के साथ ठीक काम कर रहा है। मैं microsoft edge @ingaham में समस्या का सामना कर रहा हूं
नवीन

8

मैं एक निर्देश बनाने की सलाह देता हूं

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

        };
    }]);

यह निर्देश कई बार उपयोग किया जा सकता है, यह अपने स्वयं के दायरे का उपयोग करता है और माता-पिता के दायरे पर निर्भर नहीं करता है। आप हैंडलर फंक्शन के लिए कुछ परम भी दे सकते हैं। हैंडलर फ़ंक्शन को स्कोप ऑब्जेक्ट के साथ बुलाया जाएगा, जो कि इनपुट बदलने पर सक्रिय था। $ हर बार अपने मॉडल को अपडेट लागू करें जब परिवर्तन घटना कहा जाता है


4

सबसे सरल कोणीय jqLite संस्करण।

जे एस:

.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()">

यदि कोई फ़ाइल खोली जाती है और जब हम फ़ाइल को Microsoft Edge ब्राउज़र में अपलोड करने का प्रयास करते हैं। कुछ नहीं हो रहा। क्या आप मदद कर सकते हैं?
नवीन कटकम

2

"फाइल-इनपुट" निर्देशन का वर्किंग डेमो जो 1 के साथ काम करता हैng-change

किसी <input type=file>तत्व को एनजी-चेंज डायरेक्शन का काम करने के लिए , उसे कस्टम निर्देश की आवश्यकता होती है जो एनजी-मॉडल निर्देश के साथ काम करता है ।

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

डेमो

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>


महान लेकिन निर्देश केवल एक बार कहा जाता है! यदि मैं चयनित फ़ाइल को बदलता हूं तो निर्देश को दूसरी बार नहीं कहा जाता है! क्या आपके पास इस व्यवहार के बारे में कोई विचार है?
hugsbrugs

DEMO में वह समस्या नहीं है। पाठकों के परीक्षण के लिए एक प्रतिलिपि प्रस्तुत करने योग्य उदाहरण के साथ एक नया प्रश्न बनाएं ।
georgeawg

हाँ, यह समस्या है कि कंसोल लॉग "इनपुट परिवर्तन" केवल एक बार प्रदर्शित होता है, भले ही आप कई बार चयनित फ़ाइलों को बदल दें!
hugsbrugs

परीक्षण के बाद, यह क्रोमियम पर काम करता है, लेकिन यह नवीनतम फ़ायरफ़ॉक्स संस्करण पर नहीं है ... लानत है ब्राउज़र कॉम्पिटिबिलीटी !!!
hugsbrugs

0

पर पूर्ण समाधान का आधार:

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

इनपुट क्षेत्र को छिपाने और इसे एक छवि के साथ बदलने का एक सरल तरीका, यहां एक समाधान के बाद, जिसे कोणीय पर एक हैक की भी आवश्यकता होती है लेकिन वह काम करता है [ट्रिगरगवेंट अपेक्षित रूप से काम नहीं करता है]

समाधान:

  • इनपुट फ़ील्ड को प्रदर्शन में रखें: कोई भी [इनपुट फ़ील्ड डोम में मौजूद नहीं है लेकिन दिखाई नहीं दे रहा है]
  • एक विधि को सक्रिय करने के लिए nb-click () का उपयोग करने पर छवि के ठीक बाद अपनी छवि रखें

जब छवि पर क्लिक किया जाता है तो इनपुट क्षेत्र पर एक DOM क्रिया 'क्लिक' का अनुकरण करें। 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 (यह) .scope () का उपयोग नहीं कर सकते, यह एक डीबग सुविधा है!
सेसर

0

मैंने इसे इस तरह किया है;

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

फ़ाइल इनपुट परिवर्तनों को सुनने का एक और दिलचस्प तरीका इनपुट फ़ाइल के एनजी-मॉडल विशेषता पर एक घड़ी है। बेशक FileModel एक कस्टम निर्देश है।

ऐशे ही:

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

जेएस कोड ->

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

आशा है कि यह किसी की मदद कर सकता है।


0

कोणीय तत्व (जैसे कि एक निर्देश का मूल तत्व) jQuery [लाइट] ऑब्जेक्ट हैं। इसका मतलब है कि हम इवेंट श्रोता को इस तरह रजिस्टर कर सकते हैं:

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

यह jQuery इवेंट डेलिगेशन है। यहां, श्रोता निर्देश के मूल तत्व से जुड़ा हुआ है। जब घटना को ट्रिगर किया जाता है, तो यह पंजीकृत तत्व तक बुलबुला जाएगा और jQuery यह निर्धारित करेगा कि क्या घटना परिभाषित चयनकर्ता से मेल खाते आंतरिक तत्व पर उत्पन्न हुई है। अगर ऐसा होता है, तो हैंडलर फायर करेगा।

इस विधि के लाभ हैं:

  • हैंडलर उस $ तत्व के लिए बाध्य है जो निर्देश गुंजाइश नष्ट होने पर स्वचालित रूप से साफ हो जाएगा।
  • टेम्पलेट में कोई कोड नहीं
  • भले ही आप ईवेंट हैंडलर को पंजीकृत करते समय टारगेट डेलीगेट (इनपुट) का प्रतिपादन नहीं किया गया हो (जैसे कि उपयोग करते समय ng-ifया ng-switch)

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


-1

आप बस नीचे दिए गए कोड को onchange में जोड़ सकते हैं और यह परिवर्तन का पता लगाएगा। आप फ़ाइल डेटा को हटाने के लिए एक्स क्लिक या कुछ पर एक फ़ंक्शन लिख सकते हैं ..

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

यह बुरा अभ्यास है और न कि कोणीय।
सेबस्टियन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.