How to Call Angular Function from JavaScript

Have you ever come across a problem where you had to call an Angular function from within the JavaScript function? Recently I was integrating a Payment Gateway with Angular and Spring Boot Application. In the Angular client, we need to define a handler function to process the payment response from the payment gateway. Since the handler function is a JavaScript function, we won’t be able to call the Angular function directly.

After some googling, I have found a couple of solutions. Among them, one solution was clean and straight forward which I’m gonna share with the realtime payment gateway integration example in this article.

Create Custom Event

Let’s create a handler function and a custom event called payment.success and set the response data in the detail field. So that, when this function is invoked, the event will be created. Then, the angular function that is attached to this event will be invoked. In this Angular function, we will get the response data from the event.detail field and process it further.

function (response){
		var event = new CustomEvent("payment.success", 
			{
				detail: response,
				bubbles: true,
				cancelable: true
			}
		);	  
		window.dispatchEvent(event);
	}

Call Angular Function On Custom Event

There are 2 approaches to bind an angular function with an event. We can use either HostListener decorator or Host metadata to attach the function to the event.

Using HostListener Decorator (Recommended)

@HostListener is a decorator that declares a DOM event to listen for, and provides a handler method to run when that event occurs.

Syntax

@HostListener(eventName, [args])

payment.component.ts

Let’s create a Payment Component with a function to handle the payment.success event. We are gonna import the HostListener decorator and bind the onPaymentSuccess function with the event using the HostListener decorator.

import { HostListener, Component } from '@angular/core';
import { PaymentService } from '../_services/payment.service';

@Component({
selector: 'app-payment',
templateUrl: './payment.component.html',
styleUrls: ['./payment.component.css']
})
export class PaymentComponent {

	paymentId: string;
	error: string;
  
	constructor(private paymentService: PaymentService) {
	}

	@HostListener('window:payment.success', ['$event']) 
	onPaymentSuccess(event): void {
		this.paymentService.updateOrder(event.detail).subscribe(
		data => {
			this.paymentId = event.detail.razorpay_payment_id;
		}
		,
		err => {
			this.error = err.error.message;
		}
		);
	}
}

Now, whenever the JavaScript function is invoked, an event will be created and the angular function attached to this event will be invoked.

Using host metadata

The host property of the @Directive and @Component decorators is used to bind properties, attributes, and events to that particular class component, using a set of key-value pairs.

Syntax

host: {
    [key: string]: string;
}

For event handling:

  • The key is the DOM event that the directive listens to. To listen to global events, you can add the target to the event name. The target can be window, document, or body.
  • The value is the statement to execute when the event occurs. If the statement evaluates to false, then preventDefault is applied to the DOM event. A handler method can refer to the $event local variable.

payment.component.ts

In this approach, we are gonna use the host property of @Component decorator to bind the onPaymentSuccess method with payment.sucess global window event.

@Component({
selector: 'app-payment',
templateUrl: './payment.component.html',
styleUrls: ['./payment.component.css'],
host: {'(window:payment.success)':'onPaymentSuccess($event)'}
})
export class PaymentComponent {

	paymentId: string;
	error: string;
  
	constructor(private paymentService: PaymentService) {
	}

	onPaymentSuccess(event): void {
		this.paymentService.updateOrder(event.detail).subscribe(
		data => {
			this.paymentId = event.detail.razorpay_payment_id;
		}
		,
		err => {
			this.error = err.error.message;
		}
		);
	}
}

HostListener vs Host Metadata

Here are the main differences extracted from the Angular documentation:

  • The method associated with @HostListener can be modified only in a single place—in the directive’s class. If you use the host metadata property, you must modify both the property/method declaration in the directive’s class and the metadata in the decorator associated with the directive.
  • HostListener needs to be imported in the Component class. Whereas, the host metadata is only one term to remember and doesn’t require extra ES imports.

Conclusion

That’s all folks. In this article, we have learnt on how to call the Angular function from JavaScript.

Thank you for reading.

Leave a Reply