Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "fix(slide-toggle): invalid model change event (#4140)" #4218

Merged
merged 1 commit into from
Apr 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 11 additions & 14 deletions src/lib/slide-toggle/slide-toggle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,23 +295,18 @@ describe('MdSlideToggle', () => {
expect(slideToggleControl.pristine).toBe(true);
expect(slideToggleControl.touched).toBe(false);

// After changing the value from the view, the control should
// become dirty (not pristine), but remain untouched if focus is still there.
// After changing the value programmatically, the control should
// become dirty (not pristine), but remain untouched.
slideToggle.checked = true;

// Dispatch a change event on the input element to fake a user interaction that triggered
// the state change.
dispatchFakeEvent(inputElement, 'change');

fixture.detectChanges();

expect(slideToggleControl.valid).toBe(true);
expect(slideToggleControl.pristine).toBe(false);
expect(slideToggleControl.touched).toBe(false);

// Once the input element looses focus, the control should remain dirty but should
// also turn touched.
dispatchFakeEvent(inputElement, 'blur');
// After a user interaction occurs (such as a click), the control should remain dirty and
// now also be touched.
labelElement.click();
fixture.detectChanges();

expect(slideToggleControl.valid).toBe(true);
Expand All @@ -329,13 +324,13 @@ describe('MdSlideToggle', () => {
expect(slideToggleControl.touched).toBe(false);
expect(slideToggleElement.classList).toContain('mat-checked');

// Once the input element looses focus, the control should remain dirty but should
// also turn touched.
dispatchFakeEvent(inputElement, 'blur');
// After a user interaction occurs (such as a click), the control should remain dirty and
// now also be touched.
inputElement.click();
fixture.detectChanges();

expect(slideToggleControl.touched).toBe(true);
expect(slideToggleElement.classList).toContain('mat-checked');
expect(slideToggleElement.classList).not.toContain('mat-checked');
});

// TODO(kara): update when core/testing adds fix
Expand Down Expand Up @@ -439,13 +434,15 @@ describe('MdSlideToggle', () => {
}));

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();
Expand Down
44 changes: 24 additions & 20 deletions src/lib/slide-toggle/slide-toggle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export class MdSlideToggle implements OnDestroy, AfterContentInit, ControlValueA

// A unique id for the slide-toggle. By default the id is auto-generated.
private _uniqueId = `md-slide-toggle-${++nextId}`;
private _checked: boolean = false;
private _color: string;
private _slideRenderer: SlideToggleRenderer = null;
private _disabled: boolean = false;
Expand All @@ -85,9 +86,6 @@ export class MdSlideToggle implements OnDestroy, AfterContentInit, ControlValueA
/** Whether the label should appear after or before the slide-toggle. Defaults to 'after' */
@Input() labelPosition: 'before' | 'after' = 'after';

/** Whether the slide-toggle element is checked or not */
@Input() checked: boolean = false;

/** Used to set the aria-label attribute on the underlying input element. */
@Input('aria-label') ariaLabel: string = null;

Expand Down Expand Up @@ -138,30 +136,29 @@ export class MdSlideToggle implements OnDestroy, AfterContentInit, ControlValueA
}

/**
* This function will called if the underlying input changed its value through user interaction.
* The onChangeEvent method will be also called on click.
* This is because everything for the slide-toggle is wrapped inside of a label,
* which triggers a onChange event on click.
*/
_onChangeEvent(event: Event) {
// We always have to stop propagation on the change event.
// Otherwise the change event, from the input element, will bubble up and
// emit its event object to the component's `change` output.
event.stopPropagation();

// Sync the value from the underlying input element with the slide-toggle component.
this.checked = this._inputElement.nativeElement.checked;
// Once a drag is currently in progress, we do not want to toggle the slide-toggle on a click.
if (!this.disabled && !this._slideRenderer.dragging) {
this.toggle();

// Emit our custom change event if the native input emitted one.
// It is important to only emit it, if the native input triggered one, because we don't want
// to trigger a change event, when the `checked` variable changes programmatically.
this._emitChangeEvent();
// Emit our custom change event if the native input emitted one.
// It is important to only emit it, if the native input triggered one, because
// we don't want to trigger a change event, when the `checked` variable changes for example.
this._emitChangeEvent();
}
}

_onInputClick(event: Event) {
// In some situations the user will release the mouse on the label element. The label element
// redirects the click to the underlying input element and will result in a value change.
// Prevent the default behavior if dragging, because the value will be set after drag.
if (this._slideRenderer.dragging) {
event.preventDefault();
}
this.onTouched();

// We have to stop propagation for click events on the visual hidden input element.
// By default, when a user clicks on a label element, a generated click event will be
Expand Down Expand Up @@ -198,6 +195,16 @@ export class MdSlideToggle implements OnDestroy, AfterContentInit, ControlValueA
this._focusOriginMonitor.focusVia(this._inputElement.nativeElement, this._renderer, 'keyboard');
}

/** Whether the slide-toggle is checked. */
@Input()
get checked() { return !!this._checked; }
set checked(value) {
if (this.checked !== !!value) {
this._checked = value;
this.onChange(this._checked);
}
}

/** The color of the slide-toggle. Can be primary, accent, or warn. */
@Input()
get color(): string { return this._color; }
Expand Down Expand Up @@ -238,15 +245,12 @@ export class MdSlideToggle implements OnDestroy, AfterContentInit, ControlValueA
}
}

/**
* Emits a change event on the `change` output. Also notifies the FormControl about the change.
*/
/** Emits the change event to the `change` output EventEmitter */
private _emitChangeEvent() {
let event = new MdSlideToggleChange();
event.source = this;
event.checked = this.checked;
this.change.emit(event);
this.onChange(this.checked);
}


Expand Down