diff --git a/src/demo-app/table/table-demo.html b/src/demo-app/table/table-demo.html index 0433ee7f1ad7..ba16cef3301e 100644 --- a/src/demo-app/table/table-demo.html +++ b/src/demo-app/table/table-demo.html @@ -65,7 +65,7 @@

CdkTable Example

+ mat-sort-header arrowPosition="before" disabled> ID {{row.id}} @@ -228,7 +228,7 @@

MatTable With MatTableDataSource Example

- ID + ID {{row.id}} diff --git a/src/lib/sort/sort-header.html b/src/lib/sort/sort-header.html index 4061041b1930..a2f6633d3ff9 100644 --- a/src/lib/sort/sort-header.html +++ b/src/lib/sort/sort-header.html @@ -1,6 +1,9 @@
+ diff --git a/src/lib/sort/sort-header.scss b/src/lib/sort/sort-header.scss index 088a5429f68e..6c7560e00b67 100644 --- a/src/lib/sort/sort-header.scss +++ b/src/lib/sort/sort-header.scss @@ -26,6 +26,11 @@ $mat-sort-header-arrow-transition: 225ms cubic-bezier(0.4, 0, 0.2, 1); color: currentColor; } +.mat-sort-header-disabled, +.mat-sort-header-button[disabled] { + cursor: default; +} + .mat-sort-header-arrow { height: $mat-sort-header-arrow-container-size; width: $mat-sort-header-arrow-container-size; diff --git a/src/lib/sort/sort-header.ts b/src/lib/sort/sort-header.ts index 67e395b3906e..a0b5aed3ab59 100644 --- a/src/lib/sort/sort-header.ts +++ b/src/lib/sort/sort-header.ts @@ -15,25 +15,28 @@ import { ViewEncapsulation } from '@angular/core'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; -import { - trigger, - state, - style, - animate, - transition, - keyframes, -} from '@angular/animations'; +import {animate, keyframes, state, style, transition, trigger} from '@angular/animations'; import {CdkColumnDef} from '@angular/cdk/table'; import {Subscription} from 'rxjs/Subscription'; import {merge} from 'rxjs/observable/merge'; import {MatSort, MatSortable} from './sort'; import {MatSortHeaderIntl} from './sort-header-intl'; import {getSortHeaderNotContainedWithinSortError} from './sort-errors'; -import {AnimationCurves, AnimationDurations} from '@angular/material/core'; +import { + AnimationCurves, + AnimationDurations, + CanDisable, + mixinDisabled +} from '@angular/material/core'; const SORT_ANIMATION_TRANSITION = AnimationDurations.ENTERING + ' ' + AnimationCurves.STANDARD_CURVE; +// Boilerplate for applying mixins to MatSortHeader. +/** @docs-private */ +export class MatSortHeaderBase { } +export const _MatSortHeaderMixinBase = mixinDisabled(MatSortHeaderBase); + /** * Applies sorting behavior (click to change sort) and styles to an element, including an * arrow to display the current sort direction. @@ -49,8 +52,9 @@ const SORT_ANIMATION_TRANSITION = exportAs: 'matSortHeader', templateUrl: 'sort-header.html', styleUrls: ['sort-header.css'], + inputs: ['disabled'], host: { - '(click)': '_sort.sort(this)', + '(click)': '_handleClick()', '[class.mat-sort-header-sorted]': '_isSorted()', }, encapsulation: ViewEncapsulation.None, @@ -93,7 +97,7 @@ const SORT_ANIMATION_TRANSITION = ]) ] }) -export class MatSortHeader implements MatSortable { +export class MatSortHeader extends _MatSortHeaderMixinBase implements MatSortable, CanDisable { private _rerenderSubscription: Subscription; /** @@ -118,6 +122,8 @@ export class MatSortHeader implements MatSortable { changeDetectorRef: ChangeDetectorRef, @Optional() public _sort: MatSort, @Optional() public _cdkColumnDef: CdkColumnDef) { + super(); + if (!_sort) { throw getSortHeaderNotContainedWithinSortError(); } @@ -140,6 +146,13 @@ export class MatSortHeader implements MatSortable { this._rerenderSubscription.unsubscribe(); } + /** Triggers the sort on this sort header if it is not disabled. */ + _handleClick() { + if (!this.disabled) { + this._sort.sort(this); + } + } + /** Whether this MatSortHeader is currently sorted in either ascending or descending order. */ _isSorted() { return this._sort.active == this.id && diff --git a/src/lib/sort/sort.spec.ts b/src/lib/sort/sort.spec.ts index 59d3f8df9c8a..ceb014e82425 100644 --- a/src/lib/sort/sort.spec.ts +++ b/src/lib/sort/sort.spec.ts @@ -52,7 +52,7 @@ describe('MatSort', () => { it('should have the sort headers register and deregister themselves', () => { const sortables = component.matSort.sortables; - expect(sortables.size).toBe(4); + expect(sortables.size).toBe(5); expect(sortables.get('defaultSortHeaderA')).toBe(component.matSortHeaderDefaultA); expect(sortables.get('defaultSortHeaderB')).toBe(component.matSortHeaderDefaultB); @@ -60,11 +60,26 @@ describe('MatSort', () => { expect(sortables.size).toBe(0); }); + it('should be able to disable a sort header', () => { + // With it disabled, it should not set to active + fixture.componentInstance.sort('sortF'); + fixture.detectChanges(); + expect(component.matSort.active).toBe(undefined); + + // Set disabled to false + fixture.componentInstance.disableSortF = false; + fixture.detectChanges(); + + // Sort should work + fixture.componentInstance.sort('sortF'); + fixture.detectChanges(); + expect(component.matSort.active).toBe('sortF'); + }); + it('should use the column definition if used within a cdk table', () => { let cdkTableMatSortAppFixture = TestBed.createComponent(CdkTableMatSortApp); let cdkTableMatSortAppComponent = cdkTableMatSortAppFixture.componentInstance; - cdkTableMatSortAppFixture.detectChanges(); cdkTableMatSortAppFixture.detectChanges(); const sortables = cdkTableMatSortAppComponent.matSort.sortables; @@ -78,7 +93,6 @@ describe('MatSort', () => { let matTableMatSortAppFixture = TestBed.createComponent(MatTableMatSortApp); let matTableMatSortAppComponent = matTableMatSortAppFixture.componentInstance; - matTableMatSortAppFixture.detectChanges(); matTableMatSortAppFixture.detectChanges(); const sortables = matTableMatSortAppComponent.matSort.sortables; @@ -223,6 +237,7 @@ function testSingleColumnSortDirectionSequence(fixture: ComponentFixture
D
E
+
F
` }) @@ -232,6 +247,7 @@ class SimpleMatSortApp { active: string; start: SortDirection = 'asc'; direction: SortDirection = ''; + disableSortF = true; disableClear: boolean; @ViewChild(MatSort) matSort: MatSort; @@ -246,7 +262,6 @@ class SimpleMatSortApp { } } - class FakeDataSource extends DataSource { connect(collectionViewer: CollectionViewer): Observable { return map.call(collectionViewer.viewChange, () => []);