mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(select): allow disabling ripples for options (#5967)
* Adds a binding that allows developers to disable ripples for every option in a select.
This commit is contained in:
committed by
Andrew Seguin
parent
82535039a2
commit
34ec068741
@@ -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));
|
||||
@@ -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');
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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()',
|
||||
@@ -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;
|
||||
@@ -99,6 +92,13 @@ 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>();
|
||||
|
||||
@@ -106,10 +106,7 @@ export class MdOption extends _MdOptionMixinBase implements CanDisableRipple {
|
||||
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.
|
||||
|
||||
@@ -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', () => {
|
||||
@@ -924,7 +936,6 @@ describe('MdSelect', () => {
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('misc forms', () => {
|
||||
@@ -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>
|
||||
@@ -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>;
|
||||
|
||||
@@ -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 = '';
|
||||
|
||||
@@ -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. */
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user