fix(common): prevent duplicate URL change notifications (#37404)
Prevent duplicate notifications from being emitted when multiple URL change listeners are registered using Location#onUrlChange. PR Close #37404
This commit is contained in:
parent
b5d1c8b05a
commit
fff424a35f
@ -64,6 +64,7 @@ export class Location {
|
|||||||
_platformLocation: PlatformLocation;
|
_platformLocation: PlatformLocation;
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_urlChangeListeners: ((url: string, state: unknown) => void)[] = [];
|
_urlChangeListeners: ((url: string, state: unknown) => void)[] = [];
|
||||||
|
private _urlChangeSubscription?: SubscriptionLike;
|
||||||
|
|
||||||
constructor(platformStrategy: LocationStrategy, platformLocation: PlatformLocation) {
|
constructor(platformStrategy: LocationStrategy, platformLocation: PlatformLocation) {
|
||||||
this._platformStrategy = platformStrategy;
|
this._platformStrategy = platformStrategy;
|
||||||
@ -194,10 +195,13 @@ export class Location {
|
|||||||
*/
|
*/
|
||||||
onUrlChange(fn: (url: string, state: unknown) => void) {
|
onUrlChange(fn: (url: string, state: unknown) => void) {
|
||||||
this._urlChangeListeners.push(fn);
|
this._urlChangeListeners.push(fn);
|
||||||
this.subscribe(v => {
|
|
||||||
|
if (!this._urlChangeSubscription) {
|
||||||
|
this._urlChangeSubscription = this.subscribe(v => {
|
||||||
this._notifyUrlChangeListeners(v.url, v.state);
|
this._notifyUrlChangeListeners(v.url, v.state);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_notifyUrlChangeListeners(url: string = '', state: unknown) {
|
_notifyUrlChangeListeners(url: string = '', state: unknown) {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {CommonModule, Location, LocationStrategy, PathLocationStrategy, PlatformLocation} from '@angular/common';
|
import {CommonModule, Location, LocationStrategy, PathLocationStrategy, PlatformLocation} from '@angular/common';
|
||||||
import {MockPlatformLocation} from '@angular/common/testing';
|
import {MockLocationStrategy, MockPlatformLocation} from '@angular/common/testing';
|
||||||
import {inject, TestBed} from '@angular/core/testing';
|
import {inject, TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
const baseUrl = '/base';
|
const baseUrl = '/base';
|
||||||
@ -84,7 +84,7 @@ describe('Location Class', () => {
|
|||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [CommonModule],
|
imports: [CommonModule],
|
||||||
providers: [
|
providers: [
|
||||||
{provide: LocationStrategy, useClass: PathLocationStrategy},
|
{provide: LocationStrategy, useClass: MockLocationStrategy},
|
||||||
{
|
{
|
||||||
provide: PlatformLocation,
|
provide: PlatformLocation,
|
||||||
useFactory: () => {
|
useFactory: () => {
|
||||||
@ -113,5 +113,30 @@ describe('Location Class', () => {
|
|||||||
expect((location as any)._urlChangeListeners.length).toBe(1);
|
expect((location as any)._urlChangeListeners.length).toBe(1);
|
||||||
expect((location as any)._urlChangeListeners[0]).toEqual(changeListener);
|
expect((location as any)._urlChangeListeners[0]).toEqual(changeListener);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should only notify listeners once when multiple listeners are registered', () => {
|
||||||
|
const location = TestBed.inject(Location);
|
||||||
|
const locationStrategy = TestBed.inject(LocationStrategy) as MockLocationStrategy;
|
||||||
|
let notificationCount = 0;
|
||||||
|
|
||||||
|
function incrementChangeListener(url: string, state: unknown) {
|
||||||
|
notificationCount += 1;
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function noopChangeListener(url: string, state: unknown) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
location.onUrlChange(incrementChangeListener);
|
||||||
|
location.onUrlChange(noopChangeListener);
|
||||||
|
|
||||||
|
expect(notificationCount).toBe(0);
|
||||||
|
|
||||||
|
locationStrategy.simulatePopState('/test');
|
||||||
|
|
||||||
|
expect(notificationCount).toBe(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user