What is the best way to obtain the dimensions of an image in Angular 2 (or newer) before uploading it to the server, and can this be accomplished without utilizing jQuery?

After searching through multiple resources, I realized that most of the solutions are written in jQuery. However, I am specifically looking for a solution in Typescript.

The HTML code snippet is as follows:

<input #coverFilesInput class="file-input" type="file"(change)="onChange($event)"....>

For Typescript, here is the code snippet provided:

onChange($event) { let img = event.target.files[0]; // and then I need code to validate image size }

My question is whether there exists a solution in Typescript for this issue or if I am approaching it incorrectly?

Answer №1

To access the file upload control and clear its value after each upload, you can utilize a combination of @ViewChild and ElementRef. This ensures that the (change) event triggers appropriately.

Additionally, you can employ FileReader() to read the file into an Image object and extract its width and height.

Below is the code snippet for achieving this:

HTML template

<input type="file" #coverFilesInput (change)="onChange($event)" class="file-input"  />
    Upload Percent: {{percentDone}}% <br />

    <ng-container *ngIf="uploadSuccess">
      Upload Successful of file with size : {{size}} bytes <br>
      The image height is : {{height}} <br>
      The image width is : {{width}} <br>
    </ng-container> 

The onChange method

onChange(evt:any){
   this.percentDone = 100;
   this.uploadSuccess = true;
   let image:any = evt.target.files[0];
   this.size = image.size;
   let fr = new FileReader();
   fr.onload = () => { // when file has loaded
    var img = new Image();
    img.onload = () => {
        this.width = img.width;
        this.height = img.height;
    };

    img.src = fr.result; // The data URL 
};

  fr.readAsDataURL(image);
   this.imgType.nativeElement.value = ""; // clear the value after upload
  }

complete code app.component.ts

import { Component, VERSION ,ViewChild,ElementRef} from '@angular/core';
import {HttpClientModule, HttpClient, HttpRequest, HttpResponse, HttpEventType} from '@angular/common/http';

@Component({
  selector: 'my-app',
  template: `
    Version = {{version.full}} <br/>
    <input type="file" #coverFilesInput (change)="onChange($event)" class="file-input"  />
    Upload Percent: {{percentDone}}% <br />

    <ng-container *ngIf="uploadSuccess">
      Upload Successful of file with size : {{size}} bytes <br>
      The image height is : {{height}} <br>
      The image width is : {{width}} <br>
    </ng-container> 
  `,
})
export class AppComponent {
  percentDone: number;
  uploadSuccess: boolean;
  size:any;
  width:number;
  height:number;

  @ViewChild('coverFilesInput') imgType:ElementRef;

  constructor(
    ) { }

  version = VERSION

  onChange(evt:any){
   this.percentDone = 100;
   this.uploadSuccess = true;
   let image:any = evt.target.files[0];
   this.size = image.size;
   let fr = new FileReader();
   fr.onload = () => { // when file has loaded
    var img = new Image();

    img.onload = () => {
        this.width = img.width;
        this.height = img.height;
    };

    img.src = fr.result; // This is the data URL 
   };

  fr.readAsDataURL(image);
   this.imgType.nativeElement.value = "";
  }  
}

Here is a working demo : https://stackblitz.com/edit/angular-file-upload-hnik7q

Edit : Another approach is to use [(ngModel)]="selectedFile" to manage the input file control's value without the need for @ViewChild and ElementRef. Here's how it can be implemented:

<input type="file" #coverFilesInput (change)="onChange($event)" class="file-input"  [(ngModel)]="selectedFile"/>

and in component class -

export class AppComponent {
  percentDone: number;
  uploadSuccess: boolean;
  size:any;
  width:number;
  height:number;
  selectedFile:any; // declare the property

  constructor(
    ) { }

  version = VERSION

  onChange(evt:any){
   this.percentDone = 100;
   this.uploadSuccess = true;
   let image:any = evt.target.files[0];
   this.size = image.size;
   let fr = new FileReader();
   fr.onload = () => { // when file has loaded
    var img = new Image();    
    img.onload = () => {
        this.width = img.width;
        this.height = img.height;
    };    
    img.src = fr.result; // This is the data URL 
};    
  fr.readAsDataURL(image);
  this.selectedFile = ""; // clear the file here
  }        
}

Answer №2

Give this method a try, it did the trick for me!

// Here's how you can implement it:
<input type="file" class="form-control"
            accept="image/*" 
            (change)="onChange($event)">    

// And in your TypeScript file:
onChange(fileInput: any) {
    const URL = window.URL || window.webkitURL;
    const Img = new Image();

    const filesToUpload = (fileInput.target.files);
    Img.src = URL.createObjectURL(filesToUpload[0]);

    Img.onload = (e: any) => {
      const height = e.path[0].height;
      const width = e.path[0].width;

      console.log(height,width);
  }
}

Answer №3

Utilize the ElementRef to access DOM elements.

Start by assigning an identifier to your DOM element #myImage

Then, in your component class, use ViewChild to target the specified DOM element

ViewChild('myImage')
  myImage: ElementRef;

After the view is initialized, you can retrieve details about the image

ngAfterViewInit() {
    console.log(this.myImage.nativeElement.offsetWidth);
console.log(this.myImage.nativeElement.offsetHeight);
  }

Since you are only retrieving information about the DOM element, the security risk is minimal. It is recommended not to make modifications to DOM elements using this approach.

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

I have implemented the ag grid date filter, but I am having trouble getting the apply and reset buttons to work properly within the filter

Currently, I am facing an issue with the ag grid date filter implementation. I am attempting to add both apply and reset buttons to the filter, but the code I have used does not seem to be functioning correctly. Here is the column definition code snippet ...

Utilizing JSON data within a separate TypeScript function or within the ngOnInit lifecycle hook after successfully retrieving the data

I'm new to Angular and have a simple question. In my code, I have the following: public jsonDataResult: any; private getUrl = "../assets/data_3.json"; getScoreList(){ this.http.get(this.getUrl).subscribe((res) => { this.jsonDat ...

Strategies for extracting information from the database

I have a pre-existing database that I'm trying to retrieve data from. However, whenever I run a test query, it always returns an empty value: { "users": [] } What could be causing this issue? entity: import {Entity, PrimaryGeneratedColumn, Col ...

Using a template reference variable as an @Input property for another component

Version 5.0.1 of Angular In one of my components I have the following template: <div #content>some content</div> <some-component [content]="content"></some-component> I am trying to pass the reference of the #content variable to ...

Issue with rendering React Toastify

I'm running into an issue while trying to integrate react toastify into my react vite application. Specifically, I keep getting an error related to useSyncExternalStore even after attempting to switch to version 9 of react toastify. My React version i ...

When defining a GraphQL Object type in NestJS, an error was encountered: "The schema must have unique type names, but there are multiple types named 'Address'."

Utilizing Nestjs and GraphQL for backend development, encountered an error when defining a model class (code first): Schema must contain uniquely named types but contains multiple types named "Address". Below is the Reader model file example: @ObjectType() ...

Extending Mongoose's capabilities with header files for the "plugin" feature, utilizing the .methods and .statics methods

My task is to develop Typescript header files for a script that enhances my Mongoose model using the .plugin method. The current signature in the Mongoose header files looks like this: export class Schema { // ... plugin(plugin: (schema: Schema, opt ...

Patience required for Angular to retrieve data from API call

I am currently struggling with getting my Donut chart to load properly with data returned from three separate API calls. I have initialized the chart and the API call functions in ngOninit(). However, it seems like my chart is not loading. I understand tha ...

Exploring the capabilities of Vue combined with Typescript and Audio Worklets

I've encountered a challenge with configuring Vue to compile audio worklets. Specifically, I am facing a similar issue to this problem that has already been resolved, but using Typescript instead of JavaScript. My approach was to include the ts-loader ...

Retrieve Json data from an external API in Angular by utilizing the HttpClient module

Being a novice in angular, I am experimenting with fetching data from an external API. Although I managed to retrieve the data successfully on the console, I encountered errors when attempting to display it on the screen. Below are the details of my setup: ...

You can't observe the behavior of simulated functions in a class with a manually created mock

Kindly note that I have set up a comprehensive Github repository where you can download and explore the content yourself here I am currently working on mocking a non-default exported class within a module using a manual mock placed in the folder __mocks__ ...

Apologies, but your payment request was not successful. Please try using an alternative payment method or reach out to us for assistance. Find out more information about error code [OR

While trying to test Google Pay using a fake card, I encountered an error message stating: Your request failed. Use a different payment method, or contact us. Learn more [OR-CCSEH-21]. Below is the Angular code snippet that I am working with: paymentReques ...

Issue with Vue 3 / Typescript: Unable to locate variable name in template

When working with Vue 3 and Typescript, I encountered an error that says "Cannot find name" when trying to reference a data variable in a certain area. How can I resolve this issue? Attached is a screenshot for reference: . Thank you in advance. ...

Securing your Angular 5 source code

We are in the process of developing a cutting-edge product using Angular 5 and Node.js. This new product will be implemented directly at the customer's local environment. However, one major concern we have is how to safeguard our code from potential ...

Tips for converting necessary constructor choices into discretionary ones after they have been designated by the MyClass.defaults(options) method

If I create a class called Base with a constructor that needs one object argument containing at least a version key, the Base class should also include a static method called .defaults() which can set defaults for any options on the new constructor it retu ...

Presentation of information with loading and error scenarios

How can we effectively display data in an Angular view, considering loading state and error handling? Imagine we are fetching a set of documents from our backend and need to present them in an Angular view. We want to address three possible scenarios by p ...

Struggling to grasp how to implement Redux and React-router together in one component

I have recently embarked on learning TypeScript and encountered a confusing behavior. Upon encountering this error: Type 'ComponentClass<{}>' is not assignable to type 'StatelessComponent<void | RouteComponentProps<any>> ...

Leverage local JSON file data in HTML using TypeScript and Angular 7 for enhanced functionality

I am looking to incorporate a basic local JSON file into my Angular 7 project and utilize the data within my HTML file. Just a straightforward example. The JSON file is named data.json. I aim to retrieve the information from this JSON file in app.component ...

"Learn the steps to seamlessly add text at the current cursor position with the angular-editor tool

How can I display the selected value from a dropdown in a text box at the current cursor position? I am currently using the following code: enter code selectChangeHandler(event: any) { this.selectedID = event.target.value; // console.log("this.selecte ...

Attempting a second filter of the table using the dropdown results in no data being returned

I've developed a CRUD app using Angular 7, and I'm facing an issue. When I select a dropdown item for the first time, it shows the desired table data. However, on selecting another item for the second time, it returns nothing. Below is my compone ...