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 () 가 호출하지 않습니다. Firebug에도 오류가 표시되지 않습니다.


1
도움이 될 수 있습니다 : stackoverflow.com/q/17063000/983992
Marcel Gwerder

답변:


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

각도 파일 업로드 정보

ASP.Net에서 AngularJS 파일 업로드 URL

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

NodeJS로 진행되는 AngularJs 기본 다중 파일 업로드

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 (this) .scope (). fileNameChaged (this)"$ scope.fileNameChaged = function (element) {console.log ( 'files :', element.files); } 두 곳에서 변경하고 확인할 수 있습니까? 브라우저에 따라 당신은 URL을 업로드 파일 체크 콘솔 내가 아래 바이올린을 업데이트가 파일의 전체 경로입니다 얻을 것이다 jsfiddle.net/utp7j/260
JQuery와 전문가

13
이 메소드는 기본 AngularJS 처리를 우회하므로 $ scope. $ digest ()가 호출되지 않습니다 (바인딩이 업데이트되지 않음). 나중에 'angular.element (this) .scope (). $ digest ()'를 호출하거나 $ apply를 사용하는 범위 메소드를 호출하십시오.
Ramon de Klein

113
이것은 끔찍한 대답입니다. angular.element (blah) .scope () 호출은 디버깅에만 사용해야하는 디버그 기능입니다. Angular는 .scope 기능을 사용하지 않습니다. 개발자가 디버그하는 데 도움이됩니다. 앱을 빌드하고 프로덕션에 배포 할 때 디버그 정보를 꺼야합니다. 이것은 당신의 모든 많은 속도를 높입니다! 따라서 element.scope () 호출에 의존하는 코드를 작성하는 것은 나쁜 생각입니다. 이러지 마 사용자 지정 지시문을 만드는 방법은 올바른 방법입니다. @ JQueryGuru 당신은 당신의 답변을 업데이트해야합니다. 투표가 많기 때문에 사람들은이 나쁜 조언을 따를 것입니다.
frosty

7
이 솔루션은 디버그 정보가 비활성화되면 앱을 중단합니다. 생산을 위해 그것을 사용하지 않으면 공식 추천입니다 docs.angularjs.org/guide/production . 또한 blog.thoughtram.io/angularjs/2014/12/22/…
wiherek

4
나쁜 해결책 ... ... '디버깅 끄기'에 대한 다른 의견을 읽으십시오 ... ... ... 그리고 sqren솔루션을 참조하십시오 ... ... ... @ 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
이것은 매우 불행한 "버그"를 가지고 있습니다-컨트롤러는 customOnChange에서 "this"로 묶이지 않지만 파일 입력입니다! 그것은 오랫동안 나를 버렸고 실제 버그를 찾을 수 없었습니다. 실제로 "this"를 올바르게 설정하여 호출하는 방법을 아직 확실하지 않습니다.
Karel Bílek

4
오늘날 바이올린은 Chrome 또는 Firefox에서 작동하지 않습니다.
seguso

2
이 답변은 @ KarelBílek의 설명에 결함이 있습니다. 나는 그것을 해결할 수 없었고 앵귤러 파일 업로드를 사용하기로 결정했다.
Gunar Gessner

2
이것은 절대적으로 그것을하는 방법이며, 매력처럼 작동했습니다. 게다가 왜 프로덕션 환경에서 디버그 기능을 사용 하시겠습니까?
저스틴 크루스

42

이것은 주변의 다른 것들을 개선 한 것입니다. 데이터는 일반적으로 원하는 ng-model로 끝납니다.

마크 업 (지시문이 찾을 수 있도록 속성 데이터 파일 만 작성)

<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
인가 $scope.$apply();가 필요? 내 ng-change이벤트는 여전히 그것없이 시작되는 것 같습니다.
ROW1

1
@ row1 해당 작업 중에 알아야 할 다른 각도가있는 경우에만 수동으로 적용을 실행하면 됩니다.
Scott Sword

27

깨끗한 방법은 "change"이벤트에 바인딩하기위한 고유 한 지시문을 작성하는 것입니다. IE9가 FormData를 지원하지 않으므로 change 이벤트에서 파일 객체를 실제로 가져올 수 없다는 것을 알려줍니다.

이미 FileAPI polyfill을 사용하여 IE를 지원 하는 ng-file-upload 라이브러리를 사용하여 파일을 서버에 게시하는 것을 단순화 할 수 있습니다. 이를 위해 지시문을 사용합니다.

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

이 예는 구식입니다. 문서 에서 새 문서를 받으십시오 .
Gunar Gessner

26

@Stuart Axon의 아이디어를 확장하여 파일 입력에 양방향 바인딩을 추가했습니다 (즉, 모델 값을 다시 null로 재설정하여 입력을 재설정 할 수 있음).

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=''"잘 작동하며 컨트롤러 메서드에 쓸 필요가 없다는 것입니다.
Sergey

20

여기에있는 다른 좋은 답변과 마찬가지로이 문제를 해결하기위한 지시문을 작성했지만이 구현은 이벤트를 첨부하는 각도 방식과 더 유사합니다.

다음과 같이 지시문을 사용할 수 있습니다.

HTML

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

보다시피, $ event 객체를 ng 이벤트 핸들러에 주입하는 것처럼 이벤트 핸들러에 선택된 파일을 삽입 할 수 있습니다.

자바 스크립트

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

내가 당신의 대답을 시도 할 때까지 이것으로 며칠 동안 고생했습니다. 감사!
Michael Tranchida

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

컨트롤러에서 $ scope.onFilesSelected는 어떻게 생겼습니까?
ingaham

파일이 열려 있고 Microsoft Edge 브라우저에서 파일을 업로드하려고 할 때. 아무 일도 일어나지 않습니다. 도울 수 있니?
Naveen Katakam

예, 다른 브라우저와 잘 작동합니다. 나는 마이크로 소프트 에지 @ingaham에서 문제에 직면하고있다
나빈 Katakam을

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

        };
    }]);

이 지시문은 여러 번 사용할 수 있으며 자체 범위를 사용하며 상위 범위에 의존하지 않습니다. 핸들러 함수에 몇 가지 매개 변수를 부여 할 수도 있습니다. 핸들러 함수는 입력을 변경했을 때 활성화 된 범위 객체와 함께 호출됩니다. 변경 이벤트가 호출 될 때마다 $ apply가 모델을 업데이트합니다.


4

가장 간단한 Angular jqLite 버전.

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

파일이 열려 있고 Microsoft Edge 브라우저에서 파일을 업로드하려고 할 때. 아무 일도 일어나지 않습니다. 도울 수 있니?
Naveen Katakam

2

1 과 함께 작동하는 "파일 입력"지시문의 실무 데모ng-change

하려면 <input type=file>요소 작업에게 NG 변화 지시자를, 그것은 필요로 정의 지시어를 그와 작품 NG 모델 지시어.

<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

데모에는 그런 문제가 없습니다. 독자가 조사 할 수 있는 재현 가능한 예 를 사용하여 새 질문을 작성하십시오 .
georgeawg

예. 선택한 파일을 여러 번 변경하더라도 콘솔 로그 "입력 변경"이 한 번만 표시됩니다!
hugsbrugs

테스트 후 크롬에서 작동하지만 최신 파이어 폭스 버전에서는 작동하지 않습니다 ... 빌어 먹을 브라우저 호환성 !!!
포옹

0

다음에 대한 완벽한 솔루션 기반 :

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

입력 필드를 숨기고 여기에서 솔루션 후 이미지로 대체하는 간단한 방법으로 각도에 대한 해킹이 필요하지만 작업을 수행하는 [TriggerEvent가 예상대로 작동하지 않음]

해결책:

  • 입력 필드를 display : none에 입력하십시오. [입력 필드는 DOM에 존재하지만 보이지 않습니다]
  • 이미지 바로 다음에 이미지를 배치하십시오. 이미지에서 nb-click ()을 사용하여 메소드를 활성화하십시오.

이미지를 클릭하면 입력 필드에서 DOM 조치 '클릭'을 시뮬레이션하십시오. vo!

 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 ()를 사용할 수 없습니다. 이것은 디버그 기능입니다!
Cesar

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

파일 입력 변경 사항을 수신하는 또 다른 흥미로운 방법은 입력 파일의 ng-model 속성을 감시하는 것입니다. 물론 FileModel은 사용자 지정 지시문입니다.

이처럼 :

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

JS 코드->

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

그것이 누군가를 도울 수 있기를 바랍니다.


0

각도 요소 (예 : 지시문의 루트 요소)는 jQuery [Lite] 객체입니다. 이는 다음과 같이 이벤트 리스너를 등록 할 수 있음을 의미합니다.

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에 아래 코드를 추가하면 변경 사항을 감지합니다. X 클릭 또는 파일 데이터를 제거하는 기능을 작성할 수 있습니다.

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

이것은 나쁜 습관이며 각이 아닙니다.
Sebastian
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.