Dropdown Component (may be others) don’t work in web worker

Bug description:

I have an Angular 4 app that uses platform-webworker-dynamic to run it in a worker thread. The app uses a ng-bootstrap Ngbdropdown. I can click the drop down and see the drop down menu, but when I click anywhere on the browser, I see the message:

    at NgbDropdown._isEventFromToggle (ng-bootstrap.js:3494)
    at NgbDropdown.closeFromOutsideClick (ng-bootstrap.js:3477)
    at Object.eval [as handleEvent] (products.html:6)
    at handleEvent (core.umd.js:12079)
    at callWithDebugContext (core.umd.js:13540)
    at Object.debugHandleEvent [as handleEvent] (core.umd.js:13128)
    at dispatchEvent (core.umd.js:8691)
    at Array.eval (core.umd.js:9302)
    at NamedEventEmitter.dispatchEvent (platform-webworker.umd.js:1926)
    at WebWorkerRendererFactory2._dispatchEvent (platform-webworker.umd.js:2032)

Link to minimally-working plunker that reproduces the issue:

Use this example app to create an app.

Use the following code in ng-bootstrap.js to log the ngbDropdownToggle element.

/**
* @internal
*/
set: function (toggleElement) { this._toggleElement = toggleElement; console.log(toggleElement); },
enumerable: true,
configurable: true
});

When I uses platform-browser-dynamic single threaded app, I see the following button element:

image

When I use platform-webworker-dynamic, I see the following node:

image

Version of Angular, ng-bootstrap, and Bootstrap:

Angular: 4.2.5
ng-bootstrap: 1.0.0-alpha.27
Bootstrap: Bootstrap 4.0.0-alpha.6

UPDATE:

I assume the reason why the _toggleElement is not a button when platform-webworker-dynamic is used is due to the Angular components will not have access to the DOM in the web worker mode.

2 thoughts on “Dropdown Component (may be others) don’t work in web worker

  1. WebWorker support poses a completely new set of challenges and at the moment we are not testing in the web worker environment. We might come back to the topic post 1.0 but don’t expect anything to happen here before 1.0 (unless someone from the community steps in and helps out, of course).

  2. I’d imagine the issue with this is calling methods directly on DOM objects.

    isEventFrom($event) { return this._elementRef.nativeElement.contains($event.target); }
    

    This would have been easy to fix with Angular 2 as the invokeElementMethod method could be used from the renderer, but this is deprecated now and no longer guaranteed to work in Web Workers. The current advice from the Angular team is to create your own “mini-renderer” to handle these cases in different environments.

    angular/angular#13818
    angular/angular#15008 (comment)

    The Angular team themselves even say that their support for Webworkers is still experimental, having said that I would like to work on this anyway.

    Personally, I’m not a fan of listening to DOM events globally on the document in order to implement ‘click outside to close’ functionality. '(document:click)': 'closeFromClick($event)'. I think global event handlers (global anything for that matter) should be avoided.

    My suggestion would be to implement native Angular event handlers using the (click)="onMenuClicked()" syntax on the individual elements that we are concerned about. To close the dropdown from clicking outside of it, an invisible backdrop could be created behind (underneath?) the dropdown and add an event handler there.

    @pkozlowski-opensource any thoughts on this? If you agree with this approach, I’d be happy to make a pull request.