From cc88c81e79524db015eba21f8c5ebdb6765d35fa Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Sun, 27 Dec 2020 15:04:08 +0200 Subject: [PATCH] fix(material/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 | 53 +++++++++++++++++--------------- src/material/sort/sort.spec.ts | 9 ++++++ 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/material/sort/sort-header.ts b/src/material/sort/sort-header.ts index 8b2ab1ded297..cff11afdc23e 100644 --- a/src/material/sort/sort-header.ts +++ b/src/material/sort/sort-header.ts @@ -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() { @@ -243,27 +230,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); } } @@ -330,6 +307,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 9888c4445a4d..9065a23bb52e 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', () => {