Skip to content
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(select): support disabling #1667

Merged
merged 1 commit into from
Nov 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 28 additions & 9 deletions src/demo-app/select/select-demo.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
<div class="demo-select">
<md-select placeholder="Food" [formControl]="control" [required]="isRequired">
<md-option *ngFor="let food of foods" [value]="food.value"> {{ food.viewValue }} </md-option>
</md-select>
<p> Value: {{ control.value }} </p>
<p> Touched: {{ control.touched }} </p>
<p> Dirty: {{ control.dirty }} </p>
<p> Status: {{ control.status }} </p>
<button md-button (click)="control.setValue('pizza-1')">SET VALUE</button>
<button md-button (click)="isRequired=!isRequired">TOGGLE REQUIRED</button>
<md-card>
<md-select placeholder="Food" [formControl]="foodControl">
<md-option *ngFor="let food of foods" [value]="food.value"> {{ food.viewValue }} </md-option>
</md-select>
<p> Value: {{ foodControl.value }} </p>
<p> Touched: {{ foodControl.touched }} </p>
<p> Dirty: {{ foodControl.dirty }} </p>
<p> Status: {{ foodControl.status }} </p>
<button md-button (click)="foodControl.setValue('pizza-1')">SET VALUE</button>
<button md-button (click)="toggleDisabled()">TOGGLE DISABLED</button>
</md-card>

<md-card>
<md-select placeholder="Drink" [(ngModel)]="currentDrink" [required]="isRequired" [disabled]="isDisabled"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currentDrink needs to be defined in the class.
(failing google presubmit)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

#drinkControl="ngModel">
<md-option *ngFor="let drink of drinks" [value]="drink.value" [disabled]="drink.disabled">
{{ drink.viewValue }}
</md-option>
</md-select>
<p> Value: {{ currentDrink }} </p>
<p> Touched: {{ drinkControl.touched }} </p>
<p> Dirty: {{ drinkControl.dirty }} </p>
<p> Status: {{ drinkControl.control?.status }} </p>
<button md-button (click)="currentDrink='sprite-1'">SET VALUE</button>
<button md-button (click)="isRequired=!isRequired">TOGGLE REQUIRED</button>
<button md-button (click)="isDisabled=!isDisabled">TOGGLE DISABLED</button>
</md-card>

</div>
8 changes: 8 additions & 0 deletions src/demo-app/select/select-demo.scss
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
.demo-select {
display: flex;
flex-flow: row wrap;

md-card {
width: 450px;
margin: 24px;
}

}
13 changes: 12 additions & 1 deletion src/demo-app/select/select-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,24 @@ import {FormControl} from '@angular/forms';
})
export class SelectDemo {
isRequired = false;
isDisabled = false;
currentDrink: string;
foodControl = new FormControl('');

foods = [
{value: 'steak-0', viewValue: 'Steak'},
{value: 'pizza-1', viewValue: 'Pizza'},
{value: 'tacos-2', viewValue: 'Tacos'}
];

control = new FormControl('');
drinks = [
{value: 'coke-0', viewValue: 'Coke'},
{value: 'sprite-1', viewValue: 'Sprite', disabled: true},
{value: 'water-2', viewValue: 'Water'}
];

toggleDisabled() {
this.foodControl.enabled ? this.foodControl.disable() : this.foodControl.enable();
}

}
12 changes: 12 additions & 0 deletions src/lib/core/style/_form-common.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

// Gradient for showing the dashed line when the input is disabled.
// Unlike using a border, a gradient allows us to adjust the spacing of the dotted line
// to match the Material Design spec.
$md-underline-disabled-background-image:
linear-gradient(to right, rgba(0, 0, 0, 0.26) 0%, rgba(0, 0, 0, 0.26) 33%, transparent 0%);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comment saying why you use a linear-gradient like this instead of a border?


@mixin md-control-disabled-underline {
background-image: $md-underline-disabled-background-image;
background-size: 4px 1px;
background-repeat: repeat-x;
}
5 changes: 2 additions & 3 deletions src/lib/input/input.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import '../core/style/variables';
@import '../core/style/form-common';


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

&.md-disabled {
@include md-control-disabled-underline();
border-top: 0;
background-image: $md-input-underline-disabled-background-image;
background-position: 0;
background-size: 4px 1px;
background-repeat: repeat-x;
}

.md-input-ripple {
Expand Down
18 changes: 13 additions & 5 deletions src/lib/select/_select-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
color: md-color($foreground, hint-text);
border-bottom: 1px solid md-color($foreground, divider);

md-select:focus & {
md-select:focus:not(.md-select-disabled) & {
color: md-color($primary);
border-bottom: 1px solid md-color($primary);
}

.ng-invalid.ng-touched & {
.ng-invalid.ng-touched:not(.md-select-disabled) & {
color: md-color($warn);
border-bottom: 1px solid md-color($warn);
}
Expand All @@ -25,11 +25,11 @@
.md-select-arrow {
color: md-color($foreground, hint-text);

md-select:focus & {
md-select:focus:not(.md-select-disabled) & {
color: md-color($primary);
}

.ng-invalid.ng-touched & {
.ng-invalid.ng-touched:not(.md-select-disabled) & {
color: md-color($warn);
}
}
Expand All @@ -40,10 +40,14 @@

.md-select-value {
color: md-color($foreground, text);

.md-select-disabled & {
color: md-color($foreground, hint-text);
}
}

md-option {
&:hover, &:focus {
&:hover:not(.md-option-disabled), &:focus:not(.md-option-disabled) {
background: md-color($background, hover);
}

Expand All @@ -52,5 +56,9 @@
color: md-color($primary);
}

&.md-option-disabled {
color: md-color($foreground, hint-text);
}

}
}
2 changes: 1 addition & 1 deletion src/lib/select/option.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<ng-content></ng-content>
<div class="md-option-ripple" md-ripple md-ripple-background-color="rgba(0,0,0,0)"
<div class="md-option-ripple" *ngIf="!disabled" md-ripple md-ripple-background-color="rgba(0,0,0,0)"
[md-ripple-trigger]="_getHostElement()"></div>
31 changes: 27 additions & 4 deletions src/lib/select/option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@ import {
ViewEncapsulation
} from '@angular/core';
import {ENTER, SPACE} from '../core/keyboard/keycodes';
import {coerceBooleanProperty} from '../core/coersion/boolean-property';

@Component({
moduleId: module.id,
selector: 'md-option',
host: {
'role': 'option',
'tabindex': '0',
'[attr.tabindex]': '_getTabIndex()',
'[class.md-selected]': 'selected',
'[attr.aria-selected]': 'selected.toString()',
'[attr.aria-disabled]': 'disabled.toString()',
'[class.md-option-disabled]': 'disabled',
'(click)': '_selectViaInteraction()',
'(keydown)': '_handleKeydown($event)'
},
Expand All @@ -25,11 +28,23 @@ import {ENTER, SPACE} from '../core/keyboard/keycodes';
encapsulation: ViewEncapsulation.None
})
export class MdOption {
private _selected = false;
private _selected: boolean = false;

/** Whether the option is disabled. */
private _disabled: boolean = false;

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

@Input()
get disabled() {
return this._disabled;
}

set disabled(value: any) {
this._disabled = coerceBooleanProperty(value);
}

/** Event emitted when the option is selected. */
@Output() onSelect = new EventEmitter();

Expand Down Expand Up @@ -72,13 +87,21 @@ export class MdOption {
}
}


/**
* Selects the option while indicating the selection came from the user. Used to
* determine if the select's view -> model callback should be invoked.
*/
_selectViaInteraction() {
this._selected = true;
this.onSelect.emit(true);
if (!this.disabled) {
this._selected = true;
this.onSelect.emit(true);
}
}

/** Returns the correct tabindex for the option depending on disabled state. */
_getTabIndex() {
return this.disabled ? '-1' : '0';
}

_getHostElement(): HTMLElement {
Expand Down
14 changes: 14 additions & 0 deletions src/lib/select/select.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import '../core/style/menu-common';
@import '../core/style/form-common';

$md-select-trigger-height: 30px !default;
$md-select-trigger-min-width: 112px !default;
Expand All @@ -16,6 +17,14 @@ md-select {
height: $md-select-trigger-height;
min-width: $md-select-trigger-min-width;
cursor: pointer;

[aria-disabled='true'] & {
@include md-control-disabled-underline();
border-bottom: transparent;
background-position: 0 bottom;
cursor: default;
user-select: none;
}
}

.md-select-placeholder {
Expand Down Expand Up @@ -56,6 +65,11 @@ md-option {
position: relative;
cursor: pointer;
outline: none;

&[aria-disabled='true'] {
cursor: default;
user-select: none;
}
}

.md-option-ripple {
Expand Down
Loading