Asked  7 Months ago    Answers:  5   Viewed   39 times

I know this is very a general question but I am failing to upload a file in Angular 2. I have tried

1) http://valor-software.com/ng2-file-upload/ and

2) http://ng2-uploader.com/home

...but failed. Has anyone uploaded a file in Angular? What method did you use? How to do so? If any sample code or demo link is provided it will be really appreciated.

 Answers

64

Angular 2 provides good support for uploading files. No third party library is required.

<input type="file" (change)="fileChange($event)" placeholder="Upload file" accept=".pdf,.doc,.docx">
fileChange(event) {
    let fileList: FileList = event.target.files;
    if(fileList.length > 0) {
        let file: File = fileList[0];
        let formData:FormData = new FormData();
        formData.append('uploadFile', file, file.name);
        let headers = new Headers();
        /** In Angular 5, including the header Content-Type can invalidate your request */
        headers.append('Content-Type', 'multipart/form-data');
        headers.append('Accept', 'application/json');
        let options = new RequestOptions({ headers: headers });
        this.http.post(`${this.apiEndPoint}`, formData, options)
            .map(res => res.json())
            .catch(error => Observable.throw(error))
            .subscribe(
                data => console.log('success'),
                error => console.log(error)
            )
    }
}

using @angular/core": "~2.0.0" and @angular/http: "~2.0.0"

Tuesday, June 1, 2021
 
Jauco
answered 7 Months ago
58

You can implement this using the expand operator. What you actually want to do is create a recursive flatmap. That's exactly what the operator expand was created for.

Here is the code snippet of how this works:

let times = true;
// This is a mock method for your http.get call
const httpMock = () => {
  if(times) {
    times = false;
    return Rx.Observable.of({items: ["1", "2", "3"], next: true});
  } else {
    return Rx.Observable.of({items: ["4", "5", "6"], next: false});
  }
}

httpMock()
  .expand(obj => {
    // In your case, the obj will be the response
    // implement your logic here if the 206 http header is found
    if(obj.next) {
      // If you have next values, just call the http.get method again
      // In my example it's the httpMock
      return httpMock();
    } else {
      return Rx.Observable.empty();
    }
  })
  .map(obj => obj.items.flatMap(array => array)) 
  .reduce((acc, x) => acc.concat(x), []);
  .subscribe((val) => console.log(val));

What is does is mock a first http request, that has a 'next' property to true. This matches your 206 header. We then make a second call which has the 'next' property to false.

The result is an array containing the results from both the requests. It's applicable for more requests as well thanks to the expand operator.

Working jsbin example can be found here: http://jsbin.com/wowituluqu/edit?js,console

EDIT: updated to work with an http call that returns an array from arrays and the end result is a single array that contains all the elements form the arrays.

If you wish to have as a result an array with the separate arrays from the request still inside, just remove the flatmap and return the items directly. Update codepen here: http://codepen.io/anon/pen/xRZyaZ?editors=0010#0

Saturday, July 3, 2021
 
makadev
answered 6 Months ago
31

This is what I tried and it worked as expected :

handleCategoryBanner(files: FileList) {
    this.category.category_banner = '/categories/download/' + files[0].name;
    this.formData.append('category_banner', files[0], files[0].name);
    this.categoryContainersService.uploadFile(this.formData).subscribe(filename => console.log(files[0].name));
  }
<div class="col-lg-12 text-center">
        <input type="file" (change)="handleCategoryBanner($event.target.files)" class="custom-file-input" id="category_banner" accept=".jpeg,.png,.jpg">
        <input type="hidden" name="category_banner" [(ngModel)]="category.category_banner" />
        <label class="custom-file-label" for="customFile">Banner</label>
    </div>
Tuesday, August 10, 2021
 
Lawrence Taur
answered 4 Months ago
39

You need to use a directive like below.

uploader.directive("readfile", [function () {
    return {
        scope: {
            readfile: "="
        },
        link: function (scope, element, attributes) {
            element.bind("change", function (changeEvent) {
                var reader = new FileReader();
                reader.onload = function (loadEvent) {
                    scope.$apply(function () {
                        scope.readfile = { "FileName":changeEvent.target.value.split('\').pop() , "Content":loadEvent.target.result , "Size":loadEvent.total };
                    });
                }
                reader.readAsDataURL(changeEvent.target.files[0]);
            });
        }
    }
}]);

For uploading the files:

function MyCTRL($scope, $http, $modal)
{
    $scope.currentFile="";

    $scope.currentFileGroup="";

    $scope.currentFileDescription="";

    $scope.attachedFile=[];

    $scope.fileUpload=function () 

    {

    $scope.attachedFile.push ({

        "fileGUID": GUID() + "." + $scope.currentFile.FileName.split('.').pop(),
        "fileName": $scope.currentFile.FileName,
        "fileGroup": $scope.currentFileGroup,
        "fileDescription": $scope.currentFileDescription,
        "fileSize": $scope.currentFile.Size,
        "fileContent": $scope.currentFile.Content,
        "fileState": "wait"
    });

    $scope.currentFile = "";
    $scope.currentFileGroup = "";
    $scope.currentFileDescription = "";
    $scope.AddBtnShow=false;

    var saveFile = new dataStructure();
    var fileContent = "";
    for (var i=0; i < $scope.attachedFile.length; i++) {
        if($scope.attachedFile[i].fileState!="sent") {
        fileContent = $scope.attachedFile[i].fileContent;
        saveFile.EntityInfo[0].Name = $scope.attachedFile[i].fileGUID;
        saveFile.EntityInfo[0].Type = "CUSTOMFILE";

            saveFile.EntityData = [
                {"Content": fileContent}
            ];
            var inputjsondata = JSON.stringify(saveFile);
            $http({ method: 'POST', url: rootURL + '/data/savefilecontent', data: inputjsondata, dataType: 'text', processData: false, async: false, headers: { 'Content-Type': 'application/json; charset=utf-8' } }).success(function (data) {
            });
            $scope.attachedFile[i].fileState = "sent";

            $scope.formData.Attachments.push({
                "FilenameGUID": $scope.attachedFile[i].fileGUID,
                "Filename": $scope.attachedFile[i].fileName,
                "Group": $scope.attachedFile[i].fileGroup,
                "Description": $scope.attachedFile[i].fileDescription,
                "UploadDate": uploadGregorianDate()                    
            });
        }
    }
};

And now everything is fine.

Friday, September 17, 2021
 
hohner
answered 3 Months ago
76

It appears that you didn't close the controller declaration correctly.

Specifically, you have: }); when you should have }]); instead. Note the missing ].


In context, you should have:

var controllers = angular.module('controllers', ['ngGrid', 'ngDialog', 'angularFileUpload']);

controllers.controller('CustomProductsCtrl', 
 ['$scope', '$window', 'ngDialog', 'CommonService', 
   'CustomProductsServices', '$upload', 
 function ($scope, $window, ngDialog, CommonService, 
   CustomProductsServices, $upload){

}]);  // Note: missing ']' added in here

because we need to follow the form of declaring a controller. The controller API is terse, but pretty succint:

$controller(constructor, locals);

Which expanded to your case:

module_name.controller( 'your_Ctrl', 
    [locals, function(){ 
        } 
    ] 
);

I added in extra spacing to call out the missing ] and to show how we're closing off elements within the declaration.

Thursday, November 11, 2021
 
Claudio
answered 4 Weeks ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share