I am trying to perform a full CRUD operation using Angular + Cloud Firestore + NGRX/Entity.
Id is required parameter to perform ngrx/entity. But when I create an item from my angular form to my firestore, I don't know yet the id as it would be assigned automatically with the document id of my future creation.
How can I send data to firestore using ngrx/entity without sending the id?
I have an interface as follow:
Interface of entity:
export interface Recipe {
id: string;
recipeTitle: string;
}
actions.ts:
export const addRecipe = createAction(
'[Recipe Add Component] Add Recipe',
props<{ recipe: Recipe }>()
);
export const addRecipeSuccess = createAction(
'[Recipe Add Effect] Add Recipe Success',
props<{ recipe: Recipe }>()
);
export const addRecipeFailure = createAction(
'[Recipe Add Effect] Add Recipe Failure',
props<{ error: any }>()
);
Reducer.ts
// entity adapter
export const recipeAdapter: EntityAdapter<Recipe> = createEntityAdapter<Recipe>({
});
export interface RecipeState extends EntityState<Recipe> {
error: any;
selectedRecipe: Recipe;
}
export const initialState: RecipeState = recipeAdapter.getInitialState({
error: undefined,
selectedRecipe: undefined
});
export const recipeReducer = createReducer(
initialState,
on(RecipeActions.addRecipeSuccess, (state, action) => {
return recipeAdapter.addOne(action.recipe, state);
}),
on(RecipeActions.addRecipeFailure, (state, action) => {
return {
...state,
error: action.error
};
}),
Effects.ts
createRecipe$ = createEffect(() =>
this.actions$.pipe(
ofType(fromRecipeActions.addRecipe),
mergeMap(action =>
this.recipeService.createRecipe(action.recipe).pipe(
map(recipe => fromRecipeActions.addRecipeSuccess({recipe})),
catchError(error =>
of(fromRecipeActions.addRecipeFailure({ error }))
)
)
)
)
);
Create Component.ts
createRecipe(formGroup): void {
const recipeCreated = {
recipeTitle: formGroup.recipeTitle
};
this.store.dispatch(actions.addRecipe({recipe: recipeCreated}));
this.router.navigate(['tabs/recipe']);
}
service.ts
createRecipe(recipe): Observable<any> {
return from(this.firestore.collection(`recipes`).add(recipe));
}
getRecipes(): Observable<any[]> {
return this.firestore.collection<Recipe>('recipes').snapshotChanges().pipe(map(arr => {
return arr.map(doc => {
const data = doc.payload.doc.data();
return {
id: doc.payload.doc.id,
...data
} as Recipe;
});
}));
}
deleteRecipe(recipeId: string) {
return from(this.firestore.collection<Recipe>('recipes/').doc(recipeId).delete());
}
You can create a custom ID selector which would make id optional:
export const recipeAdapter: EntityAdapter<Recipe> = createEntityAdapter<Recipe>({
selectId: t => t.id || 0
});