Reputation: 11641
In my angular application I listen to resize
event and update the breakpoint name in breakpointChanged
subject:
breakpointChanged = new Subject();
resize$ = fromEvent(window, "resize").pipe(
startWith(() => []),
map(() => [window.innerHeight, window.innerWidth]),
tap(([height, width]) => {
const name = this.breakpoint(width);
this.breakpointChanged.next(name);
})
);
Base on the breakpoint name I decided when the drawer should be open or not:
drawerOpened$ = this.breakpointChanged.pipe(
distinctUntilChanged(),
map((breakpointName) => {
return breakpointName !== "xs"; // if it's not xs breakpoint then it's true mean it's open.
})
);
I also want to use distinctUntilChanged
because if the breakpoint not changed I don't want to activate the stream.
And in ngOnInit I subscribe to the resize
stream. And I do it in runOutsideAngular
, so I wont trigger change detection every time the resize happens.
this.zone.runOutsideAngular(() => {
this.resize$.subscribe();
});
The problem is the view doesn't update.
Only when I wrap the this.breakpointChanged.next(name);
with this.zone.run(() => {})
it's works but if I do that I'll trigger change detection - always when the resize happens. which is bad thing.
Any idea how to solve this problem and make it nice and clean?
In the same context, how async
pipe doesn't make change detection? the value is changing and async
should subscribe and trigger when it's the value changes.
Upvotes: 2
Views: 710
Reputation: 12357
Add a debounceTime(250)
as the first param of the fromEvent(...).pipe(...)
Wrap the breakpoint.next
in the zone.run(..)
just as you were doing, and also keep the same runOutsideAngular
approach
Change detection will run after every 250ms duration as you resize, which is what you're after - a good user experience plus limited/less change detection
Upvotes: 0
Reputation: 17504
That's a nice question. May be we can reduce the complexity by using debounceTime()
as below:
resize$ = fromEvent(window, "resize").pipe(
startWith(() => []),
debounceTime(1000),
map(() => [window.innerHeight, window.innerWidth]),
tap(([height, width]) => {
console.log(height);
const name = this.breakpoint(width);
this.breakpointChanged.next(name);
})
);
and removing this.zone.runOutsideAngular
ngOnInit() {
this.resize$.subscribe();
}
no matter how many times it is resized, the event will be emitted after 1 second.
Here is what I tried in your example.
Let me know if this helps
Upvotes: 1