Skip to content

Conversation

wolfmanfx
Copy link
Collaborator

@wolfmanfx wolfmanfx commented Sep 20, 2025

Summary

Adds withEntityResources() to integrate Angular Resources that return arrays with NgRx Entities in SignalStore. It composes resource handling with entity helpers, keeps entity state linked to the resource value via linked signals, and supports both unnamed and named collections.

Motivation

Many resources represent collections. Previously, wiring withResource results into withEntities required boilerplate and manual sync. This feature removes redundancy by linking entity state to the resource value directly.

Design Overview

  • Composed: Builds on withResource(); derives ids, entityMap, and entities from the resource’s value.
  • Linked signals, no effects: Entity projections are linked to the resource value; synchronization is purely signal-based.
  • Supports named resources: Works for single (unnamed) and multiple (named) array resources with prefixed members.
  • Type-safe: Infers entity element type (must include an id compatible with EntityId).

Usage

Unnamed

export type Todo = { id: number; title: string; completed: boolean };

export const TodoStore = signalStore(
  withEntityResources(() => resource({ loader: () => Promise.resolve([] as Todo[]), defaultValue: [] })),
);

// Exposes resource members: value/status/error/isLoading/hasValue/_reload
// And entity members: ids/entityMap/entities

Named

export const Store = signalStore(
  withEntityResources(() => ({
    todos: resource({ loader: () => Promise.resolve([] as Todo[]), defaultValue: [] }),
    projects: resource({ loader: () => Promise.resolve([] as { id: number; name: string }[]), defaultValue: [] }),
  })),
);

// Exposes: todosValue()/todosIds()/todosEntities(), projectsValue()/projectsIds()/projectsEntities(), etc.

Entity Updaters

patchState(store, setAllEntities([{ id: 1, title: 'A', completed: false }]));
patchState(store, addEntity({ id: 2, title: 'B', completed: true }));
patchState(store, updateEntity({ id: 2, changes: { completed: false } }));
patchState(store, removeEntity(1));

// Named example:
// patchState(store, addEntity({ id: 3, title: 'C', completed: false }, { collection: 'todos' }));

Implementation Notes

  • Adds libs/ngrx-toolkit/src/lib/with-entity-resources.ts with unit tests.
  • Exports via libs/ngrx-toolkit/src/index.ts.
  • Documentation added: docs/docs/with-entity-resources.md and sidebar updated.
  • Demo added under apps/demo/src/app/todo-entity-resource/* with an E2E test.

Tests & Demo

  • Unit tests: libs/ngrx-toolkit/src/lib/with-entity-resources.spec.ts
  • Demo: apps/demo/src/app/todo-entity-resource/*
  • E2E: apps/demo/e2e/todo-entity-resource.spec.ts

Documentation

  • New page: withEntityResources() usage, inputs, and examples.
  • Cross-linked in docs/docs/extensions.md and docs/sidebars.ts.

Breaking Changes

  • None.

Checklist

  • Feature implementation
  • Unit tests
  • Demo & E2E
  • Docs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants