MCPcopy Create free account
hub / github.com/angular/components / ngAfterViewInit

Method ngAfterViewInit

src/cdk/stepper/stepper.ts:420–487  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

418 }
419
420 ngAfterViewInit() {
421 // If the step headers are defined outside of the `ngFor` that renders the steps, like in the
422 // Material stepper, they won't appear in the `QueryList` in the same order as they're
423 // rendered in the DOM which will lead to incorrect keyboard navigation. We need to sort
424 // them manually to ensure that they're correct. Alternatively, we can change the Material
425 // template to inline the headers in the `ngFor`, but that'll result in a lot of
426 // code duplication. See #23539.
427 this._stepHeader.changes
428 .pipe(startWith(this._stepHeader), takeUntil(this._destroyed))
429 .subscribe((headers: QueryList<CdkStepHeader>) => {
430 this._sortedHeaders.reset(
431 headers.toArray().sort((a, b) => {
432 const documentPosition = a._elementRef.nativeElement.compareDocumentPosition(
433 b._elementRef.nativeElement,
434 );
435
436 // `compareDocumentPosition` returns a bitmask so we have to use a bitwise operator.
437 // https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition
438 // tslint:disable-next-line:no-bitwise
439 return documentPosition & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
440 }),
441 );
442 this._sortedHeaders.notifyOnChanges();
443 });
444
445 // Note that while the step headers are content children by default, any components that
446 // extend this one might have them as view children. We initialize the keyboard handling in
447 // AfterViewInit so we're guaranteed for both view and content children to be defined.
448 this._keyManager = new FocusKeyManager<FocusableOption>(this._sortedHeaders)
449 .withWrap()
450 .withHomeAndEnd()
451 .withVerticalOrientation(this._orientation === 'vertical');
452
453 // The selected index may have changed between when the component was created and when the
454 // key manager was initialized. Use `updateActiveItem` so it's correct, but it doesn't steal
455 // away focus from the user.
456 this._keyManager.updateActiveItem(this.selectedIndex);
457
458 (this._dir ? (this._dir.change as Observable<Direction>) : observableOf<Direction>())
459 .pipe(startWith(this._layoutDirection()), takeUntil(this._destroyed))
460 .subscribe(direction => this._keyManager?.withHorizontalOrientation(direction));
461
462 this._keyManager.updateActiveItem(this.selectedIndex);
463
464 // No need to `takeUntil` here, because we're the ones destroying `steps`.
465 this.steps.changes.subscribe(() => {
466 if (!this.selected) {
467 this._selectedIndex.set(Math.max(this.selectedIndex - 1, 0));
468 }
469 });
470
471 // The logic which asserts that the selected index is within bounds doesn't run before the
472 // steps are initialized, because we don't how many steps there are yet so we may have an
473 // invalid index on init. If that's the case, auto-correct to the default so we don't throw.
474 if (!this._isValidIndex(this.selectedIndex)) {
475 this._selectedIndex.set(0);
476 }
477

Callers

nothing calls this directly

Calls 12

_layoutDirectionMethod · 0.95
_isValidIndexMethod · 0.95
withHomeAndEndMethod · 0.80
withWrapMethod · 0.80
updateActiveItemMethod · 0.80
setMethod · 0.80
_markAsInteractedMethod · 0.80
resetMethod · 0.65
sortMethod · 0.65
maxMethod · 0.45

Tested by

no test coverage detected