mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(stepper): allow number icon to be customized and expose template context variables (#10516)
* Allows for the step number icon to be overwritten using `matStepperIcon="number"`. * Exposes the `index`, `active` and `optional` template variables to `matStepperIcon`. Fixes #10513.
This commit is contained in:
committed by
Joey Perrott
parent
b8bb62f30b
commit
946fd84a15
@@ -3,15 +3,27 @@
|
||||
[class.mat-step-icon-not-touched]="state == 'number' && !selected"
|
||||
[ngSwitch]="state">
|
||||
|
||||
<span *ngSwitchCase="'number'">{{index + 1}}</span>
|
||||
<ng-container *ngSwitchCase="'number'" [ngSwitch]="!!(iconOverrides && iconOverrides.number)">
|
||||
<ng-container
|
||||
*ngSwitchCase="true"
|
||||
[ngTemplateOutlet]="iconOverrides.number"
|
||||
[ngTemplateOutletContext]="_getIconContext()"></ng-container>
|
||||
<span *ngSwitchDefault>{{index + 1}}</span>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'edit'" [ngSwitch]="!!(iconOverrides && iconOverrides.edit)">
|
||||
<ng-container *ngSwitchCase="true" [ngTemplateOutlet]="iconOverrides.edit"></ng-container>
|
||||
<ng-container
|
||||
*ngSwitchCase="true"
|
||||
[ngTemplateOutlet]="iconOverrides.edit"
|
||||
[ngTemplateOutletContext]="_getIconContext()"></ng-container>
|
||||
<mat-icon *ngSwitchDefault>create</mat-icon>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'done'" [ngSwitch]="!!(iconOverrides && iconOverrides.done)">
|
||||
<ng-container *ngSwitchCase="true" [ngTemplateOutlet]="iconOverrides.done"></ng-container>
|
||||
<ng-container
|
||||
*ngSwitchCase="true"
|
||||
[ngTemplateOutlet]="iconOverrides.done"
|
||||
[ngTemplateOutletContext]="_getIconContext()"></ng-container>
|
||||
<mat-icon *ngSwitchDefault>done</mat-icon>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
import {Subscription} from 'rxjs';
|
||||
import {MatStepLabel} from './step-label';
|
||||
import {MatStepperIntl} from './stepper-intl';
|
||||
import {MatStepperIconContext} from './stepper-icon';
|
||||
|
||||
|
||||
@Component({
|
||||
@@ -44,7 +45,7 @@ export class MatStepHeader implements OnDestroy {
|
||||
@Input() label: MatStepLabel | string;
|
||||
|
||||
/** Overrides for the header icons, passed in via the stepper. */
|
||||
@Input() iconOverrides: {[key: string]: TemplateRef<any>};
|
||||
@Input() iconOverrides: {[key: string]: TemplateRef<MatStepperIconContext>};
|
||||
|
||||
/** Index of the given step. */
|
||||
@Input() index: number;
|
||||
@@ -87,6 +88,15 @@ export class MatStepHeader implements OnDestroy {
|
||||
return this._element.nativeElement;
|
||||
}
|
||||
|
||||
/** Template context variables that are exposed to the `matStepperIcon` instances. */
|
||||
_getIconContext(): MatStepperIconContext {
|
||||
return {
|
||||
index: this.index,
|
||||
active: this.active,
|
||||
optional: this.optional
|
||||
};
|
||||
}
|
||||
|
||||
focus() {
|
||||
this._getHostElement().focus();
|
||||
}
|
||||
|
||||
@@ -8,6 +8,16 @@
|
||||
|
||||
import {Directive, Input, TemplateRef} from '@angular/core';
|
||||
|
||||
/** Template context available to an attached `matStepperIcon`. */
|
||||
export interface MatStepperIconContext {
|
||||
/** Index of the step. */
|
||||
index: number;
|
||||
/** Whether the step is currently active. */
|
||||
active: boolean;
|
||||
/** Whether the step is optional. */
|
||||
optional: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template to be used to override the icons inside the step header.
|
||||
*/
|
||||
@@ -16,7 +26,7 @@ import {Directive, Input, TemplateRef} from '@angular/core';
|
||||
})
|
||||
export class MatStepperIcon {
|
||||
/** Name of the icon to be overridden. */
|
||||
@Input('matStepperIcon') name: 'edit' | 'done';
|
||||
@Input('matStepperIcon') name: 'edit' | 'done' | 'number';
|
||||
|
||||
constructor(public templateRef: TemplateRef<any>) { }
|
||||
constructor(public templateRef: TemplateRef<MatStepperIconContext>) {}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,8 @@ this default `completed` behavior by setting the `completed` attribute as needed
|
||||
#### Overriding icons
|
||||
By default, the step headers will use the `create` and `done` icons from the Material design icon
|
||||
set via `<mat-icon>` elements. If you want to provide a different set of icons, you can do so
|
||||
by placing a `matStepperIcon` for each of the icons that you want to override:
|
||||
by placing a `matStepperIcon` for each of the icons that you want to override. The `index`,
|
||||
`active`, and `optional` values of the individual steps are available through template variables:
|
||||
|
||||
```html
|
||||
<mat-vertical-stepper>
|
||||
@@ -136,6 +137,11 @@ by placing a `matStepperIcon` for each of the icons that you want to override:
|
||||
<mat-icon>done_all</mat-icon>
|
||||
</ng-template>
|
||||
|
||||
<!-- Custom icon with a context variable. -->
|
||||
<ng-template matStepperIcon="number" let-index="index">
|
||||
{{index + 10}}
|
||||
</ng-template>
|
||||
|
||||
<!-- Stepper steps go here -->
|
||||
</mat-vertical-stepper>
|
||||
```
|
||||
|
||||
@@ -354,6 +354,13 @@ describe('MatStepper', () => {
|
||||
|
||||
expect(header.textContent).toContain('Custom done');
|
||||
});
|
||||
|
||||
it('should allow for the `number` icon to be overridden with context', () => {
|
||||
const stepperDebugElement = fixture.debugElement.query(By.directive(MatStepper));
|
||||
const headers = stepperDebugElement.nativeElement.querySelectorAll('mat-step-header');
|
||||
|
||||
expect(headers[2].textContent).toContain('III');
|
||||
});
|
||||
});
|
||||
|
||||
describe('RTL', () => {
|
||||
@@ -1025,6 +1032,9 @@ class SimpleStepperWithStepControlAndCompletedBinding {
|
||||
<mat-horizontal-stepper>
|
||||
<ng-template matStepperIcon="edit">Custom edit</ng-template>
|
||||
<ng-template matStepperIcon="done">Custom done</ng-template>
|
||||
<ng-template matStepperIcon="number" let-index="index">
|
||||
{{getRomanNumeral(index + 1)}}
|
||||
</ng-template>
|
||||
|
||||
<mat-step>Content 1</mat-step>
|
||||
<mat-step>Content 2</mat-step>
|
||||
@@ -1032,7 +1042,21 @@ class SimpleStepperWithStepControlAndCompletedBinding {
|
||||
</mat-horizontal-stepper>
|
||||
`
|
||||
})
|
||||
class IconOverridesStepper {}
|
||||
class IconOverridesStepper {
|
||||
getRomanNumeral(value: number) {
|
||||
return {
|
||||
1: 'I',
|
||||
2: 'II',
|
||||
3: 'III',
|
||||
4: 'IV',
|
||||
5: 'V',
|
||||
6: 'VI',
|
||||
7: 'VII',
|
||||
8: 'VIII',
|
||||
9: 'IX'
|
||||
}[value];
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
|
||||
@@ -31,7 +31,7 @@ import {MatStepHeader} from './step-header';
|
||||
import {MatStepLabel} from './step-label';
|
||||
import {takeUntil} from 'rxjs/operators';
|
||||
import {matStepperAnimations} from './stepper-animations';
|
||||
import {MatStepperIcon} from './stepper-icon';
|
||||
import {MatStepperIcon, MatStepperIconContext} from './stepper-icon';
|
||||
|
||||
/** Workaround for https://github.com/angular/angular/issues/17849 */
|
||||
export const _MatStep = CdkStep;
|
||||
@@ -83,20 +83,18 @@ export class MatStepper extends CdkStepper implements AfterContentInit {
|
||||
@ContentChildren(MatStepperIcon) _icons: QueryList<MatStepperIcon>;
|
||||
|
||||
/** Consumer-specified template-refs to be used to override the header icons. */
|
||||
_iconOverrides: {[key: string]: TemplateRef<any>} = {};
|
||||
_iconOverrides: {[key: string]: TemplateRef<MatStepperIconContext>} = {};
|
||||
|
||||
ngAfterContentInit() {
|
||||
const icons = this._icons.toArray();
|
||||
const editOverride = icons.find(icon => icon.name === 'edit');
|
||||
const doneOverride = icons.find(icon => icon.name === 'done');
|
||||
|
||||
if (editOverride) {
|
||||
this._iconOverrides.edit = editOverride.templateRef;
|
||||
}
|
||||
['edit', 'done', 'number'].forEach(name => {
|
||||
const override = icons.find(icon => icon.name === name);
|
||||
|
||||
if (doneOverride) {
|
||||
this._iconOverrides.done = doneOverride.templateRef;
|
||||
}
|
||||
if (override) {
|
||||
this._iconOverrides[name] = override.templateRef;
|
||||
}
|
||||
});
|
||||
|
||||
// Mark the component for change detection whenever the content children query changes
|
||||
this._steps.changes.pipe(takeUntil(this._destroyed)).subscribe(() => this._stateChanged());
|
||||
|
||||
Reference in New Issue
Block a user