Issue with handling multiple input files in an *ngFor loop

I am facing difficulties in targeting the correct input within a *ngFor loop. When I include an image with the first input (Certificat dimmatriculation), it displays a placeholder image and a delete button to reset the input, but it appears under both divs.

I specifically want to target only the input where the actual image is added. Despite having ViewChild, I am unable to make it function as intended.

View image here

Here is the code snippet:

<div class="files">
     <div class="single-file" *ngFor="let file of files">
          <h5>{{file.title}}</h5>
          <input type="file" name="file" id="{{file.slug}}" class="inputfile" #fileInput (change)="addFile(fileInput.files[0])" />
          <label for="{{file.slug}}" *ngIf="!hasFile || isDeleted">
          <img class="d-none d-xl-inline-block" src="assets/images/addImg.png" alt="">
          Ajouter votre photo
          <img class="d-block d-xl-none" src="assets/images/addImg_big.png" alt="">
     </label>
     <div class="placeholder" *ngIf="hasFile && !isDeleted">
          <img [src]="imageUrl" />
      </div>
      <div class="deleteImg" *ngIf="hasFile && !isDeleted" (click)="deleteFile()">
          <div class="btn btn-outline"><img src="assets/images/delete-x-icon.png" alt="Supprimer">Supprimer</div>
          </div>
     </div>
</div>

Furthermore, in the .ts file:

I have declared all necessary variables


file: File;
imageUrl: string | ArrayBuffer = '../app/assets/images/imgAdded.png';
hasFile = false;
isDeleted = false;

@ViewChild('fileInput', { static: false }) myFileInput: ElementRef;

files: any = [{
    'title': 'Certificat dimmatriculation',
    'slug': 'immatriculation',
    'input': '#fileInput1'
}, {
    'title': 'Preuve dassurance',
    'slug': 'insurance',
    'input': '#fileInput2'
}];

addFile(file: File) {
    if (file) {
        this.hasFile = !this.hasFile;
        // this.fileName = file.name;
        this.file = file;

        const reader = new FileReader();
        reader.readAsDataURL(file);

        reader.onload = event => {
            this.imageUrl = this.imageUrl;
            // this.imageUrl = reader.result;
        };
    }
}

deleteFile() {
    this.isDeleted = !this.isDeleted;
    this.myFileInput.nativeElement.value = '';
}

Answer №1

Right now, you're facing an issue where you're trying to handle individual file properties using component-level properties. My suggestion would be to utilize file properties for storing uploaded image data instead. This way, all actions can be targeted towards the specific file instances.

To simplify things, I've adjusted your code examples for demonstration purposes and to illustrate the approach I've taken.

In my implementation, I use a property called imageUrl on each file to hold the URL of the uploaded image data. The presence of a value in this property indicates that an image has been uploaded, and it gets cleared when the image is deleted.

component.html

<div *ngFor="let file of files">
  <h5>{{file.title}}</h5>    
  <label *ngIf="!file.imageUrl">
    <input type="file" (change)="addFile(file, $event)" />
    Add your photo
  </label>  
  <ng-container *ngIf="file.imageUrl">
    <img [src]="file.imageUrl" />
    <button (click)="deleteFile(file)">Delete</button>
  </ng-container>
</div>

Now, all operations are carried out on the individual file objects and need to be passed into the event handlers. Alternatively, you could use an array index instead of the object reference.

There might also be some confusion between the file instances and the file uploaded from the input. If feasible, consider renaming your variables files and file to something else, reserving file solely for interactions with the file input.

component.ts

addFile(file, event) {
  const uploaded = event.target.files[0];
  if (!uploaded) {
    return;
  }

  const reader = new FileReader();
  reader.onload = () => {
    file.imageUrl = reader.result;
  };

  reader.readAsDataURL(uploaded);
}

deleteFile(file) {
  file.imageUrl = '';
}

DEMO: https://stackblitz.com/edit/angular-bcgwrq

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

What is the best way to showcase several images using Sweet Alert 2?

In the process of developing my Angular 2 application, I have incorporated sweet alert 2 into certain sections. I am looking to showcase multiple images (a minimum of two) at the same time in the pop-up. Does anyone have any suggestions on how to achieve ...

ESLint encountered an issue while attempting to load the configuration "plugin:@angular-eslint/ng-cli-compat" for extension

After attempting to upgrade my Angular project from version 15 to 16, I am now facing a series of perplexing errors. IntelliJ is displaying the following error at the top: https://i.stack.imgur.com/nCS2M.png Furthermore, when trying to run ng serve, it f ...

Harnessing the power of external Javascript functions within an Angular 2 template

Within the component, I have a template containing 4 div tags. The goal is to use a JavaScript function named changeValue() to update the content of the first div from 1 to Yes!. Since I am new to TypeScript and Angular 2, I am unsure how to establish comm ...

How can I receive user input in JavaScript while incorporating three.js?

I am currently exploring the functionalities of this three.js example () and I am interested in enabling users to input specified X, Y, and Z positions for boxes dynamically. Initially, I considered utilizing a JavaScript prompt like below: var boxes = p ...

Exploring how to iterate through an object to locate a specific value with TypeScript and React

I am looking to hide a button if there is at least one order with status 'ACCEPTED' or 'DONE' in any area or subareas. How can I achieve hiding the "Hide me" menu item when there is at least one area with orders having status 'ACCE ...

Combining marker, circle, and polygon layers within an Angular 5 environment

I am working on a project where I have an array of places that are being displayed in both a table and a map. Each element in the table is represented by a marker, and either a circle or polygon. When an element is selected from the table, the marker icon ...

Angular: Initiate multiple functions simultaneously and combine results afterwards

My current code successfully zips and saves the response of a JSON array by splitting them into individual files using a single method. zip: JSZip = new JSZip(); folder: JSZip = new JSZip(); this.apicall.api1() .subscribe( response => { for (let r ...

Unable to retrieve component name using React.Children

While working with react in the nextjs framework, I attempted to create my own dropdown component structured as follows: <Dropdown> <DropdownToggle>Action</DropdownToggle> <DropdownMenu> <DropdownItem>Menu 1</Dr ...

The implementation of race in React Redux Saga is proving to have negligible impact

I have implemented the following saga effect: function* loginSaga() { const logoutTimeoutCreationDate: string | null = yield localStorage.getItem('logoutTimeoutCreationDate'); let logoutTimeout: number; if (!logoutTimeoutCreationDate || + ...

How to process response in React using Typescript and Axios?

What is the proper way to set the result of a function in a State variable? const [car, setCars] = useState<ICars[]>([]); useEffect(() =>{ const data = fetchCars(params.cartyp); //The return type of this function is: Promise<AxiosRespo ...

Converting a string to Time format using JavaScript

I am working with a time format of 2h 34m 22s which I need to parse as 02:34:22. Currently, I am achieving this using the following code: const splitterArray = '2h 34m 22s'.split(' '); let h = '00', m = '00', s = &a ...

Exploring the parent-child relationship of three components within Angular 2

Currently, I am developing a shopping cart using Angular 2. The application consists of two components - one for categories and another for product listings, both included in the main app component as children. However, I'm facing an issue where these ...

What is the process for cancelling a subscription after logging out? My account is the subject of the subscription

I have a service called authService that contains a login method, which is defined as follows: user = new Subject<User>(); login(username: string, password: string): Observable<User> { return this.http .post<User>('http://localhos ...

Exploring the functionality of multiple checkboxes in Next.js 14, the zod library, shadcn/ui components, and react-hook

I'm currently working on a form for a client where one of the questions requires the user to select checkboxes (or multiple checkboxes). I'm still learning about zod's schema so I'm facing some challenges in implementing this feature. I ...

Angular Error: Unable to process _this.handler.handle as a function

While running my tests in Angular, I encountered an error: TypeError: _this.handler.handle is not a function at MergeMapSubscriber.project (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/common/esm5/http.js:1464:80) at MergeM ...

Angular is a powerful framework that enables the creation of dynamic user interfaces. One of its many

Looking to implement a Material table with expandable rows in Angular. table-tree.html <table mat-table [dataSource]="dataSource" multiTemplateDataRows class="mat-elevation-z8" > <ng-container matColumnDef="{{co ...

Is it necessary to unsubscribe from an Angular HTTP-Request when using switchMap?

I have a question about managing subscriptions in my Angular application. I'm currently using the combineLatest operator to create an observable from two Angular observables, route.params and route.queryParams. This combined observable is then used as ...

Is there any distinction between using glob wildcards in the tsconfig.json file when specifying "include" as "src" versus "include" as "src/**/*"?

Is there a distinction between these two entries in the tsconfig.json file? "include": ["src"] "include": ["src/**/*"] Most examples I've come across use the second version, but upon reviewing my repository, ...

Using the original type's keys to index a mapped type

I am currently developing a function that is responsible for parsing a CSV file and returning an array of objects with specified types. Here is a snippet of the code: type KeyToTransformerLookup<T> = { [K in keyof T as T[K] extends string ? never : ...

Preventing memory leaks in unmounted components: A guide

Currently, I am facing an issue while fetching and inserting data using axios in my useState hook. The fetched data needs to be stored as an array, but unfortunately, I encountered a memory leak error. I have tried various solutions including using clean u ...