Skip to content

Commit 44be2e3

Browse files
committed
Additional properties for step
1 parent 90babef commit 44be2e3

File tree

8 files changed

+90
-32
lines changed

8 files changed

+90
-32
lines changed

src/cdk/stepper/stepper.ts

+22-1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,26 @@ export class CdkStep {
7777
@Input()
7878
label: string;
7979

80+
@Input()
81+
get editable() { return this._editable; }
82+
set editable(value: any) {
83+
this._editable = coerceBooleanProperty(value);
84+
}
85+
private _editable = true;
86+
87+
/** Whether the completion of step is optional or not. */
88+
@Input()
89+
get optional() { return this._optional; }
90+
set optional(value: any) {
91+
this._optional = coerceBooleanProperty(value);
92+
}
93+
private _optional = false;
94+
95+
/** Return whether step is completed or not. */
96+
get completed() {
97+
return this._stepControl ? this._stepControl.valid && this.interacted : this.interacted;
98+
}
99+
80100
constructor(private _stepper: CdkStepper) { }
81101

82102
/** Selects this step component. */
@@ -109,6 +129,7 @@ export class CdkStepper {
109129
@Input()
110130
get selectedIndex() { return this._selectedIndex; }
111131
set selectedIndex(index: number) {
132+
if (index < this._selectedIndex && !this._steps.toArray()[index].editable) { return; }
112133
if (this._selectedIndex != index && !this._anyControlsInvalid(index)) {
113134
this._emitStepperSelectionEvent(index);
114135
this._focusStep(this._selectedIndex);
@@ -208,7 +229,7 @@ export class CdkStepper {
208229
const stepsArray = this._steps.toArray();
209230
stepsArray[this._selectedIndex].interacted = true;
210231
if (this._linear) {
211-
return stepsArray.slice(0, index).some(step => step.stepControl.invalid);
232+
return stepsArray.slice(0, index).some(step => step.stepControl.invalid && !step.optional);
212233
}
213234
return false;
214235
}

src/demo-app/stepper/stepper-demo.html

+6-13
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ <h3>Linear Vertical Stepper Demo using a single form</h3>
1919
</div>
2020
</md-step>
2121

22-
<md-step formGroupName="1" [stepControl]="formArray.get([1])">
22+
<md-step formGroupName="1" [stepControl]="formArray.get([1])" [optional]="true">
2323
<ng-template mdStepLabel>
2424
<div>Fill out your phone number</div>
2525
</ng-template>
2626
<md-input-container>
27-
<input mdInput placeholder="Phone number" formControlName="phoneFormCtrl">
27+
<input mdInput placeholder="Phone number" formControlName="phoneFormCtrl" required>
2828
<md-error>This field is required</md-error>
2929
</md-input-container>
3030
<div>
@@ -88,44 +88,41 @@ <h3>Linear Horizontal Stepper Demo using a different form for each step</h3>
8888
</md-horizontal-stepper>
8989

9090
<h3>Vertical Stepper Demo</h3>
91+
<md-checkbox [(ngModel)]="isNonEditable">Make steps non-editable</md-checkbox>
9192
<md-vertical-stepper>
92-
<md-step>
93+
<md-step [editable]="!isNonEditable">
9394
<ng-template mdStepLabel>Fill out your name</ng-template>
9495
<md-form-field>
9596
<input mdInput placeholder="First Name">
96-
<md-error>This field is required</md-error>
9797
</md-form-field>
9898

9999
<md-form-field>
100100
<input mdInput placeholder="Last Name">
101-
<md-error>This field is required</md-error>
102101
</md-form-field>
103102
<div>
104103
<button md-button mdStepperNext type="button">Next</button>
105104
</div>
106105
</md-step>
107106

108-
<md-step>
107+
<md-step [editable]="!isNonEditable">
109108
<ng-template mdStepLabel>
110109
<div>Fill out your phone number</div>
111110
</ng-template>
112111
<md-form-field>
113112
<input mdInput placeholder="Phone number">
114-
<md-error>This field is required</md-error>
115113
</md-form-field>
116114
<div>
117115
<button md-button mdStepperPrevious type="button">Back</button>
118116
<button md-button mdStepperNext type="button">Next</button>
119117
</div>
120118
</md-step>
121119

122-
<md-step>
120+
<md-step [editable]="!isNonEditable">
123121
<ng-template mdStepLabel>
124122
<div>Fill out your address</div>
125123
</ng-template>
126124
<md-form-field>
127125
<input mdInput placeholder="Address">
128-
<md-error>This field is required</md-error>
129126
</md-form-field>
130127
<div>
131128
<button md-button mdStepperPrevious type="button">Back</button>
@@ -148,12 +145,10 @@ <h3>Horizontal Stepper Demo</h3>
148145
<ng-template mdStepLabel>Fill out your name</ng-template>
149146
<md-form-field>
150147
<input mdInput placeholder="First Name">
151-
<md-error>This field is required</md-error>
152148
</md-form-field>
153149

154150
<md-form-field>
155151
<input mdInput placeholder="Last Name">
156-
<md-error>This field is required</md-error>
157152
</md-form-field>
158153
<div>
159154
<button md-button mdStepperNext type="button">Next</button>
@@ -166,7 +161,6 @@ <h3>Horizontal Stepper Demo</h3>
166161
</ng-template>
167162
<md-form-field>
168163
<input mdInput placeholder="Phone number">
169-
<md-error>This field is required</md-error>
170164
</md-form-field>
171165
<div>
172166
<button md-button mdStepperPrevious type="button">Back</button>
@@ -180,7 +174,6 @@ <h3>Horizontal Stepper Demo</h3>
180174
</ng-template>
181175
<md-form-field>
182176
<input mdInput placeholder="Address">
183-
<md-error>This field is required</md-error>
184177
</md-form-field>
185178
<div>
186179
<button md-button mdStepperPrevious type="button">Back</button>

src/demo-app/stepper/stepper-demo.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {FormBuilder, FormGroup, Validators} from '@angular/forms';
1010
export class StepperDemo {
1111
formGroup: FormGroup;
1212
isNonLinear = false;
13+
isNonEditable = false;
1314

1415
nameFormGroup: FormGroup;
1516
phoneFormGroup: FormGroup;
@@ -34,7 +35,7 @@ export class StepperDemo {
3435
lastNameFormCtrl: ['', Validators.required],
3536
}),
3637
this._formBuilder.group({
37-
phoneFormCtrl: [''],
38+
phoneFormCtrl: ['', Validators.required],
3839
})
3940
])
4041
});

src/lib/stepper/_stepper-theme.scss

+9-3
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@
99

1010
.mat-horizontal-stepper-header, .mat-vertical-stepper-header {
1111

12-
.mat-stepper-label {
12+
.mat-stepper-label-active {
1313
color: mat-color($foreground, text);
1414
}
1515

16-
.mat-stepper-index {
16+
.mat-stepper-label-inactive,
17+
.mat-step-optional {
18+
color: mat-color($foreground, disabled-text);
19+
}
20+
21+
.mat-stepper-index-interacted,
22+
.mat-stepper-index-new {
1723
background-color: mat-color($primary);
1824
color: mat-color($primary, default-contrast);
1925
}
@@ -23,7 +29,7 @@
2329
color: mat-color($foreground, disabled-text);
2430
}
2531

26-
.mat-stepper-index {
32+
.mat-stepper-index-new {
2733
background-color: mat-color($foreground, disabled-text);
2834
}
2935
}

src/lib/stepper/index.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,17 @@ import {CdkStepperModule} from '@angular/cdk/stepper';
1717
import {MdCommonModule} from '../core';
1818
import {MdStepLabel} from './step-label';
1919
import {MdStepperNext, MdStepperPrevious} from './stepper-button';
20+
import {MdIconModule} from '../icon/index';
2021

2122
@NgModule({
22-
imports: [MdCommonModule, CommonModule, PortalModule, MdButtonModule, CdkStepperModule],
23+
imports: [
24+
MdCommonModule,
25+
CommonModule,
26+
PortalModule,
27+
MdButtonModule,
28+
CdkStepperModule,
29+
MdIconModule
30+
],
2331
exports: [MdCommonModule, MdHorizontalStepper, MdVerticalStepper, MdStep, MdStepLabel, MdStepper,
2432
MdStepperNext, MdStepperPrevious],
2533
declarations: [MdHorizontalStepper, MdVerticalStepper, MdStep, MdStepLabel, MdStepper,

src/lib/stepper/stepper-horizontal.html

+11-2
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,25 @@
88
[tabIndex]="_focusIndex == i ? 0 : -1"
99
(click)="step.select()"
1010
(keydown)="_onKeydown($event)">
11-
<div class="mat-stepper-index">
11+
<div class="mat-stepper-index-new" *ngIf="!step.completed || selectedIndex == i">
1212
{{i + 1}}
1313
</div>
14+
<div class="mat-stepper-index-interacted" *ngIf="step.completed && selectedIndex != i">
15+
<md-icon *ngIf="!step.editable">done</md-icon>
16+
<md-icon *ngIf="step.editable">create</md-icon>
17+
</div>
1418

15-
<div class="mat-stepper-label">
19+
<div [ngClass]="{
20+
'mat-stepper-label-active': step.completed || selectedIndex == i,
21+
'mat-stepper-label-inactive': !step.completed && selectedIndex != i
22+
}">
1623
<!-- If there is a label template, use it. -->
1724
<ng-container *ngIf="step.stepLabel" [ngTemplateOutlet]="step.stepLabel.template">
1825
</ng-container>
1926
<!-- It there is no label template, fall back to the text label. -->
2027
<div *ngIf="!step.stepLabel">{{step.label}}</div>
28+
29+
<div class="mat-step-optional" *ngIf="step.optional">Optional</div>
2130
</div>
2231
</div>
2332

src/lib/stepper/stepper-vertical.html

+12-3
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,28 @@
66
[tabIndex]="_focusIndex == i ? 0 : -1"
77
(click)="step.select()"
88
(keydown)="_onKeydown($event)">
9-
<div class="mat-stepper-index">
9+
<div class="mat-stepper-index-new" *ngIf="!step.completed || selectedIndex == i">
1010
{{i + 1}}
1111
</div>
12+
<div class="mat-stepper-index-interacted" *ngIf="step.completed && selectedIndex != i">
13+
<md-icon *ngIf="!step.editable">done</md-icon>
14+
<md-icon *ngIf="step.editable">create</md-icon>
15+
</div>
1216

13-
<div class="mat-stepper-label">
17+
<div [ngClass]="{
18+
'mat-stepper-label-active': step.completed || selectedIndex == i,
19+
'mat-stepper-label-inactive': !step.completed && selectedIndex != i
20+
}">
1421
<!-- If there is a label template, use it. -->
1522
<ng-container *ngIf="step.stepLabel"[ngTemplateOutlet]="step.stepLabel.template">
1623
</ng-container>
1724
<!-- It there is no label template, fall back to the text label. -->
1825
<div *ngIf="!step.stepLabel">{{step.label}}</div>
19-
</div>
2026

27+
<div class="mat-step-optional" *ngIf="step.optional">Optional</div>
28+
</div>
2129
</div>
30+
2231
<div class="mat-vertical-content-container">
2332
<div class="mat-vertical-stepper-content" role="tabpanel"
2433
[@stepTransition]="_getAnimationDirection(i)"

src/lib/stepper/stepper.scss

+19-8
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,32 @@ $mat-connector-line-width: 1px !default;
1111
$mat-connector-line-gap: 8px !default;
1212
$mat-horizontal-connector-line-size: 5% !default;
1313
$mat-vertical-stepper-margin-top: $mat-stepper-side-gap - $mat-connector-line-gap !default;
14+
$mat-step-optional-label-font-size: 12px;
1415

1516
:host {
1617
display: block;
1718
padding: 0 $mat-stepper-side-gap $mat-stepper-side-gap $mat-stepper-side-gap;
1819
}
1920

20-
.mat-stepper-label {
21-
display: inline-flex;
21+
.mat-stepper-label-active,
22+
.mat-stepper-label-inactive {
23+
display: inline-block;
2224
white-space: nowrap;
2325
overflow: hidden;
2426
// TODO(jwshin): text-overflow does not work as expected.
2527
text-overflow: ellipsis;
2628
min-width: $mat-stepper-label-min-width;
29+
vertical-align: middle;
2730
}
2831

29-
.mat-stepper-index {
32+
.mat-stepper-index-new ,
33+
.mat-stepper-index-interacted {
3034
border-radius: 50%;
3135
height: $mat-label-header-height;
3236
width: $mat-label-header-height;
3337
text-align: center;
3438
line-height: $mat-label-header-height;
39+
display: inline-block;
3540
}
3641

3742
.mat-horizontal-stepper-header-container {
@@ -41,15 +46,15 @@ $mat-vertical-stepper-margin-top: $mat-stepper-side-gap - $mat-connector-line-ga
4146
}
4247

4348
.mat-horizontal-stepper-header {
44-
display: inline-flex;
45-
line-height: $mat-horizontal-stepper-header-height;
49+
display: flex;
50+
height: $mat-horizontal-stepper-header-height;
4651
overflow: hidden;
4752
align-items: center;
4853
outline: none;
4954

50-
.mat-stepper-index {
55+
.mat-stepper-index-new ,
56+
.mat-stepper-index-interacted {
5157
margin-right: $mat-connector-line-gap;
52-
display: inline-block;
5358
flex: none;
5459
}
5560
}
@@ -59,12 +64,18 @@ $mat-vertical-stepper-margin-top: $mat-stepper-side-gap - $mat-connector-line-ga
5964
align-items: center;
6065
margin: $mat-connector-line-gap 0;
6166
outline: none;
67+
max-height: $mat-label-header-height;
6268

63-
.mat-stepper-index {
69+
.mat-stepper-index-new ,
70+
.mat-stepper-index-interacted {
6471
margin-right: $mat-vertical-stepper-content-margin;
6572
}
6673
}
6774

75+
.mat-step-optional {
76+
font-size: $mat-step-optional-label-font-size;
77+
}
78+
6879
.mat-connector-line {
6980
border-top-width: $mat-connector-line-width;
7081
border-top-style: solid;

0 commit comments

Comments
 (0)