DEV Community

Cover image for The Two-Level Computed Graph: How I Stopped Toggle Events From Re-Running Business Logic
Yasin Demir
Yasin Demir

Posted on • Originally published at ysndmr.com

The Two-Level Computed Graph: How I Stopped Toggle Events From Re-Running Business Logic

When you build a mapping interface in Angular Signals, the naive approach puts everything in one computed:

readonly sections = computed(() => {
    const data = this.resource.value();
    const draft = this.draftSignal();
    const collapsed = this.collapsedSignal(); // 👈 mistake
    return data.map(section => resolve(section, draft, collapsed));
});
Enter fullscreen mode Exit fullscreen mode

This looks clean. One signal, one truth. But the dependency graph doesn't care about your intentions. Every time the user toggles a section open or closed, collapsed changes, the computed re-runs, and resolve(), which does badge counting, mapping resolution, and fallback calculation across every row in every section, runs again in full.

On a feed with 50 columns and 200 values per column, that's a lot of work for a toggle.

The fix is a two-level graph:

// Level 1 — depends on data + draft only
private readonly resolvedSections = computed(() => {
    const data = this.resource.value();
    const draft = this.draftSignal();
    return data.map(section => resolve(section, draft));
    // isExpanded = false here, placeholder
});

// Level 2 — depends on Level 1 + collapse state only
readonly sections = computed(() => {
    const collapsed = this.collapsedSignal();
    return this.resolvedSections().map(section => ({
        ...section,
        isExpanded: section.available && !collapsed.has(section.name)
    }));
});
Enter fullscreen mode Exit fullscreen mode

Now a toggle only invalidates Level 2. Badge counts, mapping resolution, validation: none of that runs. isValidToSave reads resolvedSections() directly, so it's also unaffected by toggles.

The broader principle: Angular's computed graph is only as good as your dependency boundaries. If a computed reads ten signals but only five of them are relevant to its output, the other five are noise, and that noise has a runtime cost. Designing the graph means deciding, explicitly, which signals belong together.

Glitch-free reactivity isn't a property you get for free. It's something you architect.


Originally published on ysndmr.com.

Top comments (0)