diff --git a/src/lib/checkbox/checkbox.html b/src/lib/checkbox/checkbox.html index e07b211a679a..78090d6208b5 100644 --- a/src/lib/checkbox/checkbox.html +++ b/src/lib/checkbox/checkbox.html @@ -1,6 +1,6 @@ + [class.mat-checkbox-inner-container-no-side-margin]="!checkboxLabel.textContent.trim()"> - + diff --git a/src/lib/checkbox/checkbox.spec.ts b/src/lib/checkbox/checkbox.spec.ts index 9c0d81a7dd08..6ac686094a9c 100644 --- a/src/lib/checkbox/checkbox.spec.ts +++ b/src/lib/checkbox/checkbox.spec.ts @@ -765,19 +765,57 @@ describe('MdCheckbox', () => { }); describe('without label', () => { - let checkboxDebugElement: DebugElement; - let checkboxNativeElement: HTMLElement; + let testComponent: CheckboxWithoutLabel; + let checkboxElement: HTMLElement; + let checkboxInnerContainer: HTMLElement; - it('should add a css class to inner-container to remove side margin', () => { + beforeEach(() => { fixture = TestBed.createComponent(CheckboxWithoutLabel); + + const checkboxDebugEl = fixture.debugElement.query(By.directive(MdCheckbox)); + + testComponent = fixture.componentInstance; + checkboxElement = checkboxDebugEl.nativeElement; + checkboxInnerContainer = checkboxDebugEl + .query(By.css('.mat-checkbox-inner-container')).nativeElement; + }); + + it('should remove margin for checkbox without a label', () => { fixture.detectChanges(); - checkboxDebugElement = fixture.debugElement.query(By.directive(MdCheckbox)); - checkboxNativeElement = checkboxDebugElement.nativeElement; - let checkboxInnerContainerWithoutMarginCount = checkboxNativeElement - .querySelectorAll('.mat-checkbox-inner-container-no-side-margin').length; - expect(checkboxInnerContainerWithoutMarginCount).toBe(1); + expect(checkboxInnerContainer.classList) + .toContain('mat-checkbox-inner-container-no-side-margin'); }); + + it('should not remove margin if initial label is set through binding', async(() => { + testComponent.label = 'Some content'; + fixture.detectChanges(); + + expect(checkboxInnerContainer.classList) + .not.toContain('mat-checkbox-inner-container-no-side-margin'); + })); + + it('should re-add margin if label is added asynchronously', async(() => { + fixture.detectChanges(); + + expect(checkboxInnerContainer.classList) + .toContain('mat-checkbox-inner-container-no-side-margin'); + + testComponent.label = 'Some content'; + fixture.detectChanges(); + + // Wait for the MutationObserver to detect the content change and for the cdkObserveContent + // to emit the change event to the checkbox. + setTimeout(() => { + // The MutationObserver from the cdkObserveContent directive detected the content change + // and notified the checkbox component. The checkbox then marks the component as dirty + // by calling `markForCheck()`. This needs to be reflected by the component template then. + fixture.detectChanges(); + + expect(checkboxInnerContainer.classList) + .not.toContain('mat-checkbox-inner-container-no-side-margin'); + }, 1); + })); }); }); @@ -889,6 +927,8 @@ class CheckboxWithFormControl { /** Test component without label */ @Component({ - template: `` + template: `{{ label }}` }) -class CheckboxWithoutLabel {} +class CheckboxWithoutLabel { + label: string; +} diff --git a/src/lib/checkbox/checkbox.ts b/src/lib/checkbox/checkbox.ts index 9874e7697b47..8f8b59018b6e 100644 --- a/src/lib/checkbox/checkbox.ts +++ b/src/lib/checkbox/checkbox.ts @@ -158,14 +158,6 @@ export class MdCheckbox extends _MdCheckboxMixinBase /** The native ` element */ @ViewChild('input') _inputElement: ElementRef; - @ViewChild('labelWrapper') _labelWrapper: ElementRef; - - /** Whether the checkbox has label */ - _hasLabel(): boolean { - const labelText = this._labelWrapper.nativeElement.textContent || ''; - return !!labelText.trim().length; - } - /** Called when the checkbox is blurred. Needed to properly implement ControlValueAccessor. */ @ViewChild(MdRipple) _ripple: MdRipple; @@ -272,6 +264,14 @@ export class MdCheckbox extends _MdCheckboxMixinBase return this.disableRipple || this.disabled; } + /** Method being called whenever the label text changes. */ + _onLabelTextChange() { + // This method is getting called whenever the label of the checkbox changes. + // Since the checkbox uses the OnPush strategy we need to notify it about the change + // that has been recognized by the cdkObserveContent directive. + this._changeDetectorRef.markForCheck(); + } + /** * Sets the model value. Implemented as part of ControlValueAccessor. * @param value Value to be set to the model. diff --git a/src/lib/checkbox/index.ts b/src/lib/checkbox/index.ts index 1987bac28630..cfcce8f5d697 100644 --- a/src/lib/checkbox/index.ts +++ b/src/lib/checkbox/index.ts @@ -1,11 +1,11 @@ import {NgModule} from '@angular/core'; import {CommonModule} from '@angular/common'; -import {MdRippleModule, MdCommonModule, FocusOriginMonitor} from '../core'; +import {MdRippleModule, MdCommonModule, FocusOriginMonitor, ObserveContentModule} from '../core'; import {MdCheckbox} from './checkbox'; @NgModule({ - imports: [CommonModule, MdRippleModule, MdCommonModule], + imports: [CommonModule, MdRippleModule, MdCommonModule, ObserveContentModule], exports: [MdCheckbox, MdCommonModule], declarations: [MdCheckbox], providers: [FocusOriginMonitor]