angular-extensions / elements

Lazy load Angular Elements (or any other web components / custom elements ) with ease!
https://angular-extensions.github.io/elements/
MIT License
318 stars 40 forks source link

DOMException: CustomElementRegistry.define 'ust-frontend' has already been defined as a custom element #63

Open schnalfy opened 4 years ago

schnalfy commented 4 years ago

Hello everybody,

i have a problem with "multiple different dynamic elements I would like to load 2 web components. The second compnent always uses the js-file of the first component. Therefore the error 'ust-frontend' has already been defined as a custom element. I have built the web components according to the following pattern.

I hope someone can help me.

Thanks

<< ----------------------------------->> web component

import { AppRoutingModule } from './app-routing.module'; import { HttpClientModule } from '@angular/common/http'; import { BrowserModule } from '@angular/platform-browser'; import { NgModule, Injector } from '@angular/core'; import { Router } from '@angular/router'; import { Location} from '@angular/common'; import { createCustomElement } from '@angular/elements';

import { AppComponent } from './app.component'; import { EcbrateComponent } from './component/ecbrate/ecbrate.component';

import { FormsModule } from '@angular/forms';

@NgModule({ declarations: [ AppComponent, EcbrateComponent ], imports: [ BrowserModule, AppRoutingModule, FormsModule, HttpClientModule ], providers: [], entryComponents: [AppComponent] }) export class AppModule { constructor(private injector: Injector, private router: Router, private location: Location ) { const appElement = createCustomElement(AppComponent, { injector: this.injector }); console.log('define ecb-frontend'); customElements.define('ecb-frontend', appElement); console.log('defined ecb-frontend'); console.log(this.location); this.router.navigateByUrl(this.location.path(true)); console.log(this.router); this.location.subscribe(data => { console.log(data); this.router.navigateByUrl(data.url); }); } // tslint:disable-next-line: typedef ngDoBootstrap() {} }

<<---------------------------------------------------->>

lazy-element component

import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { url } from 'inspector';

@Component({ selector: 'app-lazy-element2', template: <ng-container *ngFor="let c of dynamicConfigs"> {{c.url}} <ax-lazy-element *axLazyElementDynamic= "c.tag, url: c.url; module: true" raised> </ax-lazy-element> </ng-container> }) export class LazyElement2Component implements OnInit {

elementUrl = ''; elementTag = ''; onDestroy: any; dynamicConfigs = [];

constructor(readonly activatedRoute: ActivatedRoute) { / this.onDestroy = this.activatedRoute; // tslint:disable-next-line: deprecation let componantName = ''; this.onDestroy.url.forEach( item => { item.forEach( pathItem => { console.log(pathItem.path); componantName = pathItem.path; }); }); this.elementTag = ''; this.elementUrl = 'http://localhost:4201/component/' + componantName + '/' + componantName + '.js'; console.log(this.elementUrl); this.elementTag = componantName; / this.dynamicConfigs = [ {url: 'http://localhost:4201/component/ust-frontend/ust-frontend.js', tag: 'ust-frontend'}, {url: 'http://localhost:4201/component/ecb-frontend/ecb-frontend.js', tag: 'ecb-frontend'} ]; }

ngOnInit(): void {}

// tslint:disable-next-line: use-lifecycle-interface ngOnDestroy() { // this.onDestroy.unsubscribe(); } }

<< --------------------------- >> app.module

import { BrowserModule } from '@angular/platform-browser'; import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { LazyElementsModule } from '@angular-extensions/elements'; import { CommonModule } from '@angular/common'; import { HttpClientModule } from '@angular/common/http';

import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { HeaderComponent } from './components/header/header.component'; import { HomeComponent } from './components/home/home.component'; import { DynamicLayoutComponent } from './components/dynamic-layout/dynamic-layout.component'; import { LazyElementComponent } from './components/lazy-element/lazy-element.component'; import { MainLayoutComponent } from './components/dynamic-layout/main-layout.component'; import { LoginComponent } from './components/login/login.component'; import { ReactiveFormsModule } from '@angular/forms'; import { LazyElement2Component } from './components/lazy-element2/lazy-element2.component';

@NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA], declarations: [ AppComponent, HeaderComponent, HomeComponent, DynamicLayoutComponent, LazyElementComponent, LazyElement2Component, MainLayoutComponent, LoginComponent ], imports: [ BrowserModule, AppRoutingModule, HttpClientModule, LazyElementsModule, CommonModule, ReactiveFormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule {}

tomastrajan commented 4 years ago

Hi @schnalfy !

Could you please properly format your code using 3 back ticks before and 3 back ticks after? Like this

function properlyFormated() {
    console.log('I acutally can read this...')
}

Also, the error says it all currently, you can not register the same element twice so you would most like have to re-organizae your code so that the registration logic happens only once per web-component.

schnalfy commented 4 years ago

Hello, Tomas,

the problem is that this error occurs when I try to load a second (not the same) web component. At the moment I think that the problem lies in the call of the web component. But that changes hourly ;) Do you have an example where you call two different web components?

Thanks Ralf

web component

import { AppRoutingModule } from './app-routing.module'; import { HttpClientModule } from '@angular/common/http'; import { BrowserModule } from '@angular/platform-browser'; import { NgModule, Injector } from '@angular/core'; import { Router } from '@angular/router'; import { Location} from '@angular/common'; import { createCustomElement } from '@angular/elements';

import { AppComponent } from './app.component'; import { EcbrateComponent } from './component/ecbrate/ecbrate.component';

import { FormsModule } from '@angular/forms';

@NgModule({ declarations: [ AppComponent, EcbrateComponent ], imports: [ BrowserModule, AppRoutingModule, FormsModule, HttpClientModule ], providers: [], entryComponents: [AppComponent] }) export class AppModule { constructor(private injector: Injector, private router: Router, private location: Location ) { const appElement = createCustomElement(AppComponent, { injector: this.injector }); console.log('define ecb-frontend'); customElements.define('ecb-frontend', appElement); console.log('defined ecb-frontend'); console.log(this.location); this.router.navigateByUrl(this.location.path(true)); console.log(this.router); this.location.subscribe(data => { console.log(data); this.router.navigateByUrl(data.url); }); } // tslint:disable-next-line: typedef ngDoBootstrap() {} }

<<---------------------------------------------------->>

lazy-element component

import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { url } from 'inspector';

@component({ selector: 'app-lazy-element2', template: <ng-container ngFor="let c of dynamicConfigs"> <ax-lazy-element axLazyElementDynamic= "c.tag, url: c.url; module: true" raised> }) export class LazyElement2Component implements OnInit {

elementUrl = ''; elementTag = ''; onDestroy: any; dynamicConfigs = [];

constructor(readonly activatedRoute: ActivatedRoute) { this.dynamicConfigs = [ {url: 'http://localhost:4201/component/ust-frontend/ust-frontend.js', tag: 'ust-frontend'}, {url: 'http://localhost:4201/component/ecb-frontend/ecb-frontend.js', tag: 'ecb-frontend'} ]; }

ngOnInit(): void {} }

<< --------------------------- >> app.module

import { BrowserModule } from '@angular/platform-browser'; import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { LazyElementsModule } from '@angular-extensions/elements'; import { CommonModule } from '@angular/common'; import { HttpClientModule } from '@angular/common/http';

import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { HeaderComponent } from './components/header/header.component'; import { HomeComponent } from './components/home/home.component'; import { DynamicLayoutComponent } from './components/dynamic-layout/dynamic-layout.component'; import { LazyElementComponent } from './components/lazy-element/lazy-element.component'; import { MainLayoutComponent } from './components/dynamic-layout/main-layout.component'; import { LoginComponent } from './components/login/login.component'; import { ReactiveFormsModule } from '@angular/forms'; import { LazyElement2Component } from './components/lazy-element2/lazy-element2.component';

@NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA], declarations: [ AppComponent, HeaderComponent, HomeComponent, DynamicLayoutComponent, LazyElementComponent, LazyElement2Component, MainLayoutComponent, LoginComponent ], imports: [ BrowserModule, AppRoutingModule, HttpClientModule, LazyElementsModule, CommonModule, ReactiveFormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule {}

janstadt commented 4 years ago

Gonna help this guy out here a bit.

web component

import { AppRoutingModule } from './app-routing.module';
import { HttpClientModule } from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, Injector } from '@angular/core';
import { Router } from '@angular/router';
import { Location } from '@angular/common';
import { createCustomElement } from '@angular/elements';

import { AppComponent } from './app.component';
import { EcbrateComponent } from './component/ecbrate/ecbrate.component';

import { FormsModule } from '@angular/forms';

@NgModule({
    declarations: [AppComponent, EcbrateComponent],
    imports: [
        BrowserModule,
        AppRoutingModule,
        FormsModule,
        HttpClientModule
    ],
    providers: [],
    entryComponents: [AppComponent]
})
export class AppModule {
    constructor(private injector: Injector, private router: Router, private location: Location) {
        const appElement = createCustomElement(AppComponent, {
            injector: this.injector
        });
        console.log('define ecb-frontend');
        customElements.define('ecb-frontend', appElement);
        console.log('defined ecb-frontend');
        console.log(this.location);
        this.router.navigateByUrl(this.location.path(true));
        console.log(this.router);
        this.location.subscribe(data => {
            console.log(data);
            this.router.navigateByUrl(data.url);
        });
    }
    // tslint:disable-next-line: typedef
    ngDoBootstrap() { }
}

lazy-element component

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { url } from 'inspector';

@component({
    selector: 'app-lazy-element2',
    template: <ng-container * ngFor="let c of dynamicConfigs">
        <ax-lazy - element * axLazyElementDynamic= "c.tag, url: c.url; module: true" raised >

})
export class LazyElement2Component implements OnInit {

    elementUrl = '';
    elementTag = '';
    onDestroy: any;
    dynamicConfigs = [];

    constructor(readonly activatedRoute: ActivatedRoute) {
        this.dynamicConfigs = [
            { url: 'http://localhost:4201/component/ust-frontend/ust-frontend.js', tag: 'ust-frontend' },
            { url: 'http://localhost:4201/component/ecb-frontend/ecb-frontend.js', tag: 'ecb-frontend' }
        ];
    }

    ngOnInit(): void { }
}

app.module

import { BrowserModule } from '@angular/platform-browser';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { LazyElementsModule } from '@angular-extensions/elements';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HeaderComponent } from './components/header/header.component';
import { HomeComponent } from './components/home/home.component';
import { DynamicLayoutComponent } from './components/dynamic-layout/dynamic-layout.component';
import { LazyElementComponent } from './components/lazy-element/lazy-element.component';
import { MainLayoutComponent } from './components/dynamic-layout/main-layout.component';
import { LoginComponent } from './components/login/login.component';
import { ReactiveFormsModule } from '@angular/forms';
import { LazyElement2Component } from './components/lazy-element2/lazy-element2.component';

@NgModule({
    schemas: [CUSTOM_ELEMENTS_SCHEMA],
    declarations: [
        AppComponent,
        HeaderComponent,
        HomeComponent,
        DynamicLayoutComponent,
        LazyElementComponent,
        LazyElement2Component,
        MainLayoutComponent,
        LoginComponent
    ],
    imports: [
        BrowserModule,
        AppRoutingModule,
        HttpClientModule,
        LazyElementsModule,
        CommonModule,
        ReactiveFormsModule
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }