NestboltNestbolt

@nestbolt/taggable

Events

Listen to tag lifecycle events via @nestjs/event-emitter.

Overview

When @nestjs/event-emitter is installed, @nestbolt/taggable emits events for tag creation, deletion, attachment, and detachment. This lets you react to tag changes across your application.

If @nestjs/event-emitter is not installed, the package works normally but no events are emitted.

Setup

Install and register the event emitter:

npm install @nestjs/event-emitter
import { EventEmitterModule } from "@nestjs/event-emitter";

@Module({
  imports: [
    EventEmitterModule.forRoot(),
    TaggableModule.forRoot(),
  ],
})
export class AppModule {}

Events

EventConstantPayloadWhen
tag.createdTAGGABLE_EVENTS.TAG_CREATEDTagCreatedEventAfter a tag is created
tag.deletedTAGGABLE_EVENTS.TAG_DELETEDTagDeletedEventAfter a tag is deleted
tag.attachedTAGGABLE_EVENTS.TAG_ATTACHEDTagAttachedEventAfter a tag is attached to an entity
tag.detachedTAGGABLE_EVENTS.TAG_DETACHEDTagDetachedEventAfter a tag is detached from an entity

Event Payloads

TagCreatedEvent

interface TagCreatedEvent {
  tag: TagEntity;
}

TagDeletedEvent

interface TagDeletedEvent {
  tagId: string;
  tagName: string;
}

TagAttachedEvent

interface TagAttachedEvent {
  tag: TagEntity;
  taggableType: string;
  taggableId: string;
}

TagDetachedEvent

interface TagDetachedEvent {
  tagId: string;
  taggableType: string;
  taggableId: string;
}

Listening to Events

Use the @OnEvent() decorator from @nestjs/event-emitter:

import { Injectable } from "@nestjs/common";
import { OnEvent } from "@nestjs/event-emitter";
import {
  TAGGABLE_EVENTS,
  TagCreatedEvent,
  TagAttachedEvent,
  TagDeletedEvent,
  TagDetachedEvent,
} from "@nestbolt/taggable";

@Injectable()
export class TagEventListener {
  @OnEvent(TAGGABLE_EVENTS.TAG_CREATED)
  handleTagCreated(event: TagCreatedEvent) {
    console.log(`New tag created: ${event.tag.name}`);
  }

  @OnEvent(TAGGABLE_EVENTS.TAG_ATTACHED)
  handleTagAttached(event: TagAttachedEvent) {
    console.log(
      `Tag "${event.tag.name}" attached to ${event.taggableType}#${event.taggableId}`,
    );
  }

  @OnEvent(TAGGABLE_EVENTS.TAG_DETACHED)
  handleTagDetached(event: TagDetachedEvent) {
    console.log(
      `Tag ${event.tagId} detached from ${event.taggableType}#${event.taggableId}`,
    );
  }

  @OnEvent(TAGGABLE_EVENTS.TAG_DELETED)
  handleTagDeleted(event: TagDeletedEvent) {
    console.log(`Tag deleted: ${event.tagName} (${event.tagId})`);
  }
}

Remember to register your listener as a provider in a module:

@Module({
  providers: [TagEventListener],
})
export class AppModule {}

Example: Invalidate Cache on Tag Change

@Injectable()
export class TagCacheInvalidator {
  constructor(private readonly cacheManager: Cache) {}

  @OnEvent(TAGGABLE_EVENTS.TAG_ATTACHED)
  @OnEvent(TAGGABLE_EVENTS.TAG_DETACHED)
  async invalidateEntityCache(event: TagAttachedEvent | TagDetachedEvent) {
    const cacheKey = `${event.taggableType}:${event.taggableId}:tags`;
    await this.cacheManager.del(cacheKey);
  }
}

Event Constants

All event names are available as constants to avoid typos:

import { TAGGABLE_EVENTS } from "@nestbolt/taggable";

TAGGABLE_EVENTS.TAG_CREATED;   // "tag.created"
TAGGABLE_EVENTS.TAG_DELETED;   // "tag.deleted"
TAGGABLE_EVENTS.TAG_ATTACHED;  // "tag.attached"
TAGGABLE_EVENTS.TAG_DETACHED;  // "tag.detached"