From 62b0e9676e6b2dfadbd0f0ae874bbf92599520a5 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 | 61 +++++++++++------------ src/material/sort/sort.spec.ts | 9 ++++ tools/public_api_guard/material/sort.d.ts | 2 +- 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/material/sort/sort-header.ts b/src/material/sort/sort-header.ts index bc6f32d21c84..aa3d52e22400 100644 --- a/src/material/sort/sort-header.ts +++ b/src/material/sort/sort-header.ts @@ -138,7 +138,7 @@ export class MatSortHeader extends _MatSortHeaderMixinBase private _disableClear: boolean; constructor(public _intl: MatSortHeaderIntl, - changeDetectorRef: ChangeDetectorRef, + private _changeDetectorRef: ChangeDetectorRef, @Optional() public _sort: MatSort, @Inject('MAT_SORT_HEADER_COLUMN_DEF') @Optional() public _columnDef: MatSortHeaderColumnDef, @@ -154,20 +154,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(); // We use the focus monitor because we also want to style // things differently based on the focus origin. @@ -231,23 +218,9 @@ export class MatSortHeader extends _MatSortHeaderMixinBase /** Triggers the sort on this sort header and removes the indicator hint. */ _handleClick() { - if (this._isDisabled()) { return; } - - 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 (!this._isDisabled()) { + this._sort.sort(this); } - - // 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; } /** Whether this MatSortHeader is currently sorted in either ascending or descending order. */ @@ -304,6 +277,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 0e2cedc854ba..ee9a52cbb935 100644 --- a/src/material/sort/sort.spec.ts +++ b/src/material/sort/sort.spec.ts @@ -196,6 +196,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 8de42c50b0fe..83a3b6a277bc 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(): "ascending" | "descending" | null; _getArrowDirectionState(): string; _getArrowViewState(): string;