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

Copy link
Collaborator

@rainerhahnekamp rainerhahnekamp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very good. just tiny things. if you want we can merge now, and you do the 3 tasks in a separate branch.

Copy link
Collaborator

@rainerhahnekamp rainerhahnekamp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, there are some conflicts, Can you maybe rebase from main?

@rainerhahnekamp rainerhahnekamp merged commit 1376916 into angular-architects:main Oct 21, 2025
1 check passed
@rainerhahnekamp
Copy link
Collaborator

Danke Murat!

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.

3 participants