AngularJS : 멀티 파트 양식으로 간단한 파일 업로드를 구현하는 방법은 무엇입니까?


144

AngularJS에서 node.js 서버로 간단한 멀티 파트 양식 게시를하고 싶습니다. 양식에는 한 부분에는 JSON 객체가 있고 다른 부분에는 이미지가 있어야합니다 (현재는 $ resource로 JSON 객체 만 게시하고 있습니다)

input type = "file"로 시작해야한다고 생각했지만 AngularJS가 바인딩 할 수 없다는 것을 알았습니다.

내가 찾을 수있는 모든 예제는 드래그 앤 드롭을 위해 jQuery 플러그인을 래핑하는 것입니다. 하나의 파일을 간단하게 업로드하고 싶습니다.

나는 AngularJS를 처음 사용하고 내 지시문을 작성해도 전혀 편안함을 느끼지 않습니다.


1
나는 이것이 도움이 될 것이라고 생각한다 : noypi-linux.blogspot.com/2013/04/…
Noypi Gilas

1
이 답변 참조 : stackoverflow.com/questions/18571001/… 이미 작동중인 시스템에 대한 다양한 옵션이 있습니다.
Anoyz

답변:


188

angularjs 이외의 다른 종속성이없는 실제 작동 솔루션 (v.1.0.6으로 테스트)

html

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

Angularjs (1.0.6) 는 "입력 파일"태그에서 ng-model 을 지원하지 않으므로 사용자가 선택한 모든 파일을 최종적으로 전달하는 "네이티브 웨이"에서 수행해야합니다.

제어 장치

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

};

멋진 부분은 정의되지 않은 컨텐츠 유형과 transformRequest : angular.identity로 $ http에 올바른 "컨텐츠 유형"을 선택하고 멀티 파트 데이터를 처리 할 때 필요한 경계를 관리 할 수있는 기능을 제공합니다.


2
@Fabio이 변환 요청이 무엇을 설명 할 수 있습니까? angular.identity는 무엇입니까? 멀티 파트 파일 업로드를 수행하기 위해 하루 종일 머리를 두드리고있었습니다.
augpt

1
자바 나머지 응용 프로그램에서 @RandomUser, 그런 일 mkyong.com/webservices/jax-rs/file-upload-example-in-jersey
파비오 Bonfante

2
와, 정말 훌륭합니다. 고마워요. 여기에 여러 이미지와 다른 데이터를 업로드해야합니다. 그래서 fd를 다음과 같이 조작합니다fd.append("file", files[0]); fd.append("file",files[1]); fd.append("name", "MyName")
Moshii

1
console.log (fd)는 양식이 비어 있다고 표시합니까? 그런 식입니까?
J Bourne

4
debugInfo가 비활성화 된 경우 (권장대로) 작동하지 않습니다.
Bruno Peres

42

단순 / 경량 ng-file-upload 지시문을 사용할 수 있습니다 . FileAPI 플래시 심으로 HTML5가 아닌 브라우저의 드래그 앤 드롭, 파일 진행 및 파일 업로드를 지원합니다.

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

}];

한 번에 각 파일에 대해 단일 POST 요청을 수행하지 않습니까?
Anoyz

그렇습니다. github 이슈 트래커에는 파일을 하나씩 업로드하는 것이 더 좋은 이유에 대한 토론이 있습니다. Flash API는 파일 전송을 지원하지 않으며 AFAIK Amazon S3도 지원하지 않습니다.
danial December

그래서 당신은 일반적으로 더 정확한 접근 방식이 한 번에 하나의 파일 POST 요청을 보내는 것이라고 말하고 있습니까? 그 점에서 몇 가지 장점을 볼 수 있지만 서버 측에서 편안한 지원을 할 때 더 많은 문제가 발생합니다.
Anoyz

2
내가 구현하는 방법은 각 파일을 리소스 저장으로 업로드하고 서버가 로컬 파일 시스템 (또는 데이터베이스)에 파일을 저장하고 해당 파일의 고유 ID (예 : 임의의 폴더 / 파일 이름 또는 db id)를 반환하는 것입니다. 그런 다음 모든 업로드가 완료되면 클라이언트는이 요청에 대해 업로드 된 파일의 추가 데이터 및 ID가있는 다른 PUT / POST 요청을 보냅니다. 그런 다음 서버는 레코드를 관련 파일과 함께 저장합니다. 파일을 업로드 한 다음 이메일을 보낼 때 Gmail과 같습니다.
danial

1
이것은 "단순 / 경량"이 아닙니다. 샘플 섹션에는 하나의 파일 만 업로드하는 예가 없습니다.
Chris

9

파일을 직접 보내는 것이 더 효율적입니다.

인코딩베이스 64 로는 Content-Type: multipart/form-data추가 33 %의 오버 헤드를 추가한다. 서버가 지원하는 경우 파일을 직접 보내는 것이 더 효율적입니다.

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

File 객체 와 함께 POST를 보낼 때 설정하는 것이 중요합니다 'Content-Type': undefined. XHR의 전송 방법은 다음 감지 File 객체를 자동으로 콘텐츠 형식을 설정합니다.

여러 파일을 보내려면 FileList에서 직접 여러 요청 수행을 참조하십시오.$http.post


input type = "file"로 시작해야한다고 생각했지만 AngularJS가 바인딩 할 수 없다는 것을 알았습니다.

<input type=file>요소는 기본적으로 ng-model 지시문 과 함께 작동하지 않습니다 . 사용자 지정 지시문 이 필요합니다 .

"선택-NG-파일을"지침의 워킹 데모에 맞는지 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 컨텐츠 유형 multipart/form-data

보내야하는 경우 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를 사용하여 POST를 보낼 때 설정하는 것이 중요합니다 'Content-Type': undefined. XHR의 송신 방법은 다음으로 감지 FormData오브젝트를 자동적으로 콘텐츠 타입 헤더 설정 다중 / 폼 데이터적절한 경계 .


filesInput지시어는 각도 1.6.7와 함께 일하게 나타나지 않습니다, 나는에있는 파일을 볼 수 ng-repeat있지만, 동일한 $scope.variable컨트롤러에서 비어? 또한 귀하의 예 file-model중 하나와 하나files-input
Dan

@ Dan 나는 그것을 테스트하고 작동합니다. 코드에 문제가있는 경우 Minimal, Complete, Verifiable 예제를 사용 하여 새로운 질문을해야합니다 . 지시문 이름을로 변경했습니다 select-ng-files. AngularJS 1.7.2로 테스트되었습니다.
georgeawg

5

방금이 문제가있었습니다. 따라서 몇 가지 접근 방식이 있습니다. 첫 번째는 새로운 브라우저가

var formData = new FormData();

지원이 최신 브라우저로 제한되는 방법 에 대한 정보가 포함 된 블로그 링크를 클릭하면 그렇지 않으면이 문제가 완전히 해결됩니다.

그렇지 않으면 대상 속성을 사용하여 양식을 iframe에 게시 할 수 있습니다. 양식을 게시 할 때 표시 속성이 none으로 설정된 대상을 iframe으로 설정해야합니다. 대상은 iframe의 이름입니다. (그냥 알 잖아)

이게 도움이 되길 바란다


AFAIK FormData는 IE에서 작동하지 않습니다. 이미지 파일의 base64 인코딩을 수행하고 JSON으로 보내는 것이 더 좋은 아이디어일까요? 선택한 파일 경로를 얻기 위해 AngularJS를 사용하여 입력 type = "file"에 바인딩하는 방법은 무엇입니까?
Gal Ben-Haim

3

이것이 늦은 항목이라는 것을 알고 있지만 간단한 업로드 지시문을 만들었습니다. 당신은 곧 일할 수 있습니다!

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

Web API를 사용하는 예제를 통해 Github에서 더 간단하게 업로드 할 수 있습니다 .


2
솔직히 말해서 프로젝트 readme에서 코드를 복사하여 붙여 넣기를 제안하는 것은 큰 검은 색 표시가 될 수 있습니다. npm 또는 bower와 같은 일반적인 패키지 관리자와 프로젝트를 통합하십시오.
Stefano Torresi

2

다음 과 같이 $resource리소스의 params 속성에 데이터를 할당하여 업로드 할 수 있습니다 actions.

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

1

방금 AngularJs의 간단한 업 로더에 대한 간단한 지시문 (기존의 내용 중 하나에서)을 작성했습니다.

(정확한 jQuery 업 로더 플러그인은 https://github.com/blueimp/jQuery-File-Upload입니다 )

AngularJ를 사용하는 간단한 업 로더 (CORS 구현)

(서버 측은 PHP 용이지만 노드를 간단하게 변경할 수도 있습니다)


1
당신이 당신의 repo에 문제에 응답 \ 닫는 모든 시간을 제공하지 않는 것이 언급하는 것을 잊지 마세요
올렉 Belousov을

@ OlegTikhonov : 예, 다른 프로젝트를 심각하게 고수했습니다. 집중할 수 없습니다.
sk8terboi87 ツ
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.