Skip to content

Commit 2cb745e

Browse files
committed
feat(select): support disabling
1 parent 83f6efc commit 2cb745e

File tree

11 files changed

+307
-38
lines changed

11 files changed

+307
-38
lines changed

src/demo-app/select/select-demo.html

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,30 @@
11
<div class="demo-select">
2-
<md-select placeholder="Food" [formControl]="control" [required]="isRequired">
3-
<md-option *ngFor="let food of foods" [value]="food.value"> {{ food.viewValue }} </md-option>
4-
</md-select>
5-
<p> Value: {{ control.value }} </p>
6-
<p> Touched: {{ control.touched }} </p>
7-
<p> Dirty: {{ control.dirty }} </p>
8-
<p> Status: {{ control.status }} </p>
9-
<button md-button (click)="control.setValue('pizza-1')">SET VALUE</button>
10-
<button md-button (click)="isRequired=!isRequired">TOGGLE REQUIRED</button>
2+
<md-card>
3+
<md-select placeholder="Food" [formControl]="foodControl">
4+
<md-option *ngFor="let food of foods" [value]="food.value"> {{ food.viewValue }} </md-option>
5+
</md-select>
6+
<p> Value: {{ foodControl.value }} </p>
7+
<p> Touched: {{ foodControl.touched }} </p>
8+
<p> Dirty: {{ foodControl.dirty }} </p>
9+
<p> Status: {{ foodControl.status }} </p>
10+
<button md-button (click)="foodControl.setValue('pizza-1')">SET VALUE</button>
11+
<button md-button (click)="toggleDisabled()">TOGGLE DISABLED</button>
12+
</md-card>
13+
14+
<md-card>
15+
<md-select placeholder="Drink" [(ngModel)]="currentDrink" [required]="isRequired" [disabled]="isDisabled"
16+
#drinkControl="ngModel">
17+
<md-option *ngFor="let drink of drinks" [value]="drink.value" [disabled]="drink.disabled">
18+
{{ drink.viewValue }}
19+
</md-option>
20+
</md-select>
21+
<p> Value: {{ currentDrink }} </p>
22+
<p> Touched: {{ drinkControl.touched }} </p>
23+
<p> Dirty: {{ drinkControl.dirty }} </p>
24+
<p> Status: {{ drinkControl.control?.status }} </p>
25+
<button md-button (click)="currentDrink='sprite-1'">SET VALUE</button>
26+
<button md-button (click)="isRequired=!isRequired">TOGGLE REQUIRED</button>
27+
<button md-button (click)="isDisabled=!isDisabled">TOGGLE DISABLED</button>
28+
</md-card>
29+
1130
</div>

src/demo-app/select/select-demo.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,10 @@
11
.demo-select {
2+
display: flex;
3+
flex-flow: row wrap;
4+
5+
md-card {
6+
width: 450px;
7+
margin: 24px;
8+
}
9+
210
}

src/demo-app/select/select-demo.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,24 @@ import {FormControl} from '@angular/forms';
99
})
1010
export class SelectDemo {
1111
isRequired = false;
12+
isDisabled = false;
1213

1314
foods = [
1415
{value: 'steak-0', viewValue: 'Steak'},
1516
{value: 'pizza-1', viewValue: 'Pizza'},
1617
{value: 'tacos-2', viewValue: 'Tacos'}
1718
];
1819

19-
control = new FormControl('');
20+
drinks = [
21+
{value: 'coke-0', viewValue: 'Coke'},
22+
{value: 'sprite-1', viewValue: 'Sprite', disabled: true},
23+
{value: 'water-2', viewValue: 'Water'}
24+
];
25+
26+
foodControl = new FormControl('');
27+
28+
toggleDisabled() {
29+
this.foodControl.enabled ? this.foodControl.disable() : this.foodControl.enable();
30+
}
2031

2132
}

src/lib/core/style/_form-common.scss

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
// Gradient for showing the dashed line when the input is disabled.
3+
$md-underline-disabled-background-image:
4+
linear-gradient(to right, rgba(0, 0, 0, 0.26) 0%, rgba(0, 0, 0, 0.26) 33%, transparent 0%);
5+
6+
@mixin md-control-disabled-underline {
7+
background-image: $md-underline-disabled-background-image;
8+
background-size: 4px 1px;
9+
background-repeat: repeat-x;
10+
}

src/lib/input/input.scss

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@import '../core/style/variables';
2+
@import '../core/style/form-common';
23

34

45
$md-input-floating-placeholder-scale-factor: 0.75 !default;
@@ -149,11 +150,9 @@ md-input, md-textarea {
149150
border-top-style: solid;
150151

151152
&.md-disabled {
153+
@include md-control-disabled-underline();
152154
border-top: 0;
153-
background-image: $md-input-underline-disabled-background-image;
154155
background-position: 0;
155-
background-size: 4px 1px;
156-
background-repeat: repeat-x;
157156
}
158157

159158
.md-input-ripple {

src/lib/select/_select-theme.scss

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
color: md-color($foreground, hint-text);
1212
border-bottom: 1px solid md-color($foreground, divider);
1313

14-
md-select:focus & {
14+
md-select:focus:not([aria-disabled='true']) & {
1515
color: md-color($primary);
1616
border-bottom: 1px solid md-color($primary);
1717
}
1818

19-
.ng-invalid.ng-touched & {
19+
.ng-invalid.ng-touched:not([aria-disabled='true']) & {
2020
color: md-color($warn);
2121
border-bottom: 1px solid md-color($warn);
2222
}
@@ -25,11 +25,11 @@
2525
.md-select-arrow {
2626
color: md-color($foreground, hint-text);
2727

28-
md-select:focus & {
28+
md-select:focus:not([aria-disabled='true']) & {
2929
color: md-color($primary);
3030
}
3131

32-
.ng-invalid.ng-touched & {
32+
.ng-invalid.ng-touched:not([aria-disabled='true']) & {
3333
color: md-color($warn);
3434
}
3535
}
@@ -40,10 +40,14 @@
4040

4141
.md-select-value {
4242
color: md-color($foreground, text);
43+
44+
[aria-disabled='true'] & {
45+
color: md-color($foreground, hint-text);
46+
}
4347
}
4448

4549
md-option {
46-
&:hover, &:focus {
50+
&:hover:not([aria-disabled='true']), &:focus:not([aria-disabled='true']) {
4751
background: md-color($background, hover);
4852
}
4953

@@ -52,5 +56,9 @@
5256
color: md-color($primary);
5357
}
5458

59+
&[aria-disabled='true'] {
60+
color: md-color($foreground, hint-text);
61+
}
62+
5563
}
5664
}

src/lib/select/option.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
<ng-content></ng-content>
2-
<div class="md-option-ripple" md-ripple md-ripple-background-color="rgba(0,0,0,0)"
2+
<div class="md-option-ripple" *ngIf="!disabled" md-ripple md-ripple-background-color="rgba(0,0,0,0)"
33
[md-ripple-trigger]="_getHostElement()"></div>

src/lib/select/option.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,17 @@ import {
88
ViewEncapsulation
99
} from '@angular/core';
1010
import {ENTER, SPACE} from '../core/keyboard/keycodes';
11+
import {coerceBooleanProperty} from '../core/coersion/boolean-property';
1112

1213
@Component({
1314
moduleId: module.id,
1415
selector: 'md-option',
1516
host: {
1617
'role': 'option',
17-
'tabindex': '0',
18+
'[attr.tabindex]': '_getTabIndex()',
1819
'[class.md-selected]': 'selected',
1920
'[attr.aria-selected]': 'selected.toString()',
21+
'[attr.aria-disabled]': 'disabled.toString()',
2022
'(click)': '_selectViaInteraction()',
2123
'(keydown)': '_handleKeydown($event)'
2224
},
@@ -25,11 +27,23 @@ import {ENTER, SPACE} from '../core/keyboard/keycodes';
2527
encapsulation: ViewEncapsulation.None
2628
})
2729
export class MdOption {
28-
private _selected = false;
30+
private _selected: boolean = false;
31+
32+
/** Whether the option is disabled. */
33+
private _disabled: boolean = false;
2934

3035
/** The form value of the option. */
3136
@Input() value: any;
3237

38+
@Input()
39+
get disabled() {
40+
return this._disabled;
41+
}
42+
43+
set disabled(value: any) {
44+
this._disabled = coerceBooleanProperty(value);
45+
}
46+
3347
/** Event emitted when the option is selected. */
3448
@Output() onSelect = new EventEmitter();
3549

@@ -72,13 +86,21 @@ export class MdOption {
7286
}
7387
}
7488

89+
7590
/**
7691
* Selects the option while indicating the selection came from the user. Used to
7792
* determine if the select's view -> model callback should be invoked.
7893
*/
7994
_selectViaInteraction() {
80-
this._selected = true;
81-
this.onSelect.emit(true);
95+
if (!this.disabled) {
96+
this._selected = true;
97+
this.onSelect.emit(true);
98+
}
99+
}
100+
101+
/** Returns the correct tabindex for the option depending on disabled state. */
102+
_getTabIndex() {
103+
return this.disabled ? '-1' : '0';
82104
}
83105

84106
_getHostElement(): HTMLElement {

src/lib/select/select.scss

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@import '../core/style/menu-common';
2+
@import '../core/style/form-common';
23

34
$md-select-trigger-height: 30px !default;
45
$md-select-trigger-min-width: 112px !default;
@@ -16,6 +17,14 @@ md-select {
1617
height: $md-select-trigger-height;
1718
min-width: $md-select-trigger-min-width;
1819
cursor: pointer;
20+
21+
[aria-disabled='true'] & {
22+
@include md-control-disabled-underline();
23+
border-bottom: transparent;
24+
background-position: 0 bottom;
25+
cursor: default;
26+
user-select: none;
27+
}
1928
}
2029

2130
.md-select-placeholder {
@@ -56,6 +65,11 @@ md-option {
5665
position: relative;
5766
cursor: pointer;
5867
outline: none;
68+
69+
&[aria-disabled='true'] {
70+
cursor: default;
71+
user-select: none;
72+
}
5973
}
6074

6175
.md-option-ripple {

0 commit comments

Comments
 (0)