Issue
- Create and deploy an Angular custom element Client Extension, for example: liferay-sample-custom-element-3 .
- Drag the custom element into a page and navigate with Single Page Application enabled: The angular application does not load after navigating between different pages.
Environment
- DXP 7.4 and Quarterly Releases
Resolution
- The custom application should be aware of the page navigation and events with SPA so the code should be updated:
-
Option 1: Fully functional
This approach will avoid a double load of the component detected using the second approach defined on this article, detected adding this log message to AppModule.
ngOnInit() { console.log('liferay-sample-custom-element-3 loaded'); }
Avoid this double load removing boostrap parameter and adding ngDoBootstrap, find an example below:
import {Injector, NgModule} from '@angular/core'; import {createCustomElement} from '@angular/elements'; import {BrowserModule} from '@angular/platform-browser'; import {AppComponent} from './app.component'; @NgModule({ // Remove boostrap: [AppComponent]
declarations: [AppComponent], imports: [BrowserModule], providers: [], }) export class AppModule { constructor(private injector: Injector) { const appElement = createCustomElement(AppComponent, { injector: this.injector }); customElements.define("liferay-sample-custom-element-3", appElement); } // Use ngDoBootsrap constructor ngDoBootstrap() {} } -
Option 2: The second approach involves using Angular's standard bootstrapping process by removing ngDoBootstrap and modifying the constructor.
-
...
constructor(private injector: Injector) {
const appElement = createCustomElement(AppComponent, {
injector: this.injector
});
customElements.define("liferay-sample-custom-element-3", appElement);
}
...(*) A doble load on this option has been detected
-
-
Option 3: The third approach maintains the use of the ngDoBootstrap hook, but it needs two changes:
- Remove the bootstrap property from the @ngModule annotation
- Import ApplicationRef, pass it to the ngDoBootstrap hook, and bootstrap the custom element.
-
// Import ApplicationRef
import {ApplicationRef, Injector, NgModule} from '@angular/core';
import {createCustomElement} from '@angular/elements';
import {BrowserModule} from '@angular/platform-browser';
import {AppComponent} from './app.component';
// Remove boostrap: [AppComponent]
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [],
})
export class AppModule {
constructor(private injector: Injector) {}
// Pass the ApplicationRef to the hook
ngDoBootstrap(appRef: ApplicationRef) {
const AppComponentElement = createCustomElement(AppComponent, {
injector: this.injector,
});
customElements.define(
'liferay-sample-custom-element-3',
AppComponentElement
);
// Manually bootstrap the component
appRef.bootstrap(AppComponent);
}
}
...
-
Option 1: Fully functional
- One of this options will be implemented at some point in the future in the code of the example liferay-sample-custom-element-3.
Additional Information