David Bulté
David Bulté

Reputation: 3109

In ngrx (with ngrx/effects), how to retrieve the ID of a newly created item?

Say you create a new Book, by dispatching a CREATE_BOOK action from a BookComponent. In an effect, we are handling the http save, and after that we pass the created Book to the reducer through a CREATE_BOOK_SUCCESS action. So far so good.

But how would one get the ID of the newly created Book in the BookComponent that spawned the CREATE_BOOK action? I can only think of workarounds:

Upvotes: 4

Views: 1683

Answers (2)

timdeschryver
timdeschryver

Reputation: 15507

You can't directly let the component know the ID that has been created, because you have to follow the unidirectional data flow of redux.

If you really want to use the ID somewhere you can store this inside your store state as you mentioned, or create the ID client side.

If you want to highlight the created book somewhere in a list you can make implement the trackBy function of the *ngFor directive and create an animation on the newly created item.

For more effect usages, check out Start using ngrx/effects for this

Upvotes: 2

maxime1992
maxime1992

Reputation: 23793

I've been facing that situation too and you've got in my opinion 2 options there:

  • first one and definitely the most simple, you create the ID directly on the frontend using UUID library, but maybe that your IDs are being generated on the backend and you can't do that
  • second option, a bit less forward but that's working great too:

Generate an ID and pass it within the payload of the action (in addition of your current payload if needed). You might call it for example actionId.

From your effect, when you map to the action CREATE_BOOK_SUCCESS, also pass that ID you've got access to! (because we're in the piece of code that's handling the CREATE_BOOK action).

From the (smart) component, you can subscribe to actions, just like you do within your effects! And so you can do something like that:

class MyComponent {
  // ...

  createBook(book: Book) {
    // first, generate a unique ID to track the action
    // you can call directly the uuid function or even better create
    // a uuidService that you inject but for simplicity here I'm not doing it
    const actionId: string = uuid();

    // then watch for an action of type CREATE_BOOK_SUCCESS with that ID
    this.actions.pipe(
      ofType<BooksActions.CreateBookSuccess>(BooksActions.CREATE_BOOK_SUCCESS),
      filter(({payload}) => payload.actionId === actionId),
      first(),
      tap(({payload}) => {
        // do what you want here
        // you've got access to the payload of the CREATE_BOOK_SUCCESS action where
        // you have the book returned from the backend (I think)
      })
    );

    // finally, dispatch the action
    // it's important to do it after you've subscribed to actions otherwise it might happen
    // too fast and you wouldn't get the notification
    this.actions.dispatch(new BooksActions.CreateBook({ ...book, actionId }));
  }

  // ...
}

Note that I'm using first here when subscribing to the action so even if you add 10 books reaaaally quickly you'll have 10 different subscriptions which is totally fine.

Upvotes: 2

Related Questions