-
Notifications
You must be signed in to change notification settings - Fork 6.8k
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
feat(observe-content): refactor so logic can be used without directive #11170
Conversation
src/cdk/observers/observe-content.ts
Outdated
export class ContentObserverFactory { | ||
constructor(private _mutationObserverFactory: MutationObserverFactory, private _ngZone: NgZone) {} | ||
|
||
create(element: Element, debounce?: number) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we call this one observe
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't actually start observing, it just creates the observer
src/cdk/observers/observe-content.ts
Outdated
|
||
|
||
/** A class that observes an element for content changes. */ | ||
export class ContentObserver { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could simplify the whole approach a bit by not having this class to begin with. Instead, ContentObserverFactory.observe
can return an observable which creates a MutationObserver
when something subscribes to it and then tears down the observer when there are no more subscriptions. We did something similar in the ScrollDispatcher
. It means that we lose the ability to pause an observer and resume it with the same MutationObserver
, but AFAIK there isn't much overhead to creating mutation observers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I propose keeping ContentObserverFactory
how it was before (docs private API that we use internally), and then making ContentObserver
an injectable that works like ScrollDispatcher
and BreakpointObserver
; I think having the user need to interact with two different types is more work than it has to be
@@ -120,6 +120,57 @@ describe('Observe content', () => { | |||
}); | |||
}); | |||
|
|||
describe('Observe content injectable', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since all the logic is in the injectable, maybe we should put all of the tests under this suite?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to leave the above tests alone to show that this doesn't change the behavior of the directive. Yes, we could add more tests here as well, but it felt like it would just be retesting the same logic
82e86d9
to
492e9fb
Compare
Comments addressed. I also removed the part where we observe outside the zone. I think if it's a public API that returns an |
src/cdk/observers/observe-content.ts
Outdated
/** A factory that creates ContentObservers. */ | ||
@Injectable({providedIn: 'root'}) | ||
export class ContentObserver { | ||
private _observedElements = new Map<Element, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be a WeakMap
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops, I made it a Map
so I could loop on destroy and clean up, but forgot to actually do that.
src/cdk/observers/observe-content.ts
Outdated
|
||
constructor(private _mutationObserverFactory: MutationObserverFactory) {} | ||
|
||
observe(element: Element, debounce?: number): Observable<MutationRecord[]> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As user-facing JsDoc here and other method descriptions throughout?
src/cdk/observers/observe-content.ts
Outdated
|
||
constructor(private _mutationObserverFactory: MutationObserverFactory) {} | ||
|
||
observe(element: Element, debounce?: number): Observable<MutationRecord[]> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reasoning behind making debouce
part of the API rather than letting subscribers debounce (or throttle or filter, etc) however they want?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I put it here because it was part of the directive's logic, but I agree it doesn't really belong here, will remove.
src/cdk/observers/observe-content.ts
Outdated
|
||
private _unobserveElement(element: Element) { | ||
if (this._observedElements.has(element)) { | ||
if (!--this._observedElements.get(element)!.count) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you break up the decrement and the conditional? It's generally easier to understand that way, since many people have a hard time remembering the different between --value
and value--
|
||
subscription.unsubscribe(); | ||
}))); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Should add a test for observing the same element twice, unobserving once and ensuring you still get events.
- Should add a test for debouncing if it's part of the API
42c014d
to
45cc979
Compare
PTAL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@jelbourn I moved the |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
No description provided.