Skip to main content

Entities Props Factory

There are two built-in entities props included in Elf - withEntities and UIEntities. In addition to that, we can create our own entities props for our stores.

Let's say we have a products page with a shopping cart. As well as managing a store for products, we must also maintain a shopping cart. We can create a new Store for our cart or a cart entity props in the same products store.

First, let's create the products store:

products.repository.ts
import { createStore } from '@ngneat/elf';
import { withEntities } from '@ngneat/elf-entities';

interface Product {
id: number;
title: string;
price: number;
}

export const productsStore = createStore(
{ name: 'products' },
withEntities<Product>()
);

Now we can add a cart entities props to the same store:

products.repository.ts
import { createStore } from '@ngneat/elf';
import { withEntities, entitiesPropsFactory } from '@ngneat/elf-entities';

const { cartEntitiesRef, withCartEntities } = entitiesPropsFactory('cart');

interface Product {
id: number;
title: string;
price: number;
}

interface CartItem {
id: Product['id'];
quantity: number;
}

export const productsStore = createStore(
{ name: 'products' },
withEntities<Product>(),
withCartEntities<CartItem>()
);

The entitiesPropsFactory function takes the name of the feature and returns entitiesRef and entitiesProps we can use in our store.

In the above example, our final state shape will be:

{
entities: Record<number, Product>;
ids: number[];
cartEntities: Record<number, CartItem>;
cartIds: number[];
}

We can pass the cartEntitiesRef to each one of the built-in queries and mutations:

products.repository.ts
import { upsertEntitiesById } from '@ngneat/elf-entities';

export function updateCart(id: Product['id']) {
productsStore.update(
upsertEntitiesById(id, {
updater: (e) => ({ ...e, quantity: e.quantity + 1 }),
creator: (id) => ({ id, quantity: 1 }),
ref: cartEntitiesRef,
})
);
}

One more use case for custom entities props is when we work with a normalized state. For example, we might have a movies page, with actors and genres:

movies.repository.ts
interface Actor {
id: string;
name: string;
}

interface Genre {
id: string;
name: string;
}

interface Movie {
id: string;
title: string;
genres: Array<Genre['id']>;
actors: Array<Actor['id']>;
}

const { actorsEntitiesRef, withActorsEntities } =
entitiesPropsFactory('actors');

const { genresEntitiesRef, withGenresEntities } =
entitiesPropsFactory('genres');

const store = createStore(
{ name: 'movies' },
withEntities<Movie>(),
withGenresEntities<Genre>(),
withActorsEntities<Actor>()
);

store.update(
addEntities({ id: '1', name: 'Nicolas cage' }, { ref: actorsEntitiesRef }),
addEntities({ id: '1', name: 'Action' }, { ref: genresEntitiesRef }),
addEntities({
id: '1',
title: 'Gone in 60 Seconds',
genres: ['1'],
actors: ['1'],
})
);