Events
Vendure emits events which can be subscribed to by plugins. These events are published by the EventBus and
likewise the EventBus
is used to subscribe to events.
An event exists for virtually all significant actions which occur in the system, such as:
- When entities (e.g.
Product
,Order
,Customer
) are created, updated or deleted - When a user registers an account
- When a user logs in or out
- When the state of an
Order
,Payment
,Fulfillment
orRefund
changes
A full list of the available events follows.
Event types
AccountRegistrationEvent
AccountVerifiedEvent
AdministratorEvent
AssetChannelEvent
AssetEvent
AttemptedLoginEvent
ChangeChannelEvent
ChannelEvent
CollectionEvent
CollectionModificationEvent
CountryEvent
CouponCodeEvent
CustomerAddressEvent
CustomerEvent
CustomerGroupChangeEvent
CustomerGroupEvent
FacetEvent
FacetValueEvent
FulfillmentEvent
FulfillmentStateTransitionEvent
GlobalSettingsEvent
HistoryEntryEvent
IdentifierChangeEvent
IdentifierChangeRequestEvent
InitializerEvent
LoginEvent
LogoutEvent
OrderEvent
OrderLineEvent
OrderPlacedEvent
OrderStateTransitionEvent
PasswordResetEvent
PasswordResetVerifiedEvent
PaymentMethodEvent
PaymentStateTransitionEvent
ProductChannelEvent
ProductEvent
ProductOptionEvent
ProductOptionGroupChangeEvent
ProductOptionGroupEvent
ProductVariantChannelEvent
ProductVariantEvent
PromotionEvent
ProvinceEvent
RefundStateTransitionEvent
RoleChangeEvent
RoleEvent
SearchEvent
SellerEvent
ShippingMethodEvent
StockMovementEvent
TaxCategoryEvent
TaxRateEvent
TaxRateModificationEvent
ZoneEvent
ZoneMembersEvent
Subscribing to events
To subscribe to an event, use the EventBus
's .ofType()
method. It is typical to set up subscriptions in the onModuleInit()
or onApplicationBootstrap()
lifecycle hooks of a plugin or service (see NestJS Lifecycle events.
Here's an example where we subscribe to the ProductEvent
and use it to trigger a rebuild of a static storefront:
import { Injectable, OnModuleInit } from '@nestjs/common';
import { EventBus, ProductEvent, PluginCommonModule, VendurePlugin } from '@vendure/core';
import { StorefrontBuildService } from './services/storefront-build.service';
@VendurePlugin({
imports: [PluginCommonModule],
})
export class StorefrontBuildPlugin implements OnModuleInit {
constructor(
private eventBus: EventBus,
private storefrontBuildService: StorefrontBuildService) {}
onModuleInit() {
this.eventBus
.ofType(ProductEvent)
.subscribe(event => {
this.storefrontBuildService.triggerBuild();
});
}
}
The EventBus.ofType()
and related EventBus.filter()
methods return an RxJS Observable
.
This means that you can use any of the RxJS operators to transform the stream of events.
For example, to debounce the stream of events, you could do this:
import { debounceTime } from 'rxjs/operators';
// ...
this.eventBus
.ofType(ProductEvent)
.pipe(debounceTime(1000))
.subscribe(event => {
this.storefrontBuildService.triggerBuild();
});
Subscribing to multiple event types
Using the .ofType()
method allows us to subscribe to a single event type. If we want to subscribe to multiple event types, we can use the .filter()
method instead:
import { Injectable, OnModuleInit } from '@nestjs/common';
import { EventBus, PluginCommonModule, VendurePlugin, ProductEvent, ProductVariantEvent } from '@vendure/core';
@VendurePlugin({
imports: [PluginCommonModule],
})
export class MyPluginPlugin implements OnModuleInit {
constructor(private eventBus: EventBus) {}
onModuleInit() {
this.eventBus
.filter(event =>
event instanceof ProductEvent || event instanceof ProductVariantEvent)
.subscribe(event => {
// the event will be a ProductEvent or ProductVariantEvent
});
}
}
Publishing events
You can publish events using the EventBus.publish()
method. This is useful if you want to trigger an event from within a plugin or service.
For example, to publish a ProductEvent
:
import { Injectable } from '@nestjs/common';
import { EventBus, ProductEvent, RequestContext, Product } from '@vendure/core';
@Injectable()
export class MyPluginService {
constructor(private eventBus: EventBus) {}
async doSomethingWithProduct(ctx: RequestContext, product: Product) {
// ... do something
this.eventBus.publish(new ProductEvent(ctx, product, 'updated'));
}
}
Creating custom events
You can create your own custom events by extending the VendureEvent
class. For example, to create a custom event which is triggered when a customer submits a review, you could do this:
import { ID, RequestContext, VendureEvent } from '@vendure/core';
import { ProductReviewInput } from '../types';
/**
* @description
* This event is fired whenever a ProductReview is submitted.
*/
export class ReviewSubmittedEvent extends VendureEvent {
constructor(
public ctx: RequestContext,
public input: ProductReviewInput,
) {
super();
}
}
The event would then be published from your plugin's ProductReviewService
:
import { Injectable } from '@nestjs/common';
import { EventBus, ProductReviewService, RequestContext } from '@vendure/core';
import { ReviewSubmittedEvent } from '../events/review-submitted.event';
import { ProductReviewInput } from '../types';
@Injectable()
export class ProductReviewService {
constructor(private eventBus: EventBus, private productReviewService: ProductReviewService) {}
async submitReview(ctx: RequestContext, input: ProductReviewInput) {
this.eventBus.publish(new ReviewSubmittedEvent(ctx, input));
// handle creation of the new review
// ...
}
}
Entity events
There is a special event class VendureEntityEvent
for events relating to the creation, update or deletion of entities. Let's say you have a custom entity (see defining a database entity) BlogPost
and you want to trigger an event whenever a new BlogPost
is created, updated or deleted:
import { ID, RequestContext, VendureEntityEvent } from '@vendure/core';
import { BlogPost } from '../entities/blog-post.entity';
import { CreateBlogPostInput, UpdateBlogPostInput } from '../types';
type BlogPostInputTypes = CreateBlogPostInput | UpdateBlogPostInput | ID | ID[];
/**
* This event is fired whenever a BlogPost is added, updated
* or deleted.
*/
export class BlogPostEvent extends VendureEntityEvent<BlogPost[], BlogPostInputTypes> {
constructor(
ctx: RequestContext,
entity: BlogPost,
type: 'created' | 'updated' | 'deleted',
input?: BlogPostInputTypes,
) {
super(entity, type, ctx, input);
}
}
Using this event, you can subscribe to all BlogPost
events, and for instance filter for only the created
events:
import { Injectable, OnModuleInit } from '@nestjs/common';
import { EventBus, PluginCommonModule, VendurePlugin } from '@vendure/core';
import { filter } from 'rxjs/operators';
import { BlogPostEvent } from './events/blog-post-event';
@VendurePlugin({
imports: [PluginCommonModule],
// ...
})
export class BlogPlugin implements OnModuleInit {
constructor(private eventBus: EventBus) {}
onModuleInit() {
this.eventBus
.ofType(BlogPostEvent).pipe(
filter(event => event.type === 'created'),
)
.subscribe(event => {
const blogPost = event.entity;
// do something with the newly created BlogPost
});
}
}