Search code examples
angularapingrxngrx-entity

How to define selectId for entity adapter when the relevant id is defined on the backend?


I'm dispatching the upsert action/ reducer on my store to add a new record to state and there is an effect that will call the backend and add the record/ document to my mongodb instance.

Given that the only sensible id for this particular model is defined by my backend logic at the time of document creation, how should i define selectId in my entity implementation in my front end?

At the moment an item is added to state with id: undefined and i get the warning:

entity.js:76 @ngrx/entity: The entity passed to the selectId implementation returned undefined. You should probably provide your own selectId implementation.

My adapter is defined as:

export const adapter: EntityAdapter<PublishedData> = createEntityAdapter<
  PublishedData
>({ selectId: (publishedData: PublishedData) => publishedData.doi });

and the relevant effect is:

@Effect()
  UpsertPublishedData$ = this.actions$.pipe(
    ofType<UpsertPublishedData>(PublishedDataActionTypes.UpsertPublishedData),
    switchMap(action => this.publishedDataApi.create(action.payload.publishedData)
    .pipe(mergeMap((data: PublishedData) => [ new UpsertPublishedData({ publishedData: data }),
      this.publishedDataApi.register(data[0].doi)]),
    catchError(err => of(new FailedPublishedDataAction(err)))))
  );

publishedData.doi is the offending field that I need to use to reference the entity.


Solution

  • For now I have modified the reducer to not add the record to state on the first pass where the id field (doi) is undefined.

    case PublishedDataActionTypes.UpsertWaitPublishedData: {
      if (action.payload.publishedData && action.payload.publishedData.doi) {
        return adapter.upsertOne(action.payload.publishedData, state);
      }
      return state;
    }
    

    from this originally:

      case PublishedDataActionTypes.UpsertPublishedData: {
          return adapter.upsertOne(action.payload.publishedData, state);
        }
    

    This ensures the record in state matches that in the database. This approach is still in line with an entity approach whereby no additional UpsertPublishedDataSuccess action is required.