Skip to content

Commit

Permalink
fix(sort): view not updated when sort state is changed through binding
Browse files Browse the repository at this point in the history
Fixes the visible state of the sort header not being updated if it gets changed through the `matSortActive` binding.

Fixes #19467.
  • Loading branch information
crisbeto committed Jul 24, 2020
1 parent 89b5fa8 commit 5c8d760
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 27 deletions.
55 changes: 29 additions & 26 deletions src/material/sort/sort-header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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() {
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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;
}
9 changes: 9 additions & 0 deletions src/material/sort/sort.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
2 changes: 1 addition & 1 deletion tools/public_api_guard/material/sort.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLElement>);
constructor(_intl: MatSortHeaderIntl, _changeDetectorRef: ChangeDetectorRef, _sort: MatSort, _columnDef: MatSortHeaderColumnDef, _focusMonitor: FocusMonitor, _elementRef: ElementRef<HTMLElement>);
_getAriaSortAttribute(): "none" | "ascending" | "descending";
_getArrowDirectionState(): string;
_getArrowViewState(): string;
Expand Down

0 comments on commit 5c8d760

Please sign in to comment.