From 5c8d760271887bb6c812f24efc1821c06ed1f682 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Sun, 31 May 2020 10:40:07 +0200 Subject: [PATCH] fix(sort): view not updated when sort state is changed through binding Fixes the visible state of the sort header not being updated if it gets changed through the `matSortActive` binding. Fixes #19467. --- src/material/sort/sort-header.ts | 55 ++++++++++++----------- src/material/sort/sort.spec.ts | 9 ++++ tools/public_api_guard/material/sort.d.ts | 2 +- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/src/material/sort/sort-header.ts b/src/material/sort/sort-header.ts index b2aa33c3cf92..196034bd9d62 100644 --- a/src/material/sort/sort-header.ts +++ b/src/material/sort/sort-header.ts @@ -141,7 +141,7 @@ export class MatSortHeader extends _MatSortHeaderMixinBase private _disableClear: boolean; constructor(public _intl: MatSortHeaderIntl, - changeDetectorRef: ChangeDetectorRef, + private _changeDetectorRef: ChangeDetectorRef, // `MatSort` is not optionally injected, but just asserted manually w/ better error. // tslint:disable-next-line: lightweight-tokens @Optional() public _sort: MatSort, @@ -159,20 +159,7 @@ export class MatSortHeader extends _MatSortHeaderMixinBase throw getSortHeaderNotContainedWithinSortError(); } - this._rerenderSubscription = merge(_sort.sortChange, _sort._stateChanges, _intl.changes) - .subscribe(() => { - if (this._isSorted()) { - this._updateArrowDirection(); - } - - // If this header was recently active and now no longer sorted, animate away the arrow. - if (!this._isSorted() && this._viewState && this._viewState.toState === 'active') { - this._disableViewStateAnimation = false; - this._setAnimationTransitionState({fromState: 'active', toState: this._arrowDirection}); - } - - changeDetectorRef.markForCheck(); - }); + this._handleStateChanges(); } ngOnInit() { @@ -238,27 +225,17 @@ export class MatSortHeader extends _MatSortHeaderMixinBase /** Triggers the sort on this sort header and removes the indicator hint. */ _toggleOnInteraction() { - this._sort.sort(this); // Do not show the animation if the header was already shown in the right position. if (this._viewState.toState === 'hint' || this._viewState.toState === 'active') { this._disableViewStateAnimation = true; } - - // If the arrow is now sorted, animate the arrow into place. Otherwise, animate it away into - // the direction it is facing. - const viewState: ArrowViewStateTransition = this._isSorted() ? - {fromState: this._arrowDirection, toState: 'active'} : - {fromState: 'active', toState: this._arrowDirection}; - this._setAnimationTransitionState(viewState); - - this._showIndicatorHint = false; } _handleClick() { if (!this._isDisabled()) { - this._toggleOnInteraction(); + this._sort.sort(this); } } @@ -325,6 +302,32 @@ export class MatSortHeader extends _MatSortHeaderMixinBase return !this._isDisabled() || this._isSorted(); } + /** Handles changes in the sorting state. */ + private _handleStateChanges() { + this._rerenderSubscription = + merge(this._sort.sortChange, this._sort._stateChanges, this._intl.changes).subscribe(() => { + if (this._isSorted()) { + this._updateArrowDirection(); + + // Do not show the animation if the header was already shown in the right position. + if (this._viewState.toState === 'hint' || this._viewState.toState === 'active') { + this._disableViewStateAnimation = true; + } + + this._setAnimationTransitionState({fromState: this._arrowDirection, toState: 'active'}); + this._showIndicatorHint = false; + } + + // If this header was recently active and now no longer sorted, animate away the arrow. + if (!this._isSorted() && this._viewState && this._viewState.toState === 'active') { + this._disableViewStateAnimation = false; + this._setAnimationTransitionState({fromState: 'active', toState: this._arrowDirection}); + } + + this._changeDetectorRef.markForCheck(); + }); + } + static ngAcceptInputType_disableClear: BooleanInput; static ngAcceptInputType_disabled: BooleanInput; } diff --git a/src/material/sort/sort.spec.ts b/src/material/sort/sort.spec.ts index 52cf21c975b9..bc29d15ef2de 100644 --- a/src/material/sort/sort.spec.ts +++ b/src/material/sort/sort.spec.ts @@ -195,6 +195,15 @@ describe('MatSort', () => { component.dispatchMouseEvent('defaultA', 'mouseenter'); component.expectViewAndDirectionStates(expectedStates); }); + + it('should be correct when sorting programmatically', () => { + component.active = 'defaultB'; + component.direction = 'asc'; + fixture.detectChanges(); + + expectedStates.set('defaultB', {viewState: 'asc-to-active', arrowDirection: 'active-asc'}); + component.expectViewAndDirectionStates(expectedStates); + }); }); it('should be able to cycle from asc -> desc from either start point', () => { diff --git a/tools/public_api_guard/material/sort.d.ts b/tools/public_api_guard/material/sort.d.ts index e5db876793ed..dd47ae0d4842 100644 --- a/tools/public_api_guard/material/sort.d.ts +++ b/tools/public_api_guard/material/sort.d.ts @@ -64,7 +64,7 @@ export declare class MatSortHeader extends _MatSortHeaderMixinBase implements Ca set disableClear(v: boolean); id: string; start: 'asc' | 'desc'; - constructor(_intl: MatSortHeaderIntl, changeDetectorRef: ChangeDetectorRef, _sort: MatSort, _columnDef: MatSortHeaderColumnDef, _focusMonitor: FocusMonitor, _elementRef: ElementRef); + constructor(_intl: MatSortHeaderIntl, _changeDetectorRef: ChangeDetectorRef, _sort: MatSort, _columnDef: MatSortHeaderColumnDef, _focusMonitor: FocusMonitor, _elementRef: ElementRef); _getAriaSortAttribute(): "none" | "ascending" | "descending"; _getArrowDirectionState(): string; _getArrowViewState(): string;