Home > other >  Upload images directly from an Angular application to AWS S3
Upload images directly from an Angular application to AWS S3

Time:02-05

I am currently following this tutorial to upload an image directly from my angular application onto an AWS S3 bucket. I made some minor changes to sort out the few errors that came up during my execution, however when I run my code I find that the function I use to select the image ("selectFile()") is not being executed when I click the button.

The code in my appcomponent.ts file is as follows:

export class AppComponent {
  selectedFiles: any = '';  //In the tutorial it was selectedFiles: FileList; But it kept throwing errors.
  imageSrc: string = '';

  constructor(private uploadService: UploadService) { }
  
  ngOnInit() {
  }
  
  upload() {
    const file = this.selectedFiles.item(0);
    this.uploadService.uploadFile(file);
  }
  
  selectFile(event: any) {
    const reader = new FileReader();
    if(event.target.files && event.target.files.length) {
      const [file] = event.target.files;
      console.log(file.name);
      reader.readAsDataURL(file);
      reader.onload = () => {
        this.imageSrc = reader.result as string;
      }
      this.selectedFiles = file;
    }
  }
}

UploadService:

import { Injectable } from '@angular/core';
import * as AWS from 'aws-sdk/global';
import * as S3 from 'aws-sdk/clients/s3';

@Injectable({
  providedIn: 'root'
})
export class UploadService {

  constructor() { }

  uploadFile(file: any) {
    const contentType = file.type;
    const bucket = new S3({
      accessKeyId: '...',
      secretAccessKey: '...',
      region: '...'
    });
    const params = {
      Bucket: '...',
      Key: file.name,
      Body: file,
      ACL: 'public-read',
      ContentType: contentType
    };
    bucket.upload(params, function(err: any, data: any){
      if (err) {
        console.log('There was an error uploading your file: ', err);
        return false;
      }
      console.log('Successfully uploaded file.', data);
      return true;
    });
    //for upload progress   
    /*bucket.upload(params).on('httpUploadProgress', function (evt) {
        console.log(evt.loaded   ' of '   evt.total   ' Bytes');
      }).send(function (err, data) {
      if (err) {
        console.log('There was an error uploading your file: ', err);
        return false;
      }
      console.log('Successfully uploaded file.', data);
      return true;
    });*/
  }
}

And AppComponent.html is below:

<label >
  <img [src]="imageSrc" *ngIf="imageSrc" style="width:100%">
  <input type="file" (change)="selectFile($event)">
</label>

<button  [disabled]="!selectedFiles" (click)="upload()">Upload</button>

Where am I going wrong?

CodePudding user response:

You're taking the first file out of the file list twice:

const [file] = event.target.files; // taking the first file

and then again inside the upload function:

const file = this.selectedFiles.item(0);

Also, it looks like you're mixing this.selectedFiles (which the name and your tutorial imply should be a list of files, and for some reason you're intializing it to an empty string!) and you assign to it type File inside selectFile.

I think it would be better to work with strong types, where I would change the .html and .ts as below:

.html:

<label >
  <img [src]="imageSrc" *ngIf="imageSrc" style="width:100%">
  <input type="file" (change)="selectFile($event.target.files)">
</label>

<button  [disabled]="!selectedFileToUpload" (click)="upload()">Upload</button>

and .ts:

private selectedFileToUpload: File = null;

public upload() {
    if (!this.selectedFileToUpload) {
        alert('Please select a file first!'); // or any other message to the user to choose a file
        return;
    }

    this.uploadService.uploadFile(this.selectedFileToUpload);
}

public selectFile(filesList: FileList) {
    var reader = new FileReader();

    const fileToUpload = filesList.item(0);

    console.log(fileToUpload.name);
    reader.readAsDataURL(fileToUpload);
    reader.onload = () => {
        this.imageSrc = reader.result as string;
    };

    this.selectedFileToUpload = fileToUpload;
}

Note,

however when I run my code I find that the function I use to select the image ("selectFile()") is not being executed when I click the button.

The selectFile function should not be executed when you click the upload button! The selectFile function will be executed every time you change a file in the selected files, and in the example I wrote (not tested) it should save a reference to the file you want to upload. Then, the Upload button would only trigger the upload function that would take the same reference to the selected file and pass it to the upload service to be uploaded by the s3 package.

Again, I didn't test the code, but I tried to help by fixing your logic.

  •  Tags:  
  • Related