Skip to main content

Angular Guidline

  • simple, long‑term style guide you can apply across list/add/edit.

simple, long‑term style guide you can apply across list/add/edit.

Core Pattern (Recommended for your project)

  • Use rxResource() for fetching data.
  • Use signal() for form fields and UI state.
  • Use computed() for derived state like loading.
  • Use effect() only for side effects (snackbar, logging).
  • Use lastValueFrom() (or firstValueFrom()) for mutations (add/update/delete) so you can await.

1. List Page Pattern

const listResource = rxResource({
stream: () => api.getContact()
});

const deleting = signal(false);
const loading = computed(() => listResource.isLoading() || deleting());

const showError = effect(() => {
const err = listResource.error();
if (err) snackbar.open(err.message, 'Close', { duration: 3000 });
});

2. Add Page Pattern

const firstName = signal('');
const lastName = signal('');
const phone = signal<number | null>(null);
const email = signal('');

const saving = signal(false);

async function onSave() {
saving.set(true);
await lastValueFrom(api.addContact({ firstName: firstName(), ... }));
saving.set(false);
router.navigate(['/doc/crud']);
}

3) Edit Page Pattern

const id = signal(route.snapshot.paramMap.get('id') ?? '');

const contactResource = rxResource({
params: id,
stream: ({ params }) => api.getContactId(params)
});

// keep form values synced with fetched data but editable
const firstName = linkedSignal(() => contactResource.value()?.firstName ?? '');
const lastName = linkedSignal(() => contactResource.value()?.lastName ?? '');
const phone = linkedSignal(() => contactResource.value()?.phoneNumber ?? '');
const email = linkedSignal(() => contactResource.value()?.email ?? '');

const saving = signal(false);
const loading = computed(() => contactResource.isLoading() || saving());

signal

A piece of reactive state. Read with signal() and write with signal.set(value).

computed

A derived signal that re-calculates automatically when dependencies change. Example: loading = computed(() => resource.isLoading() || saving()).

effect

Runs a side effect when its dependencies change. Example: showError runs when contactsResource.error() changes.

linkedSignal

A signal that syncs from a source (like a resource or input) but stays editable. In your edit form, it starts from fetched contact fields but can be edited by the user.

toSignal

Converts an Observable into a signal. Example pattern: const user = toSignal(api.getUser()). You import it in edit-contact but don’t use it yet.

rxResource

Wraps an Observable stream into a resource with built-in value(), error(), isLoading(), reload(). It’s ideal when you want declarative data fetching that “feels like” signals. Observable

RxJS stream of async values (HTTP, events, etc). They are lazy and don’t do work until subscribed. rxResource and lastValueFrom are both ways to subscribe.

Input form

onchange : run when an input's value changed and then commited