Skip to content

Commit

Permalink
feat(select): allow disabling ripples for options (#5967)
Browse files Browse the repository at this point in the history
* Adds a binding that allows developers to disable ripples for every option in a select.
  • Loading branch information
devversion authored and andrewseguin committed Jul 28, 2017
1 parent 8253503 commit 34ec068
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 22 deletions.
13 changes: 6 additions & 7 deletions src/lib/core/option/option.spec.ts
Expand Up @@ -9,18 +9,18 @@ describe('MdOption component', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [MdOptionModule],
declarations: [OptionWithDisableRipple]
declarations: [OptionWithDisable]
}).compileComponents();
}));

describe('ripples', () => {
let fixture: ComponentFixture<OptionWithDisableRipple>;
let fixture: ComponentFixture<OptionWithDisable>;
let optionDebugElement: DebugElement;
let optionNativeElement: HTMLElement;
let optionInstance: MdOption;

beforeEach(() => {
fixture = TestBed.createComponent(OptionWithDisableRipple);
fixture = TestBed.createComponent(OptionWithDisable);
fixture.detectChanges();

optionDebugElement = fixture.debugElement.query(By.directive(MdOption));
Expand Down Expand Up @@ -58,7 +58,7 @@ describe('MdOption component', () => {
expect(optionNativeElement.querySelectorAll('.mat-ripple-element').length)
.toBe(0, 'Expected no ripples to show up initially');

fixture.componentInstance.disableRipple = true;
optionInstance.disableRipple = true;
fixture.detectChanges();

dispatchFakeEvent(optionNativeElement, 'mousedown');
Expand All @@ -73,9 +73,8 @@ describe('MdOption component', () => {
});

@Component({
template: `<md-option [disableRipple]="disableRipple" [disabled]="disabled"></md-option>`
template: `<md-option [disabled]="disabled"></md-option>`
})
export class OptionWithDisableRipple {
disableRipple: boolean;
export class OptionWithDisable {
disabled: boolean;
}
23 changes: 10 additions & 13 deletions src/lib/core/option/option.ts
Expand Up @@ -22,7 +22,6 @@ import {ENTER, SPACE} from '../keyboard/keycodes';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {MATERIAL_COMPATIBILITY_MODE} from '../../core/compatibility/compatibility';
import {MdOptgroup} from './optgroup';
import {CanDisableRipple, mixinDisableRipple} from '../common-behaviors/disable-ripple';

/**
* Option IDs need to be unique across components, so this counter exists outside of
Expand All @@ -35,19 +34,12 @@ export class MdOptionSelectionChange {
constructor(public source: MdOption, public isUserInput = false) { }
}

// Boilerplate for applying mixins to MdOption.
/** @docs-private */
export class MdOptionBase {}
export const _MdOptionMixinBase = mixinDisableRipple(MdOptionBase);


/**
* Single option inside of a `<md-select>` element.
*/
@Component({
moduleId: module.id,
selector: 'md-option, mat-option',
inputs: ['disableRipple'],
host: {
'role': 'option',
'[attr.tabindex]': '_getTabIndex()',
Expand All @@ -66,10 +58,11 @@ export const _MdOptionMixinBase = mixinDisableRipple(MdOptionBase);
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MdOption extends _MdOptionMixinBase implements CanDisableRipple {
export class MdOption {
private _selected: boolean = false;
private _active: boolean = false;
private _multiple: boolean = false;
private _disableRipple: boolean = false;

/** Whether the option is disabled. */
private _disabled: boolean = false;
Expand Down Expand Up @@ -99,17 +92,21 @@ export class MdOption extends _MdOptionMixinBase implements CanDisableRipple {
get disabled() { return (this.group && this.group.disabled) || this._disabled; }
set disabled(value: any) { this._disabled = coerceBooleanProperty(value); }

/** Whether ripples for the option are disabled. */
get disableRipple() { return this._disableRipple; }
set disableRipple(value: boolean) {
this._disableRipple = value;
this._changeDetectorRef.markForCheck();
}

/** Event emitted when the option is selected or deselected. */
@Output() onSelectionChange = new EventEmitter<MdOptionSelectionChange>();

constructor(
private _element: ElementRef,
private _changeDetectorRef: ChangeDetectorRef,
@Optional() public readonly group: MdOptgroup,
@Optional() @Inject(MATERIAL_COMPATIBILITY_MODE) public _isCompatibilityMode: boolean
) {
super();
}
@Optional() @Inject(MATERIAL_COMPATIBILITY_MODE) public _isCompatibilityMode: boolean) {}

/**
* Whether or not the option is currently active and ready to be selected.
Expand Down
16 changes: 14 additions & 2 deletions src/lib/select/select.spec.ts
Expand Up @@ -308,6 +308,18 @@ describe('MdSelect', () => {
expect(event.defaultPrevented).toBe(true);
});

it('should update disableRipple properly on each option', () => {
const options = fixture.componentInstance.options.toArray();

expect(options.every(option => option.disableRipple === false))
.toBeTruthy('Expected all options to have disableRipple set to false initially.');

fixture.componentInstance.disableRipple = true;
fixture.detectChanges();

expect(options.every(option => option.disableRipple === true))
.toBeTruthy('Expected all options to have disableRipple set to true.');
});
});

describe('selection logic', () => {
Expand Down Expand Up @@ -924,7 +936,6 @@ describe('MdSelect', () => {
});
});
}));

});

describe('misc forms', () => {
Expand Down Expand Up @@ -2660,7 +2671,7 @@ describe('MdSelect', () => {
<div [style.height.px]="heightAbove"></div>
<md-select placeholder="Food" [formControl]="control" [required]="isRequired"
[tabIndex]="tabIndexOverride" [aria-label]="ariaLabel" [aria-labelledby]="ariaLabelledby"
[panelClass]="panelClass">
[panelClass]="panelClass" [disableRipple]="disableRipple">
<md-option *ngFor="let food of foods" [value]="food.value" [disabled]="food.disabled">
{{ food.viewValue }}
</md-option>
Expand All @@ -2687,6 +2698,7 @@ class BasicSelect {
ariaLabel: string;
ariaLabelledby: string;
panelClass = ['custom-one', 'custom-two'];
disableRipple: boolean;

@ViewChild(MdSelect) select: MdSelect;
@ViewChildren(MdOption) options: QueryList<MdOption>;
Expand Down
16 changes: 16 additions & 0 deletions src/lib/select/select.ts
Expand Up @@ -344,6 +344,15 @@ export class MdSelect extends _MdSelectMixinBase implements AfterContentInit, On
}
private _value: any;

/** Whether ripples for all options in the select are disabled. */
@Input()
get disableRipple(): boolean { return this._disableRipple; }
set disableRipple(value: boolean) {
this._disableRipple = coerceBooleanProperty(value);
this._setOptionDisableRipple();
}
private _disableRipple: boolean = false;

/** Aria label of the select. If not specified, the placeholder will be used as label. */
@Input('aria-label') ariaLabel: string = '';

Expand Down Expand Up @@ -719,6 +728,7 @@ export class MdSelect extends _MdSelectMixinBase implements AfterContentInit, On
this._listenToOptions();
this._setOptionIds();
this._setOptionMultiple();
this._setOptionDisableRipple();
}

/** Listens to user-generated selection events on each option. */
Expand Down Expand Up @@ -815,6 +825,12 @@ export class MdSelect extends _MdSelectMixinBase implements AfterContentInit, On
}
}

/** Sets the `disableRipple` property on each option. */
private _setOptionDisableRipple() {
if (this.options) {
this.options.forEach(option => option.disableRipple = this.disableRipple);
}
}
/**
* Must set the width of the selected option's value programmatically
* because it is absolutely positioned and otherwise will not clip
Expand Down

0 comments on commit 34ec068

Please sign in to comment.