-
Notifications
You must be signed in to change notification settings - Fork 6.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(stepper): Support additional properties for step #6509
Changes from 5 commits
af7d725
1bd2486
81eee36
edd0a03
b214f70
a1f1977
ec3993a
c8a71f4
1a5af09
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/** | ||
* @license | ||
* Copyright Google Inc. All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import {Directive, Input} from '@angular/core'; | ||
import {CdkStep} from './stepper'; | ||
|
||
@Directive({ | ||
selector: 'cdkStepIcon' | ||
}) | ||
export class CdkStepIcon { | ||
/** Step of the icon to be displayed. */ | ||
@Input() | ||
step: CdkStep; | ||
|
||
/** Whether the step of the icon to be displayed is active. */ | ||
@Input() | ||
selected: boolean; | ||
|
||
/** Index of the step. */ | ||
@Input() | ||
index: number; | ||
|
||
/** Whether the user has touched the step that is not selected. */ | ||
get notTouched() { | ||
return this._getIndicatorType() == 'number' && !this.selected; | ||
} | ||
|
||
/** Returns the type of icon to be displayed. */ | ||
_getIndicatorType(): 'number' | 'edit' | 'done' { | ||
if (!this.step.completed || this.selected) { | ||
return 'number'; | ||
} else { | ||
return this.step.editable ? 'edit' : 'done'; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/** | ||
* @license | ||
* Copyright Google Inc. All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import {Directive, Input} from '@angular/core'; | ||
import {CdkStep} from './stepper'; | ||
|
||
@Directive({ | ||
selector: 'cdkStepLabelContainer' | ||
}) | ||
export class CdkStepLabelContainer { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also don't see a need for a cdk version of this |
||
/** Step of the label to be displayed. */ | ||
@Input() | ||
step: CdkStep; | ||
|
||
/** Whether the step of label to be displayed is selected. */ | ||
@Input() | ||
selected: boolean; | ||
|
||
/** Whether the label to be displayed is active. */ | ||
get active() { | ||
return this.step.completed || this.selected; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -77,6 +77,35 @@ export class CdkStep { | |
@Input() | ||
label: string; | ||
|
||
@Input() | ||
get editable() { return this._editable; } | ||
set editable(value: any) { | ||
this._editable = coerceBooleanProperty(value); | ||
} | ||
private _editable = true; | ||
|
||
/** Whether the completion of step is optional or not. */ | ||
@Input() | ||
get optional() { return this._optional; } | ||
set optional(value: any) { | ||
this._optional = coerceBooleanProperty(value); | ||
} | ||
private _optional = false; | ||
|
||
/** Return whether step is completed or not. */ | ||
@Input() | ||
get completed() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm I wonder if this is something we want to give the user control of by making it an @jelbourn WDYT of something like this: @Input()
get completed() {
return this._customCompleted == null ? this._defaultCompleted : this._customCompleted;
}
set completed(value) {
this._customCompleted = value == null ? null : coerceBooleanProperty(value);
}
private _customCompleted: boolean | null = null;
private get _defaultCompleted() {
return this._stepControl ? this._stepControl.valid && this.interacted : this.interacted;
} This way most users could use the default completeness behavior, but they could still override if they want There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems reasonable, though |
||
return this._customCompleted == null ? this._defaultCompleted : this._customCompleted; | ||
} | ||
set completed(value: any) { | ||
this._customCompleted = coerceBooleanProperty(value); | ||
} | ||
private _customCompleted: boolean | null = null; | ||
|
||
private get _defaultCompleted() { | ||
return this._stepControl ? this._stepControl.valid && this.interacted : this.interacted; | ||
} | ||
|
||
constructor(private _stepper: CdkStepper) { } | ||
|
||
/** Selects this step component. */ | ||
|
@@ -109,6 +138,7 @@ export class CdkStepper { | |
@Input() | ||
get selectedIndex() { return this._selectedIndex; } | ||
set selectedIndex(index: number) { | ||
if (index < this._selectedIndex && !this._steps.toArray()[index].editable) { return; } | ||
if (this._anyControlsInvalid(index)) { | ||
// remove focus from clicked step header if the step is not able to be selected | ||
this._stepHeader.toArray()[index].nativeElement.blur(); | ||
|
@@ -211,7 +241,7 @@ export class CdkStepper { | |
const stepsArray = this._steps.toArray(); | ||
stepsArray[this._selectedIndex].interacted = true; | ||
if (this._linear) { | ||
return stepsArray.slice(0, index).some(step => step.stepControl.invalid); | ||
return stepsArray.slice(0, index).some(step => step.stepControl.invalid && !step.optional); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This makes sense if you're thinking about the step being invalid due to a required field not being filled out, but it makes less sense if you consider invalid for other reasons (e.g. entering "1234" as your email). Need to think more about what the right behavior for optional is... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mmalerba Do you mean that if the step is optional but the field is invalid due to some other reason, the user shouldn't be able to move on? If it is optional, shouldn't the user be able to move on even if the input is not valid? The field will still fire an error, so the user will still be aware that the input is invalid as they move on. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think if its optional they should be able to skip it, not enter invalid input |
||
} | ||
return false; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<div [ngSwitch]="_getIndicatorType()"> | ||
<span *ngSwitchCase="'number'">{{index + 1}}</span> | ||
<md-icon *ngSwitchCase="'edit'">create</md-icon> | ||
<md-icon *ngSwitchCase="'done'">done</md-icon> | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this needs a cdk version, the icon is a material design specific piece of UI