diff --git a/src/components/checkbox/checkbox.html b/src/components/checkbox/checkbox.html
index 7303056d8589..c1fff754de90 100644
--- a/src/components/checkbox/checkbox.html
+++ b/src/components/checkbox/checkbox.html
@@ -1,5 +1,18 @@
-
-
-
+
+
diff --git a/src/components/checkbox/checkbox.scss b/src/components/checkbox/checkbox.scss
index 1ad59c831cae..4564ab1f1764 100644
--- a/src/components/checkbox/checkbox.scss
+++ b/src/components/checkbox/checkbox.scss
@@ -1,6 +1,7 @@
@import "default-theme";
@import "theme-functions";
@import "variables";
+@import "mixins";
/** The width/height of the checkbox element. */
$md-checkbox-size: $md-toggle-size !default;
@@ -217,11 +218,8 @@ $_md-checkbox-indeterminate-checked-easing-function: cubic-bezier(0.14, 0, 0, 1)
}
md-checkbox {
- cursor: pointer;
-
- &:focus {
- // TODO(traviskaufman): Add ink ripple on focus state, once ripple is implemented.
- outline: none;
+ &, label {
+ cursor: pointer;
}
}
@@ -251,7 +249,7 @@ md-checkbox {
}
// TODO(kara): Remove this style when fixing vertical baseline
-.md-checkbox-layout label {
+.md-checkbox-layout .md-checkbox-label {
line-height: 24px;
}
@@ -461,3 +459,11 @@ md-checkbox {
}
}
}
+
+// Underlying native input element.
+// Visually hidden but still able to respond to focus.
+.md-checkbox-input {
+ @include md-visually-hidden;
+}
+
+@include md-temporary-ink-ripple(checkbox);
diff --git a/src/components/checkbox/checkbox.spec.ts b/src/components/checkbox/checkbox.spec.ts
index 05404886d01f..e95e977d6e48 100644
--- a/src/components/checkbox/checkbox.spec.ts
+++ b/src/components/checkbox/checkbox.spec.ts
@@ -13,7 +13,7 @@ import {By} from '@angular/platform-browser';
import {MdCheckbox} from './checkbox';
import {PromiseCompleter} from '../../core/async/promise-completer';
-
+// TODO: Implement E2E tests for spacebar/click behavior for checking/unchecking
describe('MdCheckbox', () => {
let builder: TestComponentBuilder;
@@ -28,6 +28,8 @@ describe('MdCheckbox', () => {
let checkboxNativeElement: HTMLElement;
let checkboxInstance: MdCheckbox;
let testComponent: SingleCheckbox;
+ let inputElement: HTMLInputElement;
+ let labelElement: HTMLLabelElement;
beforeEach(async(() => {
builder.createAsync(SingleCheckbox).then(f => {
@@ -38,71 +40,79 @@ describe('MdCheckbox', () => {
checkboxNativeElement = checkboxDebugElement.nativeElement;
checkboxInstance = checkboxDebugElement.componentInstance;
testComponent = fixture.debugElement.componentInstance;
+ inputElement = checkboxNativeElement.querySelector('input');
+ labelElement = checkboxNativeElement.querySelector('label');
});
}));
it('should add and remove the checked state', () => {
expect(checkboxInstance.checked).toBe(false);
expect(checkboxNativeElement.classList).not.toContain('md-checkbox-checked');
- expect(checkboxNativeElement.getAttribute('aria-checked')).toBe('false');
+ expect(inputElement.checked).toBe(false);
testComponent.isChecked = true;
fixture.detectChanges();
expect(checkboxInstance.checked).toBe(true);
expect(checkboxNativeElement.classList).toContain('md-checkbox-checked');
- expect(checkboxNativeElement.getAttribute('aria-checked')).toBe('true');
+ expect(inputElement.checked).toBe(true);
testComponent.isChecked = false;
fixture.detectChanges();
expect(checkboxInstance.checked).toBe(false);
expect(checkboxNativeElement.classList).not.toContain('md-checkbox-checked');
- expect(checkboxNativeElement.getAttribute('aria-checked')).toBe('false');
+ expect(inputElement.checked).toBe(false);
});
it('should add and remove indeterminate state', () => {
expect(checkboxNativeElement.classList).not.toContain('md-checkbox-checked');
- expect(checkboxNativeElement.getAttribute('aria-checked')).toBe('false');
+ expect(inputElement.checked).toBe(false);
+ expect(inputElement.indeterminate).toBe(false);
testComponent.isIndeterminate = true;
fixture.detectChanges();
expect(checkboxNativeElement.classList).toContain('md-checkbox-indeterminate');
- expect(checkboxNativeElement.getAttribute('aria-checked')).toBe('mixed');
+ expect(inputElement.checked).toBe(false);
+ expect(inputElement.indeterminate).toBe(true);
testComponent.isIndeterminate = false;
fixture.detectChanges();
expect(checkboxNativeElement.classList).not.toContain('md-checkbox-indeterminate');
- expect(checkboxNativeElement.getAttribute('aria-checked')).toBe('false');
+ expect(inputElement.checked).toBe(false);
+ expect(inputElement.indeterminate).toBe(false);
});
it('should toggle checked state on click', () => {
expect(checkboxInstance.checked).toBe(false);
- checkboxNativeElement.click();
+ labelElement.click();
fixture.detectChanges();
expect(checkboxInstance.checked).toBe(true);
- checkboxNativeElement.click();
+ labelElement.click();
fixture.detectChanges();
expect(checkboxInstance.checked).toBe(false);
});
it('should change from indeterminate to checked on click', () => {
+ testComponent.isChecked = false;
testComponent.isIndeterminate = true;
fixture.detectChanges();
- checkboxNativeElement.click();
- fixture.detectChanges();
+ expect(checkboxInstance.checked).toBe(false);
+ expect(checkboxInstance.indeterminate).toBe(true);
+
+ checkboxInstance.onInteractionEvent({stopPropagation: () => {}});
expect(checkboxInstance.checked).toBe(true);
expect(checkboxInstance.indeterminate).toBe(false);
- checkboxNativeElement.click();
+ checkboxInstance.onInteractionEvent({stopPropagation: () => {}});
fixture.detectChanges();
expect(checkboxInstance.checked).toBe(false);
@@ -112,21 +122,23 @@ describe('MdCheckbox', () => {
it('should add and remove disabled state', () => {
expect(checkboxInstance.disabled).toBe(false);
expect(checkboxNativeElement.classList).not.toContain('md-checkbox-disabled');
- expect(checkboxNativeElement.tabIndex).toBe(0);
+ expect(inputElement.tabIndex).toBe(0);
+ expect(inputElement.disabled).toBe(false);
testComponent.isDisabled = true;
fixture.detectChanges();
expect(checkboxInstance.disabled).toBe(true);
expect(checkboxNativeElement.classList).toContain('md-checkbox-disabled');
- expect(checkboxNativeElement.hasAttribute('tabindex')).toBe(false);
+ expect(inputElement.disabled).toBe(true);
testComponent.isDisabled = false;
fixture.detectChanges();
expect(checkboxInstance.disabled).toBe(false);
expect(checkboxNativeElement.classList).not.toContain('md-checkbox-disabled');
- expect(checkboxNativeElement.tabIndex).toBe(0);
+ expect(inputElement.tabIndex).toBe(0);
+ expect(inputElement.disabled).toBe(false);
});
it('should not toggle `checked` state upon interation while disabled', () => {
@@ -152,25 +164,13 @@ describe('MdCheckbox', () => {
expect(checkboxNativeElement.id).toBe('simple-check');
});
- it('should create a label element with its own unique id for aria-labelledby', () => {
- let labelElement = checkboxNativeElement.querySelector('label');
- expect(labelElement.id).toBeTruthy();
- expect(labelElement.id).not.toBe(checkboxNativeElement.id);
- expect(checkboxNativeElement.getAttribute('aria-labelledby')).toBe(labelElement.id);
- });
-
it('should project the checkbox content into the label element', () => {
- let labelElement = checkboxNativeElement.querySelector('label');
-
- expect(labelElement.textContent.trim()).toBe('Simple checkbox');
- });
-
- it('should mark the host element with role="checkbox"', () => {
- expect(checkboxNativeElement.getAttribute('role')).toBe('checkbox');
+ let label = checkboxNativeElement.querySelector('.md-checkbox-label');
+ expect(label.textContent.trim()).toBe('Simple checkbox');
});
it('should make the host element a tab stop', () => {
- expect(checkboxNativeElement.tabIndex).toBe(0);
+ expect(inputElement.tabIndex).toBe(0);
});
it('should add a css class to end-align the checkbox', () => {
@@ -196,46 +196,6 @@ describe('MdCheckbox', () => {
return promiseCompleter.promise;
});
- it('should stop propagation of interaction events when disabed', () => {
- testComponent.isDisabled = true;
- fixture.detectChanges();
-
- checkboxNativeElement.click();
- fixture.detectChanges();
-
- expect(testComponent.parentElementClicked).toBe(false);
- });
-
- it('should not scroll when pressing space on the checkbox', () => {
- let keyboardEvent = dispatchKeyboardEvent('keydown', checkboxNativeElement, ' ');
- fixture.detectChanges();
-
- expect(keyboardEvent.preventDefault).toHaveBeenCalled();
- });
-
- it('should toggle the checked state when pressing space', () => {
- dispatchKeyboardEvent('keyup', checkboxNativeElement, ' ');
- fixture.detectChanges();
-
- expect(checkboxInstance.checked).toBe(true);
-
- dispatchKeyboardEvent('keyup', checkboxNativeElement, ' ');
- fixture.detectChanges();
-
- expect(checkboxInstance.checked).toBe(false);
- });
-
- it('should not toggle the checked state when pressing space if disabled', () => {
- testComponent.isDisabled = true;
- fixture.detectChanges();
-
- dispatchKeyboardEvent('keyup', checkboxNativeElement, ' ');
- fixture.detectChanges();
-
- expect(checkboxInstance.checked).toBe(false);
- expect(testComponent.parentElementKeyedUp).toBe(false);
- });
-
describe('state transition css classes', () => {
it('should transition unchecked -> checked -> unchecked', () => {
testComponent.isChecked = true;
@@ -294,14 +254,47 @@ describe('MdCheckbox', () => {
describe('with provided aria-label ', () => {
let checkboxDebugElement: DebugElement;
let checkboxNativeElement: HTMLElement;
+ let inputElement: HTMLInputElement;
it('should use the provided aria-label', async(() => {
builder.createAsync(CheckboxWithAriaLabel).then(f => {
fixture = f;
checkboxDebugElement = fixture.debugElement.query(By.directive(MdCheckbox));
checkboxNativeElement = checkboxDebugElement.nativeElement;
+ inputElement = checkboxNativeElement.querySelector('input');
- expect(checkboxNativeElement.getAttribute('aria-label')).toBe('Super effective');
+ fixture.detectChanges();
+ expect(inputElement.getAttribute('aria-label')).toBe('Super effective');
+ });
+ }));
+ });
+
+ describe('with provided aria-labelledby ', () => {
+ let checkboxDebugElement: DebugElement;
+ let checkboxNativeElement: HTMLElement;
+ let inputElement: HTMLInputElement;
+
+ it('should use the provided aria-labelledby', async(() => {
+ builder.createAsync(CheckboxWithAriaLabelledby).then(f => {
+ fixture = f;
+ checkboxDebugElement = fixture.debugElement.query(By.directive(MdCheckbox));
+ checkboxNativeElement = checkboxDebugElement.nativeElement;
+ inputElement = checkboxNativeElement.querySelector('input');
+
+ fixture.detectChanges();
+ expect(inputElement.getAttribute('aria-labelledby')).toBe('some-id');
+ });
+ }));
+
+ it('should not assign aria-labelledby if none is provided', async(() => {
+ builder.createAsync(SingleCheckbox).then(f => {
+ fixture = f;
+ checkboxDebugElement = fixture.debugElement.query(By.directive(MdCheckbox));
+ checkboxNativeElement = checkboxDebugElement.nativeElement;
+ inputElement = checkboxNativeElement.querySelector('input');
+
+ fixture.detectChanges();
+ expect(inputElement.getAttribute('aria-labelledby')).toBe(null);
});
}));
});
@@ -310,6 +303,8 @@ describe('MdCheckbox', () => {
let checkboxDebugElement: DebugElement;
let checkboxNativeElement: HTMLElement;
let testComponent: CheckboxWithTabIndex;
+ let inputElement: HTMLInputElement;
+ let labelElement: HTMLLabelElement;
beforeEach(async(() => {
builder.createAsync(CheckboxWithTabIndex).then(f => {
@@ -319,11 +314,13 @@ describe('MdCheckbox', () => {
testComponent = fixture.debugElement.componentInstance;
checkboxDebugElement = fixture.debugElement.query(By.directive(MdCheckbox));
checkboxNativeElement = checkboxDebugElement.nativeElement;
+ inputElement = checkboxNativeElement.querySelector('input');
+ labelElement = checkboxNativeElement.querySelector('label');
});
}));
it('should preserve any given tabIndex', async(() => {
- expect(checkboxNativeElement.tabIndex).toBe(7);
+ expect(inputElement.tabIndex).toBe(7);
}));
it('should preserve given tabIndex when the checkbox is disabled then enabled', () => {
@@ -336,7 +333,7 @@ describe('MdCheckbox', () => {
testComponent.isDisabled = false;
fixture.detectChanges();
- expect(checkboxNativeElement.tabIndex).toBe(13);
+ expect(inputElement.tabIndex).toBe(13);
});
});
@@ -351,7 +348,7 @@ describe('MdCheckbox', () => {
it('should assign a unique id to each checkbox', () => {
let [firstId, secondId] =
fixture.debugElement.queryAll(By.directive(MdCheckbox))
- .map(debugElement => debugElement.nativeElement.id);
+ .map(debugElement => debugElement.nativeElement.querySelector('input').id);
expect(firstId).toBeTruthy();
expect(secondId).toBeTruthy();
@@ -382,8 +379,22 @@ describe('MdCheckbox', () => {
}));
});
-});
+ describe('with name attribute', () => {
+ beforeEach(async(() => {
+ builder.createAsync(CheckboxWithNameAttribute).then(f => {
+ f.detectChanges();
+ fixture = f;
+ });
+ }));
+ it('should forward name value to input element', fakeAsync(() => {
+ let checkboxElement = fixture.debugElement.query(By.directive(MdCheckbox));
+ let inputElement = checkboxElement.nativeElement.querySelector('input');
+
+ expect(inputElement.getAttribute('name')).toBe('test-name');
+ }));
+ });
+});
/** Simple component for testing a single checkbox. */
@Component({
@@ -454,49 +465,16 @@ class CheckboxWithTabIndex {
})
class CheckboxWithAriaLabel { }
-// TODO(jelbourn): remove eveything below when Angular supports faking events.
-
-
-var BROWSER_SUPPORTS_EVENT_CONSTRUCTORS: boolean = (function() {
- // See: https://github.com/rauschma/event_constructors_check/blob/gh-pages/index.html#L39
- try {
- return new Event('submit', { bubbles: false }).bubbles === false &&
- new Event('submit', { bubbles: true }).bubbles === true;
- } catch (e) {
- return false;
- }
-})();
-
-
-/**
- * Dispatches a keyboard event from an element.
- * @param eventName The name of the event to dispatch, such as "keydown".
- * @param element The element from which the event will be dispatched.
- * @param key The key tied to the KeyboardEvent.
- * @returns The artifically created keyboard event.
- */
-function dispatchKeyboardEvent(eventName: string, element: HTMLElement, key: string): Event {
- let keyboardEvent: Event;
- if (BROWSER_SUPPORTS_EVENT_CONSTRUCTORS) {
- keyboardEvent = new KeyboardEvent(eventName);
- } else {
- keyboardEvent = document.createEvent('Event');
- keyboardEvent.initEvent(eventName, true, true);
- }
-
- // Hack DOM Level 3 Events "key" prop into keyboard event.
- Object.defineProperty(keyboardEvent, 'key', {
- value: key,
- enumerable: false,
- writable: false,
- configurable: true,
- });
-
- // Using spyOn seems to be the *only* way to determine if preventDefault is called, since it
- // seems that `defaultPrevented` does not get set with the technique.
- spyOn(keyboardEvent, 'preventDefault').and.callThrough();
-
- element.dispatchEvent(keyboardEvent);
- return keyboardEvent;
-}
+/** Simple test component with an aria-label set. */
+@Component({
+ directives: [MdCheckbox],
+ template: ``
+})
+class CheckboxWithAriaLabelledby {}
+/** Simple test component with name attribute */
+@Component({
+ directives: [MdCheckbox],
+ template: ``
+})
+class CheckboxWithNameAttribute {}
diff --git a/src/components/checkbox/checkbox.ts b/src/components/checkbox/checkbox.ts
index 8ac0105ea657..13bf2395e233 100644
--- a/src/components/checkbox/checkbox.ts
+++ b/src/components/checkbox/checkbox.ts
@@ -15,8 +15,6 @@ import {
ControlValueAccessor,
} from '@angular/common';
-
-
/**
* Monotonically increasing integer used to auto-generate unique ids for checkbox components.
*/
@@ -59,21 +57,11 @@ enum TransitionCheckState {
templateUrl: './components/checkbox/checkbox.html',
styleUrls: ['./components/checkbox/checkbox.css'],
host: {
- 'role': 'checkbox',
- '[id]': 'id',
'[class.md-checkbox-indeterminate]': 'indeterminate',
'[class.md-checkbox-checked]': 'checked',
'[class.md-checkbox-disabled]': 'disabled',
'[class.md-checkbox-align-end]': 'align == "end"',
- '[attr.tabindex]': 'disabled ? null : tabindex',
- '[attr.aria-label]': 'ariaLabel',
- '[attr.aria-labelledby]': 'labelId',
- '[attr.aria-checked]': 'getAriaChecked()',
- '[attr.aria-disabled]': 'disabled',
- '(click)': 'onInteractionEvent($event)',
- '(keydown.space)': 'onSpaceDown($event)',
- '(keyup.space)': 'onInteractionEvent($event)',
- '(blur)': 'onTouched()'
+ '[class.md-checkbox-focused]': 'hasFocus',
},
providers: [MD_CHECKBOX_CONTROL_VALUE_ACCESSOR],
encapsulation: ViewEncapsulation.None,
@@ -86,9 +74,19 @@ export class MdCheckbox implements ControlValueAccessor {
*/
@Input('aria-label') ariaLabel: string = '';
+ /**
+ * Users can specify the `aria-labelledby` attribute which will be forwarded to the input element
+ */
+ @Input('aria-labelledby') ariaLabelledby: string = null;
+
/** A unique id for the checkbox. If one is not supplied, it is auto-generated. */
@Input() id: string = `md-checkbox-${++nextId}`;
+ /** ID to be applied to the `input` element */
+ get inputId(): string {
+ return `input-${this.id}`;
+ }
+
/** Whether or not the checkbox should come before or after the label. */
@Input() align: 'start' | 'end' = 'start';
@@ -104,6 +102,9 @@ export class MdCheckbox implements ControlValueAccessor {
*/
@Input() tabindex: number = 0;
+ /** Name value will be applied to the input element if present */
+ @Input() name: string = null;
+
/** Event emitted when the checkbox's `checked` value changes. */
@Output() change: EventEmitter = new EventEmitter();
@@ -123,6 +124,8 @@ export class MdCheckbox implements ControlValueAccessor {
private _changeSubscription: {unsubscribe: () => any} = null;
+ hasFocus: boolean = false;
+
constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}
/**
@@ -172,43 +175,6 @@ export class MdCheckbox implements ControlValueAccessor {
}
}
- /** The id that is attached to the checkbox's label. */
- get labelId() {
- return `${this.id}-label`;
- }
-
- /** Returns the proper aria-checked attribute value based on the checkbox's state. */
- getAriaChecked() {
- if (this.indeterminate) {
- return 'mixed';
- }
- return this.checked ? 'true' : 'false';
- }
-
- /** Toggles the checked state of the checkbox. If the checkbox is disabled, this does nothing. */
- toggle() {
- this.checked = !this.checked;
- }
-
- /**
- * Event handler used for both (click) and (keyup.space) events. Delegates to toggle().
- */
- onInteractionEvent(event: Event) {
- if (this.disabled) {
- event.stopPropagation();
- return;
- }
- this.toggle();
- }
-
- /**
- * Event handler used for (keydown.space) events. Used to prevent spacebar events from bubbling
- * when the component is focused, which prevents side effects like page scrolling from happening.
- */
- onSpaceDown(evt: Event) {
- evt.preventDefault();
- }
-
/** Implemented as part of ControlValueAccessor. */
writeValue(value: any) {
this.checked = !!value;
@@ -248,6 +214,43 @@ export class MdCheckbox implements ControlValueAccessor {
}
}
+ /**
+ * Informs the component when the input has focus so that we can style accordingly
+ * @internal
+ */
+ onInputFocus() {
+ this.hasFocus = true;
+ }
+
+ /**
+ * Informs the component when we lose focus in order to style accordingly
+ * @internal
+ */
+ onInputBlur() {
+ this.hasFocus = false;
+ this.onTouched();
+ }
+
+ /**
+ * Toggles the `checked` value between true and false
+ */
+ toggle() {
+ this.checked = !this.checked;
+ }
+
+ /**
+ * Event handler for checkbox input element. Toggles checked state if element is not disabled.
+ * @param event
+ * @internal
+ */
+ onInteractionEvent(event: Event) {
+ if (this.disabled) {
+ event.stopPropagation();
+ } else {
+ this.toggle();
+ }
+ }
+
private _getAnimationClassForCheckStateTransition(
oldState: TransitionCheckState, newState: TransitionCheckState): string {
var animSuffix: string;
diff --git a/src/components/radio/radio.scss b/src/components/radio/radio.scss
index d1589500e1a2..24d66cc2cf78 100644
--- a/src/components/radio/radio.scss
+++ b/src/components/radio/radio.scss
@@ -1,5 +1,6 @@
@import "default-theme";
@import "variables";
+@import "mixins";
$md-radio-size: $md-toggle-size !default;
@@ -26,34 +27,6 @@ md-radio-button {
width: $md-radio-size;
}
-// TODO(mtlin): Replace when ink ripple component is implemented.
-// A placeholder ink ripple, shown when keyboard focused.
-.md-ink-ripple {
- background-color: md-color($md-accent);
- border-radius: 50%;
- height: 48px;
- left: 10px;
- opacity: 0;
- pointer-events: none;
- position: absolute;
- top: 10px;
- transform: translate(-50%,-50%);
- transition: opacity ease 0.28s, background-color ease 0.28s;
- width: 48px;
- overflow: hidden;
-
- // Fade in when radio focused.
- .md-radio-focused & {
- opacity: 0.1;
- }
-
- // TODO(mtlin): This corresponds to disabled focus state, but it's unclear how to enter into
- // this state.
- .md-radio-disabled & {
- background: #000;
- }
-}
-
// The outer circle for the radio, always present.
.md-radio-outer-circle {
border-color: md-color($md-foreground, secondary-text);
@@ -117,17 +90,12 @@ md-radio-button {
// Underlying native input element.
// Visually hidden but still able to respond to focus.
.md-radio-input {
- position: absolute;
- width: 0;
- height: 0;
- margin: 0;
- padding: 0;
- opacity: 0;
- appearance: none;
- border: none;
+ @include md-visually-hidden;
}
// Basic disabled state.
.md-radio-disabled, .md-radio-disabled .md-radio-label {
cursor: default;
}
+
+@include md-temporary-ink-ripple(radio);
diff --git a/src/core/style/_mixins.scss b/src/core/style/_mixins.scss
index b9445b392c7a..b760828f1773 100644
--- a/src/core/style/_mixins.scss
+++ b/src/core/style/_mixins.scss
@@ -24,4 +24,34 @@
position: absolute;
text-transform: none;
width: 1px;
+}
+
+@mixin md-temporary-ink-ripple($component) {
+ // TODO(mtlin): Replace when ink ripple component is implemented.
+ // A placeholder ink ripple, shown when keyboard focused.
+ .md-ink-ripple {
+ background-color: md-color($md-accent);
+ border-radius: 50%;
+ height: 48px;
+ left: 50%;
+ opacity: 0;
+ overflow: hidden;
+ pointer-events: none;
+ position: absolute;
+ top: 50%;
+ transform: translate(-50%,-50%);
+ transition: opacity ease 0.28s, background-color ease 0.28s;
+ width: 48px;
+
+ // Fade in when radio focused.
+ .md-#{$component}-focused & {
+ opacity: 0.1;
+ }
+
+ // TODO(mtlin): This corresponds to disabled focus state, but it's unclear how to enter into
+ // this state.
+ .md-#{$component}-disabled & {
+ background: #000;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/demo-app/checkbox/checkbox-demo.ts b/src/demo-app/checkbox/checkbox-demo.ts
index 8f4a9b154405..7e4584697b9e 100644
--- a/src/demo-app/checkbox/checkbox-demo.ts
+++ b/src/demo-app/checkbox/checkbox-demo.ts
@@ -40,8 +40,11 @@ class MdCheckboxDemoNestedChecklist {
}
];
- allComplete(tasks: Task[]): boolean {
- return tasks.every(t => t.completed);
+ allComplete(task: Task): boolean {
+ let subtasks = task.subtasks;
+ return subtasks.every(t => t.completed) ? true
+ : subtasks.every(t => !t.completed) ? false
+ : task.completed;
}
someComplete(tasks: Task[]): boolean {
@@ -52,10 +55,6 @@ class MdCheckboxDemoNestedChecklist {
setAllCompleted(tasks: Task[], completed: boolean) {
tasks.forEach(t => t.completed = completed);
}
-
- updateOnSubtaskChange(task: Task) {
- task.completed = this.allComplete(task.subtasks);
- }
}
@Component({
diff --git a/src/demo-app/checkbox/nested-checklist.html b/src/demo-app/checkbox/nested-checklist.html
index 309ffeddce79..4b721ab99759 100644
--- a/src/demo-app/checkbox/nested-checklist.html
+++ b/src/demo-app/checkbox/nested-checklist.html
@@ -2,7 +2,7 @@ Tasks