Skip to content

Commit

Permalink
fix(platform-browser): DomEventsPlugin should always be the last pl…
Browse files Browse the repository at this point in the history
…ugin to be called for `supports()`.

This fixes the issues when `BrowserModule` is not the first module imported.

Fixes #37149 #37850
  • Loading branch information
JeanMeche committed May 21, 2023
1 parent 87b8aba commit f223c82
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 2 deletions.
4 changes: 4 additions & 0 deletions packages/platform-browser/src/dom/events/dom_events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import {EventManagerPlugin} from './event_manager';

@Injectable()
export class DomEventsPlugin extends EventManagerPlugin {
// EventManager needs to now which plugin is DomEventsPlugin.
// Using instanceof is not possible due to circular dependency.
readonly isDomEventPlugin = true;

constructor(@Inject(DOCUMENT) doc: any) {
super(doc);
}
Expand Down
11 changes: 10 additions & 1 deletion packages/platform-browser/src/dom/events/event_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,16 @@ export class EventManager {
plugins.forEach((plugin) => {
plugin.manager = this;
});
this._plugins = plugins.slice().reverse();

// Cannot use DomEventPlugin type here as it would create a circular deps
const otherPlugins = plugins.filter(p => !(p as any).isDomEventPlugin);
this._plugins = otherPlugins.slice().reverse();

// DomEventsPlugin.supports() always returns true, it should always be the last plugin.
const domEventPlugin = plugins.find(p => (p as any).isDomEventPlugin);
if (domEventPlugin) {
this._plugins.push(domEventPlugin);
}
}

/**
Expand Down
43 changes: 42 additions & 1 deletion packages/platform-browser/test/dom/events/event_manager_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@
*/

import {ɵgetDOM as getDOM} from '@angular/common';
import {Component, destroyPlatform, Inject, NgModule, provideZoneChangeDetection} from '@angular/core';
import {NgZone} from '@angular/core/src/zone/ng_zone';
import {TestBed} from '@angular/core/testing';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {BrowserModule} from '@angular/platform-browser/public_api';
import {DomEventsPlugin} from '@angular/platform-browser/src/dom/events/dom_events';
import {EventManager, EventManagerPlugin} from '@angular/platform-browser/src/dom/events/event_manager';
import {EVENT_MANAGER_PLUGINS, EventManager, EventManagerPlugin} from '@angular/platform-browser/src/dom/events/event_manager';

import {createMouseEvent, el} from '../../../testing/src/browser_util';

Expand Down Expand Up @@ -487,6 +491,43 @@ describe('EventManager', () => {
done();
});
});

it('should always order the plugins with DomEventsPlugin being last', (done) => {
destroyPlatform();
const app = getDOM().createElement('app', doc);
doc.body.appendChild(app);
class Plugin {}
@NgModule({
providers: [
{
provide: EVENT_MANAGER_PLUGINS,
useClass: Plugin,
multi: true,
},
],
})
class EventModule {
}

@Component({
selector: 'app',
template: '',
})
class MyComp {
constructor(EventManager: EventManager) {
const plugins = (EventManager as any)._plugins;
expect(plugins[1]).toBeInstanceOf(Plugin);
expect(plugins[plugins.length - 1]).toBeInstanceOf(DomEventsPlugin);
done();
}
}

@NgModule({imports: [EventModule, BrowserModule], bootstrap: [MyComp], declarations: [MyComp]})
class SomeModule {
}

platformBrowserDynamic().bootstrapModule(SomeModule);
});
});
})();

Expand Down

0 comments on commit f223c82

Please sign in to comment.