Skip to content

Commit 36bc124

Browse files
committed
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.
1 parent 264c20d commit 36bc124

File tree

3 files changed

+40
-32
lines changed

3 files changed

+40
-32
lines changed

src/material/sort/sort-header.ts

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ export class MatSortHeader extends _MatSortHeaderMixinBase
139139
private _disableClear: boolean;
140140

141141
constructor(public _intl: MatSortHeaderIntl,
142-
changeDetectorRef: ChangeDetectorRef,
142+
private _changeDetectorRef: ChangeDetectorRef,
143143
@Optional() public _sort: MatSort,
144144
@Inject('MAT_SORT_HEADER_COLUMN_DEF') @Optional()
145145
public _columnDef: MatSortHeaderColumnDef,
@@ -155,20 +155,7 @@ export class MatSortHeader extends _MatSortHeaderMixinBase
155155
throw getSortHeaderNotContainedWithinSortError();
156156
}
157157

158-
this._rerenderSubscription = merge(_sort.sortChange, _sort._stateChanges, _intl.changes)
159-
.subscribe(() => {
160-
if (this._isSorted()) {
161-
this._updateArrowDirection();
162-
}
163-
164-
// If this header was recently active and now no longer sorted, animate away the arrow.
165-
if (!this._isSorted() && this._viewState && this._viewState.toState === 'active') {
166-
this._disableViewStateAnimation = false;
167-
this._setAnimationTransitionState({fromState: 'active', toState: this._arrowDirection});
168-
}
169-
170-
changeDetectorRef.markForCheck();
171-
});
158+
this._handleStateChanges();
172159
}
173160

174161
ngOnInit() {
@@ -234,23 +221,9 @@ export class MatSortHeader extends _MatSortHeaderMixinBase
234221

235222
/** Triggers the sort on this sort header and removes the indicator hint. */
236223
_handleClick() {
237-
if (this._isDisabled()) { return; }
238-
239-
this._sort.sort(this);
240-
241-
// Do not show the animation if the header was already shown in the right position.
242-
if (this._viewState.toState === 'hint' || this._viewState.toState === 'active') {
243-
this._disableViewStateAnimation = true;
224+
if (!this._isDisabled()) {
225+
this._sort.sort(this);
244226
}
245-
246-
// If the arrow is now sorted, animate the arrow into place. Otherwise, animate it away into
247-
// the direction it is facing.
248-
const viewState: ArrowViewStateTransition = this._isSorted() ?
249-
{fromState: this._arrowDirection, toState: 'active'} :
250-
{fromState: 'active', toState: this._arrowDirection};
251-
this._setAnimationTransitionState(viewState);
252-
253-
this._showIndicatorHint = false;
254227
}
255228

256229
/** Whether this MatSortHeader is currently sorted in either ascending or descending order. */
@@ -307,6 +280,32 @@ export class MatSortHeader extends _MatSortHeaderMixinBase
307280
return !this._isDisabled() || this._isSorted();
308281
}
309282

283+
/** Handles changes in the sorting state. */
284+
private _handleStateChanges() {
285+
this._rerenderSubscription =
286+
merge(this._sort.sortChange, this._sort._stateChanges, this._intl.changes).subscribe(() => {
287+
if (this._isSorted()) {
288+
this._updateArrowDirection();
289+
290+
// Do not show the animation if the header was already shown in the right position.
291+
if (this._viewState.toState === 'hint' || this._viewState.toState === 'active') {
292+
this._disableViewStateAnimation = true;
293+
}
294+
295+
this._setAnimationTransitionState({fromState: this._arrowDirection, toState: 'active'});
296+
this._showIndicatorHint = false;
297+
}
298+
299+
// If this header was recently active and now no longer sorted, animate away the arrow.
300+
if (!this._isSorted() && this._viewState && this._viewState.toState === 'active') {
301+
this._disableViewStateAnimation = false;
302+
this._setAnimationTransitionState({fromState: 'active', toState: this._arrowDirection});
303+
}
304+
305+
this._changeDetectorRef.markForCheck();
306+
});
307+
}
308+
310309
static ngAcceptInputType_disableClear: BooleanInput;
311310
static ngAcceptInputType_disabled: BooleanInput;
312311
}

src/material/sort/sort.spec.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,15 @@ describe('MatSort', () => {
196196
component.dispatchMouseEvent('defaultA', 'mouseenter');
197197
component.expectViewAndDirectionStates(expectedStates);
198198
});
199+
200+
it('should be correct when sorting programmatically', () => {
201+
component.active = 'defaultB';
202+
component.direction = 'asc';
203+
fixture.detectChanges();
204+
205+
expectedStates.set('defaultB', {viewState: 'asc-to-active', arrowDirection: 'active-asc'});
206+
component.expectViewAndDirectionStates(expectedStates);
207+
});
199208
});
200209

201210
it('should be able to cycle from asc -> desc from either start point', () => {

tools/public_api_guard/material/sort.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export declare class MatSortHeader extends _MatSortHeaderMixinBase implements Ca
6464
set disableClear(v: boolean);
6565
id: string;
6666
start: 'asc' | 'desc';
67-
constructor(_intl: MatSortHeaderIntl, changeDetectorRef: ChangeDetectorRef, _sort: MatSort, _columnDef: MatSortHeaderColumnDef, _focusMonitor: FocusMonitor, _elementRef: ElementRef<HTMLElement>);
67+
constructor(_intl: MatSortHeaderIntl, _changeDetectorRef: ChangeDetectorRef, _sort: MatSort, _columnDef: MatSortHeaderColumnDef, _focusMonitor: FocusMonitor, _elementRef: ElementRef<HTMLElement>);
6868
_getAriaSortAttribute(): "ascending" | "descending" | null;
6969
_getArrowDirectionState(): string;
7070
_getArrowViewState(): string;

0 commit comments

Comments
 (0)