diff --git a/src/demo-app/slide-toggle/slide-toggle-demo.html b/src/demo-app/slide-toggle/slide-toggle-demo.html index cf78e71dea60..a1c6192e1563 100644 --- a/src/demo-app/slide-toggle/slide-toggle-demo.html +++ b/src/demo-app/slide-toggle/slide-toggle-demo.html @@ -11,4 +11,19 @@ Disable Bound + +

Example where the slide toggle is required inside of a form.

+ +
+ + + Slide Toggle + + +

+ +

+ +
+ \ No newline at end of file diff --git a/src/demo-app/slide-toggle/slide-toggle-demo.ts b/src/demo-app/slide-toggle/slide-toggle-demo.ts index 02b758051d23..7a8127dc3ac7 100644 --- a/src/demo-app/slide-toggle/slide-toggle-demo.ts +++ b/src/demo-app/slide-toggle/slide-toggle-demo.ts @@ -9,4 +9,9 @@ import {Component} from '@angular/core'; }) export class SlideToggleDemo { firstToggle: boolean; + + onFormSubmit() { + alert(`You submitted the form.`); + } + } diff --git a/src/lib/checkbox/checkbox.html b/src/lib/checkbox/checkbox.html index 7921f192adbb..f4b2b1154204 100644 --- a/src/lib/checkbox/checkbox.html +++ b/src/lib/checkbox/checkbox.html @@ -2,6 +2,7 @@
{ })); + it('should forward the required attribute', () => { + testComponent.isRequired = true; + fixture.detectChanges(); + + expect(inputElement.required).toBe(true); + + testComponent.isRequired = false; + fixture.detectChanges(); + + expect(inputElement.required).toBe(false); + }); + describe('state transition css classes', () => { it('should transition unchecked -> checked -> unchecked', () => { testComponent.isChecked = true; @@ -502,6 +514,7 @@ describe('MdCheckbox', () => {
{ class SingleCheckbox { alignment: string = 'start'; isChecked: boolean = false; + isRequired: boolean = false; isIndeterminate: boolean = false; isDisabled: boolean = false; parentElementClicked: boolean = false; diff --git a/src/lib/checkbox/checkbox.ts b/src/lib/checkbox/checkbox.ts index 39959ada95af..0dee0d42202c 100644 --- a/src/lib/checkbox/checkbox.ts +++ b/src/lib/checkbox/checkbox.ts @@ -12,6 +12,7 @@ import { ModuleWithProviders, } from '@angular/core'; import {NG_VALUE_ACCESSOR, ControlValueAccessor} from '@angular/forms'; +import {BooleanFieldValue} from '@angular2-material/core'; /** * Monotonically increasing integer used to auto-generate unique ids for checkbox components. @@ -92,6 +93,9 @@ export class MdCheckbox implements ControlValueAccessor { return `input-${this.id}`; } + /** Whether the checkbox is required or not. */ + @Input() @BooleanFieldValue() required: boolean = false; + /** Whether or not the checkbox should come before or after the label. */ @Input() align: 'start' | 'end' = 'start'; diff --git a/src/lib/slide-toggle/slide-toggle.html b/src/lib/slide-toggle/slide-toggle.html index 48d7115f30dd..810fef49b038 100644 --- a/src/lib/slide-toggle/slide-toggle.html +++ b/src/lib/slide-toggle/slide-toggle.html @@ -13,8 +13,9 @@
- { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [MdSlideToggleModule.forRoot(), FormsModule], - declarations: [SlideToggleTestApp], + declarations: [SlideToggleTestApp, SlideToggleFormsTestApp], }); TestBed.compileComponents(); @@ -318,6 +318,18 @@ describe('MdSlideToggle', () => { expect(slideToggleElement.classList).toContain('md-slide-toggle-focused'); }); + it('should forward the required attribute', () => { + testComponent.isRequired = true; + fixture.detectChanges(); + + expect(inputElement.required).toBe(true); + + testComponent.isRequired = false; + fixture.detectChanges(); + + expect(inputElement.required).toBe(false); + }); + }); describe('custom template', () => { @@ -331,6 +343,55 @@ describe('MdSlideToggle', () => { })); }); + describe('with forms', () => { + + let fixture: ComponentFixture; + let testComponent: SlideToggleFormsTestApp; + let buttonElement: HTMLButtonElement; + let labelElement: HTMLLabelElement; + let inputElement: HTMLInputElement; + + // This initialization is async() because it needs to wait for ngModel to set the initial value. + beforeEach(async(() => { + fixture = TestBed.createComponent(SlideToggleFormsTestApp); + + testComponent = fixture.debugElement.componentInstance; + + fixture.detectChanges(); + + buttonElement = fixture.debugElement.query(By.css('button')).nativeElement; + labelElement = fixture.debugElement.query(By.css('label')).nativeElement; + inputElement = fixture.debugElement.query(By.css('input')).nativeElement; + })); + + it('should prevent the form from submit when being required', () => { + + if ('reportValidity' in inputElement === false) { + // If the browser does not report the validity then the tests will break. + // e.g Safari 8 on Mobile. + return; + } + + testComponent.isRequired = true; + + fixture.detectChanges(); + + buttonElement.click(); + fixture.detectChanges(); + + expect(testComponent.isSubmitted).toBe(false); + + testComponent.isRequired = false; + fixture.detectChanges(); + + buttonElement.click(); + fixture.detectChanges(); + + expect(testComponent.isSubmitted).toBe(true); + }); + + }); + }); /** @@ -347,16 +408,25 @@ function dispatchFocusChangeEvent(eventName: string, element: HTMLElement): void @Component({ selector: 'slide-toggle-test-app', template: ` - + Test Slide Toggle + `, }) class SlideToggleTestApp { isDisabled: boolean = false; + isRequired: boolean = false; slideModel: boolean = false; slideChecked: boolean = false; slideColor: string; @@ -371,3 +441,17 @@ class SlideToggleTestApp { this.lastEvent = event; } } + + +@Component({ + selector: 'slide-toggle-forms-test-app', + template: ` +
+ Required + +
` +}) +class SlideToggleFormsTestApp { + isSubmitted: boolean = false; + isRequired: boolean = false; +} diff --git a/src/lib/slide-toggle/slide-toggle.ts b/src/lib/slide-toggle/slide-toggle.ts index 1b5ea011ca33..17eb2e0ea645 100644 --- a/src/lib/slide-toggle/slide-toggle.ts +++ b/src/lib/slide-toggle/slide-toggle.ts @@ -66,6 +66,7 @@ export class MdSlideToggle implements AfterContentInit, ControlValueAccessor { private _slideRenderer: SlideToggleRenderer = null; @Input() @BooleanFieldValue() disabled: boolean = false; + @Input() @BooleanFieldValue() required: boolean = false; @Input() name: string = null; @Input() id: string = this._uniqueId; @Input() tabIndex: number = 0;