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 thehost
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, thehost
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.