Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 27 additions & 13 deletions libs/single-spa-angular/src/single-spa-angular.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import type { LifeCycles } from 'single-spa';
import { getContainerElementAndSetTemplate } from 'single-spa-angular/internals';

import { SingleSpaPlatformLocation } from './platform-providers';
import type { SingleSpaAngularOptions, BootstrappedSingleSpaAngularOptions } from './types';
import type {
SingleSpaAngularOptions,
BootstrappedSingleSpaAngularOptions,
BootstrappedInstanceRef,
} from './types';

const defaultOptions = {
// Required options that will be set by the library consumer.
Expand All @@ -14,7 +18,7 @@ const defaultOptions = {
Router: undefined,
domElementGetter: undefined, // only optional if you provide a domElementGetter as a custom prop
updateFunction: () => Promise.resolve(),
bootstrappedRef: null,
instances: {},
};

export function singleSpaAngular<T>(userOptions: SingleSpaAngularOptions<T>): LifeCycles<T> {
Expand Down Expand Up @@ -53,7 +57,12 @@ export function singleSpaAngular<T>(userOptions: SingleSpaAngularOptions<T>): Li
};
}

async function bootstrap(options: BootstrappedSingleSpaAngularOptions): Promise<void> {
async function bootstrap(options: BootstrappedSingleSpaAngularOptions, props: any): Promise<void> {
const instance: BootstrappedInstanceRef = {
bootstrappedRef: null,
};
options.instances[props.name || props.appName] = instance;

if (options.NgZone === 'noop') {
return;
}
Expand All @@ -77,8 +86,8 @@ async function bootstrap(options: BootstrappedSingleSpaAngularOptions): Promise<
// Angular zone via `NgZone.run()`, which signals to Angular that something has changed
// and change detection should run.
// See https://github.com/single-spa/single-spa-angular/issues/86
options.routingEventListener = () => {
options.bootstrappedNgZone!.run(() => {});
instance.routingEventListener = () => {
instance.bootstrappedNgZone!.run(() => {});
};
}

Expand Down Expand Up @@ -126,6 +135,8 @@ async function mount(

const bootstrappedOptions = options as BootstrappedSingleSpaAngularOptions;

const instance = bootstrappedOptions.instances[props.name || props.appName];

if (options.NgZone !== 'noop') {
const ngZone: NgZone = bootstrappedRef.injector.get(options.NgZone);

Expand All @@ -140,22 +151,25 @@ async function mount(
skipLocationChangeOnNonImperativeRoutingTriggers(bootstrappedRef, options);
}

bootstrappedOptions.bootstrappedNgZone = ngZone;
window.addEventListener('single-spa:routing-event', bootstrappedOptions.routingEventListener!);
instance.bootstrappedNgZone = ngZone;
window.addEventListener('single-spa:routing-event', instance.routingEventListener!);
}

bootstrappedOptions.bootstrappedRef = bootstrappedRef;
instance.bootstrappedRef = bootstrappedRef;
return bootstrappedRef;
}

function unmount(options: BootstrappedSingleSpaAngularOptions): Promise<void> {
function unmount(options: BootstrappedSingleSpaAngularOptions, props: any): Promise<void> {
const instance = options.instances[props.name || props.appName];

return Promise.resolve().then(() => {
if (options.routingEventListener) {
window.removeEventListener('single-spa:routing-event', options.routingEventListener);
if (instance.routingEventListener) {
window.removeEventListener('single-spa:routing-event', instance.routingEventListener);
}

options.bootstrappedRef!.destroy();
options.bootstrappedRef = null;
instance.bootstrappedRef!.destroy();
instance.bootstrappedRef = null;
instance.bootstrappedNgZone = undefined;
});
}

Expand Down
4 changes: 4 additions & 0 deletions libs/single-spa-angular/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ export interface SingleSpaAngularOptions<
}

export interface BootstrappedSingleSpaAngularOptions extends SingleSpaAngularOptions {
instances: Record<string, BootstrappedInstanceRef>;
}

export interface BootstrappedInstanceRef {
bootstrappedRef: NgModuleRef<any> | ApplicationRef | null;
// All below properties can be optional in case of
// `SingleSpaAngularOpts.NgZone` is a `noop` string and not an `NgZone` class.
Expand Down
Loading