Creating a File Upload Service in Angular: A Step-By-Step Guide

When utilizing a service to upload images, I am encountering difficulty in retrieving the url value that is set after the render.onload event.

// custom image upload service
export class ImageUploadService {

  constructor(private notificationService: NotificationService) {}

  uploadImage(event: Event) {
      const file = (event.target as HTMLInputElement).files[0];

      if (file.type === 'image/png' || file.type === 'image/jpeg' || file.type === 'image/jpg') {
          const reader = new FileReader();
          let url;
          reader.onload = () => {
              url = reader.result;
          };
          reader.onerror = (error: any) => {
              this.notificationService.error(`Error loading image: ${error}`);
              return;
          };
          reader.readAsDataURL(file);
          return { File: file, Url: url };
      } else {
          this.notificationService.error('Invalid format. Only images in Png, Jpeg, and Jpg formats are allowed.');
          return;
      }
  }
}

// component using the image upload service
uploadBanner(event: Event) {
  const upload = this.imageUploadService.uploadImage(event);
  if (upload) {
    this.bannerUrl = upload.Url;
    this.shop.banner = upload.File;
  }
}

What is the best way to retrieve the values for url and file?

Answer №1

It seems like you are approaching this as a synchronous operation, when in reality it is not. To handle this issue properly, consider utilizing either Promise or Observable and make sure to return the data once your onload event triggers.

export class UploadService {

  constructor(private alertService: AlertService) {}

  uploadPhoto(event: Event): Promise<{file: any, url: string}> { {
    return new Promise((resolve, reject) => {
      const file = (event.target as HTMLInputElement).files[0];

      if (file.type === 'image/png' || file.type === 'image/jpeg' || file.type === 'image/jpg') {
        const reader = new FileReader();
        let url;
        reader.onload = () => {
          resolve({file, url: reader.result})
        };
        reader.onerror = (error: any) => {
          this.alertService.error(`Error loading image: ${error}`);
          reject(error)
        };
        reader.readAsDataURL(file);
      } else {
        let error = 'Invalid format. Only images of type Png, Jpeg, and Jpg are allowed.'
        this.alertService.error(error);
        reject(error);
      }
    }
  }
}

Component

// component
uploadBanner = async (event: Event) => {
  const url = await this.uploadService.uploadPhoto(event);
  console.log(url)
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using Observables for Polling in Angular 8

Greetings, I am in the process of upgrading my project from Angular 5 to Angular 8. Below is the code snippet I used for polling: Observable.interval(this.intervalTime).timeout(600000) .takeWhile(() => this.alive) .subs ...

Issue NG8002: Unable to link to 'FormGroup' as it is not recognized as a property of 'form' in Angular 9

I recently created a brand new Angular 9 application with a submodule. Here are my app.modules.ts: import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from & ...

Mistakes in Compiling Typescript Code in Angular 2

Currently, I am utilizing Visual Studio 2017 for the development of an Angular 2 application with an Asp.Net Core WebApi backend. My guide through this process is the ASP.NET Core and Angular 2 Book authored by Valerio De Sanctis. Initially, everything was ...

Is there a way to manage the rendering of a child component when using the .map() method?

I have a task that involves adding animation to the first element of an array. Currently, when data updates, my parent and child components both rerender, causing the animation to play multiple times on all elements in the array added to the child simultan ...

Angular 14: Removing elements from FormArray causes the remaining elements to lose their values

My form includes custom inputs and utilizes the ControlValueAccessor. To view the implementation, visit this link. I encountered an issue where deleting an item from a FormArray would inadvertently clear the values of the other FormGroups still present in ...

How can you dynamically disable a radio option button using Angular rendering without relying on an ID?

Is there a way to disable the male radio button without using an id, and utilizing angular rendering2? It seems like it's not working for me. I need to make this change only in the form.ts file, without altering the HTML code. form.html <label& ...

Transition from using Observable to BehaviorSubject

I have an observable with a condition attached to it: let data$: Observable<DataModel[]>; this.httpClient.get<DataModel[]>>(`data`) .pipe(map((result: DataModel[]>) => this.data$ = result)); let result: boolean = this.data$.pipe( ...

Preventing JavaScript Compilation for a Specific Folder using tsconfig: A Step-by-Step Guide

To create my own npx package, I'm currently working on converting my .ts files into .js. The purpose of the application is to generate TypeScript templates for users based on their selected options. In this app, there's a CLI called 'index.t ...

I am encountering an issue with Wedriver.IO where screenshots of executions on a Remote Selenium Grid Hub are not being included in my Allure Reports

wdio.conf.ci.js: The following code snippet has been added. afterTest: function(test, context, { error, result, duration, passed, retries }) { if (passed){ browser.takeScreenshot(); } }, I expect to see a screenshot attachment in the bottom right corn ...

Encountering TypeScript error in the beforeRouteUpdate hook with Vue and vue-property-decorator

I am developing an application using Vue 2 with TypeScript and vue-property-decorator. Within my component, I am utilizing the beforeRouteEnter/beforeRouteUpdate hooks. One of the methods in my component is findProjects, which I want to call within the bef ...

Angular is having trouble with disabled dates on the HTML5 Datepicker

I am encountering an issue with disabling past dates in a date-picker using HTML5. When I use the date-picker without any specific conditions, the disabled dates work as expected. However, when I try to use the date-picker with conditions, it does not fun ...

Creating a typescript type for contextual dispatch by leveraging the values of another interface

I am seeking to define a specific type for my "reducer" function. The "reducer" function I have takes in 2 parameters: the current state and the data sent in the dispatch context (to be used by the reducer). const reducer = ( state: any, props: { ...

Steps for setting up a project to compile for ES6 syntax:

Working on a project using Angular 2 + PrimeNG, I encountered an issue with TypeScript compilation while trying to use Git. The solution involved adjusting the package.json file. "dependencies": { "@angular/common": "2.4.2", // List of dependencies goes ...

Tips for handling dropdowns within a formarray in Angular

https://i.stack.imgur.com/f7V4H.pngI'm currently attempting to dynamically select a dropdown value, but the issue I'm encountering is that when I select a value in the dropdown, I get an object out of it. From this object, I am trying to set the ...

Angular 5: experiencing issues with HttpClient when using REST API

Currently, I am in the process of developing a REST API using Spring to perform CRUD operations based on a tutorial I found. However, I have encountered an issue with the HTTP client not retrieving data, and upon inspection, I discovered the following erro ...

Typescript error: Import statement not allowed here

Recently delving into the world of TypeScript, I encountered an issue when attempting to build for production. My first step was running tsc Although this step passed without any errors, I faced import errors when trying to execute the build file with ...

Error encountered with TypeScript when utilizing conditional types in React components

Having trouble with TypeScript error when working with conditional types in React components. The issue arises when attempting to render different component types based on a type prop and providing corresponding props for each type. type PairingCardProps ...

Remove the array stored in the local storage of an Ionic 2 application

In my application, I store data in a string. To convert the data into arrays, I use JSON.parse. this.items = JSON.parse(todos); On the results page, I display my arrays as follows: Array1 Array2 Array3 However, I have noticed that the delete button aft ...

"Unfortunately, this container did not send out any hits" - Google Tag Manager

After successfully integrating Google Tag Manager into my Next.js website, here is the implemented code: import '../styles/global.css'; import type { AppProps } from 'next/app'; import Script from 'next/script'; import NextNP ...

A guide on converting nested arrays of objects in JavaScript

I am faced with transforming an array of Objects that contain a nested structure. Here is an example of the data: [ { geography: 'Austia', product: 'RTD Coffee', dataType: 'Off-Trade rsp (curr/con, lo ...