-
Notifications
You must be signed in to change notification settings - Fork 6.8k
fix(material-experimental/mdc-slider): fix change events on slider in… #22286
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
Changes from 3 commits
8363278
07e55a1
41d8d45
85ae780
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import {DOCUMENT} from '@angular/common'; | ||
import {Inject, Injectable} from '@angular/core'; | ||
import {SpecificEventListener} from '@material/base'; | ||
import {Subject, Subscription} from 'rxjs'; | ||
import {finalize} from 'rxjs/operators'; | ||
|
||
/** | ||
* Handles listening for all change and input events that occur on the document. | ||
* | ||
* This service exposes a single method #listen to allow users to subscribe to change and input | ||
* events that occur on the document. Since listening for these events on the document can be | ||
* expensive, we lazily attach listeners to the document when the first subscription is made, and | ||
* remove the listeners once the last observer unsubscribes. | ||
*/ | ||
@Injectable({providedIn: 'root'}) | ||
export class GlobalChangeAndInputListener<K extends 'change'|'input'> { | ||
|
||
/** The injected document if available or fallback to the global document reference. */ | ||
private _document: Document; | ||
|
||
/** Stores the subjects that emit the events that occur on the global document. */ | ||
private _subjects = new Map<K, Subject<Event>>(); | ||
|
||
/** Stores the event handlers that emit the events that occur on the global document. */ | ||
private _handlers = new Map<K, ((event: Event) => void)>(); | ||
|
||
constructor(@Inject(DOCUMENT) document: any) { | ||
this._document = document; | ||
} | ||
|
||
/** Returns a function for handling the given type of event. */ | ||
private _createHandlerFn(type: K): ((event: Event) => void) { | ||
return (event: Event) => { | ||
this._subjects.get(type)!.next(event); | ||
}; | ||
} | ||
|
||
/** Returns a subscription to global change or input events. */ | ||
listen(type: K, callback: SpecificEventListener<K>): Subscription { | ||
// This is the first subscription to these events. | ||
if (!this._subjects.get(type)) { | ||
const handlerFn = this._createHandlerFn(type).bind(this); | ||
this._subjects.set(type, new Subject<Event>()); | ||
this._handlers.set(type, handlerFn); | ||
this._document.addEventListener(type, handlerFn, true); | ||
} | ||
|
||
const subject = this._subjects.get(type)!; | ||
const handler = this._handlers.get(type)!; | ||
|
||
return subject.pipe(finalize(() => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Returning a subscription means that we can't use operators on the same stream. You can check out There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think for this case, returning a subscription is sufficient. I think if we reach a point where we need to start using operators on the stream it would make sense to extend the functionality this way, but for the current use case and for the foreseeable future, this should be fine |
||
// This is the last event listener unsubscribing. | ||
if (subject.observers.length === 1) { | ||
this._document.removeEventListener(type, handler, true); | ||
this._subjects.delete(type); | ||
this._handlers.delete(type); | ||
} | ||
})).subscribe(callback); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import {DOCUMENT} from '@angular/common'; | ||
import {Inject, Injectable} from '@angular/core'; | ||
import {SpecificEventListener} from '@material/base'; | ||
import {Subject, Subscription} from 'rxjs'; | ||
import {finalize} from 'rxjs/operators'; | ||
|
||
/** | ||
* Handles listening for all change events that occur on the document. | ||
* | ||
* This service exposes a single method #listen to allow users to subscribe to change events that | ||
* occur on the document. Since listening for all change events on the document can be expensive, | ||
* we lazily attach a single event listener to the document when the first subscription is made, | ||
* and remove the event listener once the last observer unsubscribes. | ||
*/ | ||
@Injectable({providedIn: 'root'}) | ||
export class GlobalChangeListener { | ||
crisbeto marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** The injected document if available or fallback to the global document reference. */ | ||
private _document: Document; | ||
|
||
/** Emits change events that occur on the global document. */ | ||
private _change: Subject<Event> = new Subject<Event>(); | ||
|
||
constructor(@Inject(DOCUMENT) document: any) { | ||
this._document = document; | ||
this._handler = this._handler.bind(this); | ||
} | ||
|
||
/** Emits the given event from the change subject. */ | ||
private _handler(event: Event) { | ||
this._change.next(event); | ||
} | ||
|
||
/** Returns a subscription to global change events. */ | ||
listen <K extends 'change'>(callback: SpecificEventListener<K>): Subscription { | ||
// This is the first subscription to change events. | ||
if (this._change.observers.length === 0) { | ||
this._document.addEventListener('change', this._handler, true); | ||
} | ||
|
||
return this._change.pipe(finalize(() => { | ||
// This is the last change listener unsubscribing. | ||
if (this._change.observers.length === 1) { | ||
this._document.removeEventListener('change', this._handler, true); | ||
} | ||
})).subscribe(callback); | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.