angular/components · error · Error

CdkSelectAll: missing CdkSelection in the parent

Error message

CdkSelectAll: missing CdkSelection in the parent

What it means

CdkSelectAll/CdkSelectToggle (selection-toggle.ts) requires a parent CdkSelection whose SelectionSet it operates on. ngOnInit calls _assertValidParentSelection, which throws in dev mode when the injected parent selection (_selection) is missing — i.e., the toggle directive was used outside a CdkSelection container. Without it, the toggle has no selection model to drive.

Source

Thrown at src/cdk-experimental/selection/selection-toggle.ts:79

    this.checked = _selection.change.pipe(
      switchMap(() => observableOf(this._isSelected())),
      distinctUntilChanged(),
    );
  }

  ngOnInit() {
    this._assertValidParentSelection();
    this._configureControlValueAccessor();
  }

  ngOnDestroy() {
    this._destroyed.next();
    this._destroyed.complete();
  }

  private _assertValidParentSelection() {
    if (!this._selection && (typeof ngDevMode === 'undefined' || ngDevMode)) {
      throw Error('CdkSelectAll: missing CdkSelection in the parent');
    }
  }

  private _configureControlValueAccessor() {
    if (this._controlValueAccessors && this._controlValueAccessors.length) {
      this._controlValueAccessors[0].registerOnChange((e: unknown) => {
        if (typeof e === 'boolean') {
          this.toggle();
        }
      });

      this.checked.pipe(takeUntil(this._destroyed)).subscribe(state => {
        this._controlValueAccessors![0].writeValue(state);
      });
    }
  }

  private _isSelected(): boolean {

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Wrap the toggle in a CdkSelection: place it inside the <cdk-selection> element that has dataSource set.
  2. If it must live elsewhere, hoist the CdkSelection to a common ancestor component template.
  3. Verify the injected parent: ensure the directive's selector matches the CdkSelection host (parent/content based DI).

Example fix

<!-- before -->
<my-toolbar><cdk-select-all>...</cdk-select-all></my-toolbar>

<!-- after -->
<cdk-selection [dataSource]="rows">
  <my-toolbar><cdk-select-all>...</cdk-select-all></my-toolbar>
</cdk-selection>
Defensive patterns

Strategy: type-guard

Validate before calling

const parentSelection: CdkSelection<unknown> | null = inject(CdkSelection, { optional: true });
if (!parentSelection) throw new Error('<cdk-select-all> must be used inside <cdk-selection>');

Type guard

function hasParentSelection(dir: { _selection: CdkSelection<unknown> | null | undefined }): boolean {
  return dir._selection != null;
}

Try / catch

ngOnInit() {
  try {
    this._assertValidParentSelection();
  } catch (e) {
    console.error('Place this directive inside a CdkSelection element.', e);
  }
}

Prevention

When it happens

Trigger: Placing <cdk-select-all> (or the toggle directive) in a template with no ancestor <cdk-selection> / [cdkSelection] directive; putting it inside a CDK table row whose parent selection lives in an unrelated component; typos in selector usage that skip the wrapper.

Common situations: Moving the select-all checkbox out of the CdkSelection template during refactor; rendering rows with a custom component that does not project the toggle under CdkSelection; forgetting that the directive resolves the parent via content/parent injection, not a service.

Related errors


AI-assisted analysis of angular/components@0411926e7d (2026-08-31). Data as JSON: /api/errors/f5b631732cf5b2ba. Report an issue: GitHub.