ngx-parent-injector
v3.0.1
Published
Inject parent window services (and other injectables) into child window Angular apps, allowing parent and child window apps to share data and behave as if they were a single app. ## Usage
Downloads
4
Maintainers
Readme
ngx-parent-injector
Inject parent window services (and other injectables) into child window Angular apps, allowing parent and child window apps to share data and behave as if they were a single app.
Usage
ngx-parent-angular
is intended to be used in a multi-window Angular app, where the parent and child windows are running separate Angular apps. For an overview on how to set up this kind of app, please see the Demo App.
- Add
NgxParentInjectorModule
to theimports
of the root Angular module of the parent window. - Add
NgxParentInjectorChildModule.forRoot(...)
to theimports
of the root Angular module of each child window.
To inject a parent window's service in a child window:
- In the parent window, the service's injection token must be explicitly exposed to the child window by calling
exposeToken()
. - In the child window, we request the parent window's service by using Angular's builtin
@Inject
decorator together with thegetParentToken()
function.
Sample
parentWindow/parentWindow.module.ts
// Angular imports omitted
import { exposeToken, NgxParentInjectorModule } from 'ngx-parent-injector';
import { SomeParentService } from './someParentModule/someParent.service';
import { SOME_PARENT_TOKEN } from './someParentModule/someParent.token';
@NgModule({
// other metadata
imports: [
// other imports
NgxParentInjectorModule,
],
providers: [{
provide: SOME_PARENT_TOKEN,
useValue: "I'm an injection token value"
}]
})
export class ParentWindowModule {
public constructor() {
// 1. expose InjectionTokens in the parent window
exposeToken(SomeParentService);
exposeToken(SOME_PARENT_TOKEN);
}
}
childWindow/childWindow.module.ts
// Angular imports omitted
import { NgxParentInjectorChildModule } from 'ngx-parent-injector/child';
import { ChildWindowComponent } from './childWindow.component.ts';
@NgModule({
// other metadata
imports: [
// other imports
NgxParentInjectorChildModule.forRoot(),
],
declarations: [ChildWindowComponent],
bootstrap: [ChildWindowComponent]
})
export class ChildWindowModule {}
childWindow/childWindow.component.ts
// Angular imports omitted
import { getParentToken } from 'ngx-parent-injector/child';
import { SomeParentService } from '../parentWindow/someParentModule/someParent.service';
import { SOME_PARENT_TOKEN } from '../parentWindow/someParentModule/someParent.token';
@Component({
template: '<div>Parent Token Value: {{ injectionTokenValue }}</div>'
})
export class ChildWindowComponent {
public constructor(
// 2. request parent window services or injectable values.
@Inject(getParentToken(SomeParentService)) public someParentService: SomeParentService,
@Inject(getParentToken(SOME_PARENT_TOKEN)) public injectionTokenValue: string
) {
// Injected dependencies from parent window are ready to use
}
}
Testing
Unit testing child window code which consumes any code from ngx-parent-injector/child
requires some additional steps.
- Set
testMode: true
in the options passed toNgxParentInjectorChild.forRoot
. This can be achieved by adjustingenvironment.ts
to include a flag indicating test mode, and setting that flag totrue
during test builds by usingfileReplacements
inangular.json
's test block. - Since
getParentToken(token)
will simply returntoken
unchanged if it can't find the corresponding token on the parent app, you can provide mocks fortoken
as you normally would in the testing module. - Call
disableWarnings()
before running tests to prevent warnings from polluting the test output.
See the Demo App for an example of unit tests.
Conceptual overview
ngx-parent-injector works based on two separate concepts.
Enabling child windows to inject services from the parent window.
The parent window's Angular injector as well as chosen injection tokens are attached to the parent's global window object.
Child windows can then access the parent window's injector and injection tokens using window.opener
, and use them to get the runtime instances of the services in the child windows. This process is made unobtrusive in child Angular apps by using Angular's built in provider system and @Inject
decorator.
Injection tokens (like constructor functions for services) will have separate in-memory representations in parent and child window apps, even if they are imported from the same source file. This means that simply using an injection token from a child window's app with the parent window's injector instance will not yield the expected result. For this reason, ngx-parent-injector
relies on associating strings to injection tokens so that for any given child-window injection token, the corresponding parent-window token can be retrieved. For services, the constructor function's name
value is used, and for instances of InjectionToken
, the result of calling toString()
is used. Note that this means that name collisions are technically possible, although in practice it rarely occurs. It also means that class names should not be mangled/obfuscated, because in general the same class will be obfuscated to a different symbol in parent and child apps.
Triggering change detection in both the parent and child windows at appropriate moments.
By injecting services from a parent Angular app into a child Angular app, the apps become logically entangled. As a consequence, any change in the parent app may require a child app to update its view, and vice versa. This is achieved by injecting the parent app's NgZone
service into the child app using the process described above. Every time the parent window's NgZone
's microtask queue empties, we manually trigger a change detection in the child window in order to update the child app's view in response to an event in the parent app. Conversely, whenever the microtask queue of the child app's own NgZone
empties, we push an item to the parent app NgZone
's microtask queue to propagate events which originated in the child app to the parent app (as well as to trigger change detection in other child apps).
Build
Run ng build ngx-parent-injector
to build the project. The build artifacts will be stored in the dist/ngx-parent-injector
directory.
Publishing
After building your library with ng build ngx-parent-injector
, go to the dist folder cd dist/ngx-parent-injector
and run npm publish
.
Further help
To get more help on the Angular CLI use ng help
or go check out the Angular CLI Overview and Command Reference page.