Custom Element in Angular 17
Asked Answered
P

2

5

since I updated Angular to version 17 I can't create web components.. I used to do it in app.module, where are they created now? I tried in app.component as the guide says but it doesn't seem to work.. Can someone help me please??

I tried in app.component as the guide says but it doesn't seem to work..

@Component({
  standalone: true,
  selector: 'app-root',
  template: `
    <input #input value="Message" />
    <button type="button" (click)="popup.showAsElement(input.value)">Show as element</button>
  `,
  providers: [PopupService],
  imports: [PopupComponent],
})
export class AppComponent {
  constructor(
    injector: Injector,
    public popup: PopupService,
  ) {
    // Convert `PopupComponent` to a custom element.
    const PopupElement = createCustomElement(PopupComponent, {injector});
    // Register the custom element with the browser.
    customElements.define('popup-element', PopupElement);
  }
}
Prase answered 6/2 at 9:26 Comment(0)
S
7

See the way to create a custom Element. For the purposes of this example

In your main.ts replace

bootstrapApplication(AppComponent, appConfig)
.catch((err) => console.error(err));

with

createApplication()
.then((app) => {
    const app = createApplication({providers:[...]});
    const PopupElement = createCustomElement(AppComponent, {
        injector: (app).injector
    });
    customElements.define('popup-element', PopupElement);
}
.catch((err) => console.error(err));

a stackblitz (see that, you need refresh the "visor" if you make any change)

however, this can be simplified further without removing the bootstrapApplication method:

bootstrapApplication(AppComponent, appConfig)
.then((app) => {
    const PopupElement = createCustomElement(AppComponent, {
        injector: (app).injector
    });
    customElements.define('popup-element', PopupElement);
})
.catch((err) => console.error(err));

Update for Angular 18

If we have an AppComponent standalone. In main.ts

createApplication()
    .then((app) => {
        const MyComponent= createCustomElement(AppComponent, { injector: app.injector });
        customElements.define('my-tag', MyComponent);
    })
    .catch((err) => console.error(err));
Saccharoid answered 6/2 at 10:4 Comment(7)
Thanks so much for the reply, it was very helpful for me. I would like to ask you something else: after making the changes you suggested, the customElement is created. For clarity let's call the project where I create the element project 1 and the other project 2. If I wanted to export the element to project 2, how can I do it? I tried copying the js of the dist in project 2 and putting them as src. Then in the body I recalled the element with the <popup-element> tag but it doesn't understand that it is a custom element. ps: I have already added the CUSTOM_ELEMENTS_SCHEMAPrase
@nixxx, I think remember that you should add the <script src=...></script> at the end of your page -inside the body-, but now I'm not pretty sure.Saccharoid
@Saccharoid where did you get that puiece of code? "See the way to create a custom Element in your main.ts" thanksNorthing
@StefanoFavero, see your angular.json file. In projects-->ClientApp-->Architect-->build-->options-->main you have the file.ts that have been executed. Generally is called main.ts. and the main.ts can be in the way bootstrapApplication(AppComponent,... if you're working with standalone components or platformBrowserDynamic().bootstrapModule(AppModule)... if you're using modules. This is the code you need replace to create elementsSaccharoid
@Saccharoid it gives me the error Uncaught SyntaxError: Unexpected token 'export' (at main.js:25942:1) in prod build, however works well with ng serveAssentor
@VictorBredihin I have the same case with the error Unexpected token 'export'. Did you manage to solve this?Veraveracious
@Lapidus, if you're using Angular 18 see the updated answerSaccharoid
D
1

Adding it for people who need to do this setup from scratch and are loooking for some good reference. Based on the post, setup web component bootstrapping The ng generate command created some basic files in the projects/my-library-web-components/src/app/* directory. However, we only need the app.config.ts file. Move this file up a directory and rename it to main.config.ts. It should be next to your main.ts file. You can delete the rest of the files in the app/* directory.

Your src directory should look like this when you are done: enter image description here

Replace ALL content inside main.config.ts with:

import { ApplicationConfig } from '@angular/core';

export const appConfig: ApplicationConfig = {
    providers: [],
};

Replace ALL content inside main.ts with:

import {createApplication} from '@angular/platform-browser';
import {appConfig} from './main.config';
import {createCustomElement} from '@angular/elements';
import { MyLibraryComponent } from 'my-library';
import { ApplicationRef } from '@angular/core';

(async () => {
  const app: ApplicationRef = await createApplication(appConfig);

  // Define Web Components
  const myLibraryComponent = createCustomElement(MyLibraryComponent, {injector: app.injector});
  customElements.define('my-library-component', myLibraryComponent);
})();

Modify your index.html to use your web component like:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>EtlpWc</title>
        <base href="/" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
    </head>
    <body>
        <my-library-component></my-library-component>
    </body>
</html>

This is the index.html located in the same directory as your main.ts and main.config.ts

Ductile answered 4/4 at 22:2 Comment(1)
Hi Asif, can you advise how to implement ngcspnonce or csp_nonce in custom web components?Scorecard

© 2022 - 2024 — McMap. All rights reserved.