Skip to content

Commit 0d162a4

Browse files
authored
feat(material/sort): default arrow position in MatSortDefaultOptions (#23609)
closes #23600
1 parent 341d14b commit 0d162a4

File tree

5 files changed

+164
-8
lines changed

5 files changed

+164
-8
lines changed

src/material/sort/sort-header.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
-->
1111
<div class="mat-sort-header-container mat-focus-indicator"
1212
[class.mat-sort-header-sorted]="_isSorted()"
13-
[class.mat-sort-header-position-before]="arrowPosition == 'before'"
13+
[class.mat-sort-header-position-before]="arrowPosition === 'before'"
1414
[attr.tabindex]="_isDisabled() ? null : 0"
1515
role="button">
1616

src/material/sort/sort-header.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,13 @@ import {
2424
} from '@angular/core';
2525
import {CanDisable, mixinDisabled} from '@angular/material/core';
2626
import {merge, Subscription} from 'rxjs';
27-
import {MatSort, MatSortable} from './sort';
27+
import {
28+
MAT_SORT_DEFAULT_OPTIONS,
29+
MatSort,
30+
MatSortable,
31+
MatSortDefaultOptions,
32+
SortHeaderArrowPosition,
33+
} from './sort';
2834
import {matSortAnimations} from './sort-animations';
2935
import {SortDirection} from './sort-direction';
3036
import {getSortHeaderNotContainedWithinSortError} from './sort-errors';
@@ -134,7 +140,7 @@ export class MatSortHeader
134140
@Input('mat-sort-header') id: string;
135141

136142
/** Sets the position of the arrow that displays when sorted. */
137-
@Input() arrowPosition: 'before' | 'after' = 'after';
143+
@Input() arrowPosition: SortHeaderArrowPosition = 'after';
138144

139145
/** Overrides the sort start value of the containing MatSort for this MatSortable. */
140146
@Input() start: 'asc' | 'desc';
@@ -182,6 +188,9 @@ export class MatSortHeader
182188
private _elementRef: ElementRef<HTMLElement>,
183189
/** @breaking-change 14.0.0 _ariaDescriber will be required. */
184190
@Optional() private _ariaDescriber?: AriaDescriber | null,
191+
@Optional()
192+
@Inject(MAT_SORT_DEFAULT_OPTIONS)
193+
defaultOptions?: MatSortDefaultOptions,
185194
) {
186195
// Note that we use a string token for the `_columnDef`, because the value is provided both by
187196
// `material/table` and `cdk/table` and we can't have the CDK depending on Material,
@@ -193,6 +202,10 @@ export class MatSortHeader
193202
throw getSortHeaderNotContainedWithinSortError();
194203
}
195204

205+
if (defaultOptions?.arrowPosition) {
206+
this.arrowPosition = defaultOptions?.arrowPosition;
207+
}
208+
196209
this._handleStateChanges();
197210
}
198211

src/material/sort/sort.spec.ts

Lines changed: 136 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ describe('MatSort', () => {
4545
MatSortDuplicateMatSortableIdsApp,
4646
MatSortableMissingIdApp,
4747
MatSortableInvalidDirection,
48+
MatSortableInvalidDirection,
49+
MatSortWithArrowPosition,
4850
],
4951
}).compileComponents();
5052
}),
@@ -78,7 +80,6 @@ describe('MatSort', () => {
7880
const cdkTableMatSortAppFixture = TestBed.createComponent(CdkTableMatSortApp);
7981
const cdkTableMatSortAppComponent = cdkTableMatSortAppFixture.componentInstance;
8082

81-
cdkTableMatSortAppFixture.detectChanges();
8283
cdkTableMatSortAppFixture.detectChanges();
8384

8485
const sortables = cdkTableMatSortAppComponent.matSort.sortables;
@@ -92,7 +93,6 @@ describe('MatSort', () => {
9293
const matTableMatSortAppFixture = TestBed.createComponent(MatTableMatSortApp);
9394
const matTableMatSortAppComponent = matTableMatSortAppFixture.componentInstance;
9495

95-
matTableMatSortAppFixture.detectChanges();
9696
matTableMatSortAppFixture.detectChanges();
9797

9898
const sortables = matTableMatSortAppComponent.matSort.sortables;
@@ -439,6 +439,64 @@ describe('MatSort', () => {
439439
descriptionElement = document.getElementById(descriptionId);
440440
expect(descriptionElement?.textContent).toBe('Sort 2nd column');
441441
});
442+
443+
it('should render arrows after sort header by default', () => {
444+
const matSortWithArrowPositionFixture = TestBed.createComponent(MatSortWithArrowPosition);
445+
446+
matSortWithArrowPositionFixture.detectChanges();
447+
448+
const containerA = matSortWithArrowPositionFixture.nativeElement.querySelector(
449+
'#defaultA .mat-sort-header-container',
450+
);
451+
const containerB = matSortWithArrowPositionFixture.nativeElement.querySelector(
452+
'#defaultB .mat-sort-header-container',
453+
);
454+
455+
expect(containerA.classList.contains('mat-sort-header-position-before')).toBe(false);
456+
expect(containerB.classList.contains('mat-sort-header-position-before')).toBe(false);
457+
});
458+
459+
it('should render arrows before if appropriate parameter passed', () => {
460+
const matSortWithArrowPositionFixture = TestBed.createComponent(MatSortWithArrowPosition);
461+
const matSortWithArrowPositionComponent = matSortWithArrowPositionFixture.componentInstance;
462+
matSortWithArrowPositionComponent.arrowPosition = 'before';
463+
464+
matSortWithArrowPositionFixture.detectChanges();
465+
466+
const containerA = matSortWithArrowPositionFixture.nativeElement.querySelector(
467+
'#defaultA .mat-sort-header-container',
468+
);
469+
const containerB = matSortWithArrowPositionFixture.nativeElement.querySelector(
470+
'#defaultB .mat-sort-header-container',
471+
);
472+
473+
expect(containerA.classList.contains('mat-sort-header-position-before')).toBe(true);
474+
expect(containerB.classList.contains('mat-sort-header-position-before')).toBe(true);
475+
});
476+
477+
it('should render arrows in proper position based on arrowPosition parameter', () => {
478+
const matSortWithArrowPositionFixture = TestBed.createComponent(MatSortWithArrowPosition);
479+
const matSortWithArrowPositionComponent = matSortWithArrowPositionFixture.componentInstance;
480+
481+
matSortWithArrowPositionFixture.detectChanges();
482+
483+
const containerA = matSortWithArrowPositionFixture.nativeElement.querySelector(
484+
'#defaultA .mat-sort-header-container',
485+
);
486+
const containerB = matSortWithArrowPositionFixture.nativeElement.querySelector(
487+
'#defaultB .mat-sort-header-container',
488+
);
489+
490+
expect(containerA.classList.contains('mat-sort-header-position-before')).toBe(false);
491+
expect(containerB.classList.contains('mat-sort-header-position-before')).toBe(false);
492+
493+
matSortWithArrowPositionComponent.arrowPosition = 'before';
494+
495+
matSortWithArrowPositionFixture.detectChanges();
496+
497+
expect(containerA.classList.contains('mat-sort-header-position-before')).toBe(true);
498+
expect(containerB.classList.contains('mat-sort-header-position-before')).toBe(true);
499+
});
442500
});
443501

444502
describe('with default options', () => {
@@ -477,6 +535,45 @@ describe('MatSort', () => {
477535
testSingleColumnSortDirectionSequence(fixture, ['desc', 'asc']);
478536
});
479537
});
538+
539+
describe('with default arrowPosition', () => {
540+
let fixture: ComponentFixture<MatSortWithoutInputs>;
541+
542+
beforeEach(
543+
waitForAsync(() => {
544+
TestBed.configureTestingModule({
545+
imports: [MatSortModule, MatTableModule, CdkTableModule, NoopAnimationsModule],
546+
declarations: [MatSortWithoutInputs],
547+
providers: [
548+
{
549+
provide: MAT_SORT_DEFAULT_OPTIONS,
550+
useValue: {
551+
disableClear: true,
552+
arrowPosition: 'before',
553+
},
554+
},
555+
],
556+
}).compileComponents();
557+
}),
558+
);
559+
560+
beforeEach(() => {
561+
fixture = TestBed.createComponent(MatSortWithoutInputs);
562+
fixture.detectChanges();
563+
});
564+
565+
it('should render arrows in proper position', () => {
566+
const containerA = fixture.nativeElement.querySelector(
567+
'#defaultA .mat-sort-header-container',
568+
);
569+
const containerB = fixture.nativeElement.querySelector(
570+
'#defaultB .mat-sort-header-container',
571+
);
572+
573+
expect(containerA.classList.contains('mat-sort-header-position-before')).toBe(true);
574+
expect(containerB.classList.contains('mat-sort-header-position-before')).toBe(true);
575+
});
576+
});
480577
});
481578

482579
/**
@@ -736,3 +833,40 @@ class MatSortWithoutExplicitInputs {
736833
dispatchMouseEvent(sortElement, event);
737834
}
738835
}
836+
837+
@Component({
838+
template: `
839+
<div matSort>
840+
<div id="defaultA" #defaultA mat-sort-header="defaultA" [arrowPosition]="arrowPosition">
841+
A
842+
</div>
843+
<div id="defaultB" #defaultB mat-sort-header="defaultB" [arrowPosition]="arrowPosition">
844+
B
845+
</div>
846+
</div>
847+
`,
848+
})
849+
class MatSortWithArrowPosition {
850+
arrowPosition?: 'before' | 'after';
851+
@ViewChild(MatSort) matSort: MatSort;
852+
@ViewChild('defaultA') defaultA: MatSortHeader;
853+
@ViewChild('defaultB') defaultB: MatSortHeader;
854+
}
855+
856+
@Component({
857+
template: `
858+
<div matSort>
859+
<div id="defaultA" #defaultA mat-sort-header="defaultA">
860+
A
861+
</div>
862+
<div id="defaultB" #defaultB mat-sort-header="defaultB">
863+
B
864+
</div>
865+
</div>
866+
`,
867+
})
868+
class MatSortWithoutInputs {
869+
@ViewChild(MatSort) matSort: MatSort;
870+
@ViewChild('defaultA') defaultA: MatSortHeader;
871+
@ViewChild('defaultB') defaultB: MatSortHeader;
872+
}

src/material/sort/sort.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ import {
2828
getSortInvalidDirectionError,
2929
} from './sort-errors';
3030

31+
/** Position of the arrow that displays when sorted. */
32+
export type SortHeaderArrowPosition = 'before' | 'after';
33+
3134
/** Interface for a directive that holds sorting state consumed by `MatSortHeader`. */
3235
export interface MatSortable {
3336
/** The id of the column being sorted. */
@@ -53,6 +56,8 @@ export interface Sort {
5356
export interface MatSortDefaultOptions {
5457
/** Whether to disable clearing the sorting state. */
5558
disableClear?: boolean;
59+
/** Position of the arrow that displays when sorted. */
60+
arrowPosition?: SortHeaderArrowPosition;
5661
}
5762

5863
/** Injection token to be used to override the default options for `mat-sort`. */

tools/public_api_guard/material/sort.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,16 +97,17 @@ export const matSortAnimations: {
9797

9898
// @public
9999
export interface MatSortDefaultOptions {
100+
arrowPosition?: SortHeaderArrowPosition;
100101
disableClear?: boolean;
101102
}
102103

103104
// @public
104105
export class MatSortHeader extends _MatSortHeaderBase implements CanDisable, MatSortable, OnDestroy, OnInit, AfterViewInit {
105106
constructor(
106107
_intl: MatSortHeaderIntl, _changeDetectorRef: ChangeDetectorRef, _sort: MatSort, _columnDef: MatSortHeaderColumnDef, _focusMonitor: FocusMonitor, _elementRef: ElementRef<HTMLElement>,
107-
_ariaDescriber?: AriaDescriber | null | undefined);
108+
_ariaDescriber?: AriaDescriber | null | undefined, defaultOptions?: MatSortDefaultOptions);
108109
_arrowDirection: SortDirection;
109-
arrowPosition: 'before' | 'after';
110+
arrowPosition: SortHeaderArrowPosition;
110111
// (undocumented)
111112
_columnDef: MatSortHeaderColumnDef;
112113
get disableClear(): boolean;
@@ -146,7 +147,7 @@ export class MatSortHeader extends _MatSortHeaderBase implements CanDisable, Mat
146147
// (undocumented)
147148
static ɵcmp: i0.ɵɵComponentDeclaration<MatSortHeader, "[mat-sort-header]", ["matSortHeader"], { "disabled": "disabled"; "id": "mat-sort-header"; "arrowPosition": "arrowPosition"; "start": "start"; "sortActionDescription": "sortActionDescription"; "disableClear": "disableClear"; }, {}, never, ["*"]>;
148149
// (undocumented)
149-
static ɵfac: i0.ɵɵFactoryDeclaration<MatSortHeader, [null, null, { optional: true; }, { optional: true; }, null, null, { optional: true; }]>;
150+
static ɵfac: i0.ɵɵFactoryDeclaration<MatSortHeader, [null, null, { optional: true; }, { optional: true; }, null, null, { optional: true; }, { optional: true; }]>;
150151
}
151152

152153
// @public
@@ -177,6 +178,9 @@ export interface Sort {
177178
// @public
178179
export type SortDirection = 'asc' | 'desc' | '';
179180

181+
// @public
182+
export type SortHeaderArrowPosition = 'before' | 'after';
183+
180184
// (No @packageDocumentation comment for this package)
181185

182186
```

0 commit comments

Comments
 (0)