MemberJunction / MemberJunction/MJ

mj-tree-dropdown search input permanently freezes page on large parent templates

Open
#2,356 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TSQL
Stars
29
Forks
6
Avg merge
2d 1h
Merged PRs (30d)
323

Description

## Problem

Typing any character into the `mj-tree-dropdown` search input permanently freezes the browser tab. The page becomes completely unresponsive and never recovers — requires a hard refresh.

## Reproduction

1. Navigate to Knowledge Hub > Classify
2. Click "Content Types" tab, then "Add Content Type"
3. Open the "AI Model (for tagging)" tree-dropdown
4. Type any character in the search box
5. Page freezes permanently

## Investigation So Far

Extensive debugging was done. Key findings:

- **The `onSearchInput` handler completes in 0.3ms** — the handler itself is not the bottleneck
- **The 200ms debounced `performSearch` never fires** — the freeze occurs before the debounce period
- **`FilterNodes()` takes ~21ms for 311 nodes** — not expensive
- **No `console.log` output appears** when typing — the freeze happens at the zone.js/Angular CD level, not in component code
- **`OnPush` change detection** on tree/tree-dropdown components did not help
- **Running the input listener outside NgZone** did not help (the listener never fired)
- **The hosting page template** (`autotagging-pipeline-resource.component.html`) is ~2000 lines with ~96 method calls in template bindings

## Root Cause Hypothesis

The `(input)` event on the search box triggers zone.js's `ApplicationRef.tick()`, which runs change detection on the **entire application** — not just the tree-dropdown. The autotagging dashboard's 2000-line template with extensive bindings causes CD to take so long the browser marks the page as unresponsive. Since this triggers on every keystroke and the CD cycle never completes before the next one starts, it creates a permanent freeze.

## What Was Tried (All Failed)

1. `ChangeDetectionStrategy.OnPush` on tree + tree-dropdown components
2. `NgZone.runOutsideAngular()` for the input event listener
3. Removing `[value]="SearchText"` binding to avoid two-way CD triggers
4. Moving `SearchText` update from `onSearchInput` to the debounced `performSearch`
5. `ExpandToNodeSilent()` to batch `detectChanges()` calls (helped with post-search but not the initial freeze)

## Possible Approaches Not Yet Tried

1. **Detach CD on the parent component** while the dropdown is open (`ChangeDetectorRef.detach()` on the autotagging component)
2. **Use `NgZone.runOutsideAngular`** at a higher level — wrap the entire tree-dropdown `@if (IsOpen)` block in a zone-less container
3. **Reduce the parent template** — split the 2000-line template into smaller child components with `OnPush` so CD doesn't re-check everything
4. **Use a simple `` or flat list** instead of tree-dropdown for the model picker — avoids the complex tree rendering entirely
5. **Profile with Chrome DevTools Performance tab** — record the freeze to identify exactly which function/layout operation is blocking

## Additional Bugs in mj-tree-dropdown

While investigating, two additional bugs were identified:
- **Enter key doesn't select** the focused node — `onSearchKeyDown()` only handles Escape and ArrowDown, missing Enter
- **`ExpandToNode()` calls `detectChanges()` per node** in a loop — should batch into a single CD call

## Files

- `packages/Angular/Generic/trees/src/lib/tree-dropdown/tree-dropdown.component.ts` — dropdown wrapper
- `packages/Angular/Generic/trees/src/lib/tree/tree.component.ts` — inner tree component
- `packages/Angular/Explorer/dashboards/src/AI/components/autotagging/autotagging-pipeline-resource.component.html` — 2000-line parent template

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.