0

I have to build a web component to inject inside a legacy code project; I tried to follow the official documentation to do so using angular (https://v19.angular.dev/guide/elements) but I feel like is a bit incomplete: for example there is nothing about how do produce a js file to then refer in the html of the target project to be able to use the custom html tag.

I searched extensively for guides or more about the topic but nothing pops out on the Internet, at least not for the newer versions of Angular (newest stuff I found was 2 year old).

I followed the official guide 'till the end and tried to ng build and use the main.js and polyfill.js inside of an html file to reference the custom html tag created in Angular but I get the following error that is not so explanatory:

main-ZVR3556L.js:7  y: NG0908
    at new e (file:///C:/Users/sviaga/Desktop/testProjects/dist/main-ZVR3556L.js:7:19677)
    at Object.ngZoneFactory [as useFactory] (file:///C:/Users/sviaga/Desktop/testProjects/dist/main-ZVR3556L.js:7:59858)
    at Object.r [as factory] (file:///C:/Users/sviaga/Desktop/testProjects/dist/main-ZVR3556L.js:7:5002)
    at Ke.hydrate (file:///C:/Users/sviaga/Desktop/testProjects/dist/main-ZVR3556L.js:7:4140)
    at Ke.get (file:///C:/Users/sviaga/Desktop/testProjects/dist/main-ZVR3556L.js:7:3304)
    at vf (file:///C:/Users/sviaga/Desktop/testProjects/dist/main-ZVR3556L.js:7:63982)
    at Ca (file:///C:/Users/sviaga/Desktop/testProjects/dist/main-ZVR3556L.js:7:65759)
    at lo (file:///C:/Users/sviaga/Desktop/testProjects/dist/main-ZVR3556L.js:7:77258)
    at file:///C:/Users/sviaga/Desktop/testProjects/dist/main-ZVR3556L.js:7:82993

Anyone out there building web components in angular that's facing my same troubles?

This is my app.component.ts:

import { Component, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { NotificationsCenterComponent } from './notifications-center/notifications-center.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss',
})
export class AppComponent {
  constructor(injector: Injector) {
    const NotificationsCenterElement = createCustomElement(NotificationsCenterComponent, { injector });

    customElements.define('notifications-center', NotificationsCenterElement);
  }
}

This is my notifications-center.ts and html;

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

@Component({
  selector: 'app-notifications-center',
  imports: [],
  templateUrl: './notifications-center.component.html',
  styleUrl: './notifications-center.component.scss'
})
export class NotificationsCenterComponent {

}
<p>notifications-center works!</p>

As you can tell the component is default just because I wanted to test stuff before actually starting the developing.

This is the html file where I'm trying to use the web-component:

<html>
    <head>
        <script src="dist/main-ZVR3556L.js"></script>
        <script src="dist/polyfills-B6TNHZQ6.js"></script>
    </head>
    <body>
        <notifications-center></notifications-center>
    </body>
</html>
8
  • why do you try to createCustomElement and register it in the constructor of AppComponent = during the initiation of AppComponent? just put that "registering code" in main.ts or some other script on top level Commented Jul 18 at 15:50
  • I do so because that’s in Angular’s official documentation Commented Jul 18 at 23:01
  • Please do not upload images of code/data/errors. Commented Jul 19 at 2:04
  • @hello-there I don't think so. Just create empty injector and pass it to the configuration if that param is your problem. Commented Jul 19 at 13:13
  • 1
    @hello-there, I just create at home a simple example, I hope help you (see that the script are "loaded" as "module") Commented Jul 21 at 18:16

1 Answer 1

1

Steps: 1.- Created in Angular 19.0.0 a new aplication

ng new my-app

2.-install @angular/elements, see that actually is the version 20, so you ad @19.0.0

cd my-app
npm i @angular/[email protected]

3.-replace the file in main.ts with the code (1)

import { createApplication } from '@angular/platform-browser';
import { NotificationsCenterComponent } from './app/notifications-center.component';
import { createCustomElement } from '@angular/elements'

createApplication()
    .then((app) => {
        const MyComponent = createCustomElement(NotificationsCenterComponent, 
           { injector: app.injector });
        customElements.define('notifications-center', MyComponent);
    })
    .catch((err) => console.error(err));

4.-Create a new standalone component NotificationCenterComponent Some simple like

@Component({
  selector: 'app-notifications-center',
  imports: [CommonModule], //<--if we need use interpolation, @for, @if ...
  standalone:true,
  templateUrl: './notifications-center.component.html',
  styleUrl: './notifications-center.component.css'
})
export class NotificationsCenterComponent {
  title = 'element';
}

5.-Execute ng build

ng build

Be Carefull!!, each time you use ng-build the file dist/browser/index.html is override it

6.-go to dist/browser, you can see an index.html that should work when you replace the app-root tag, some like

<!doctype html>
<html lang="en" data-beasties-container>

<head>
  <meta charset="utf-8">
  <title>Element</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link rel="stylesheet" href="styles-5INURTSO.css">
</head>

<body>
  <!--see that you replace the app-root tag-->
  <notifications-center></notifications-center>
  <script src="polyfills-B6TNHZQ6.js" type="module"></script>
  <script src="main-O3QGPD42.js" type="module"></script>
</body>

</html>

Now you need execute the .html, but you need execute in a "server". see that the script have type=module. You can use server express, the extension preview html in visualStudio, visual comunity or another way, so you can execute in your navigator.

A "easy" solution is install globally the http-server

npm install --global http-server

goto the directory and execute

http-server

open a navigator and use

http://localhost:8080/index.html

(1) really it's not magic, when you use ng build it's executed the file indicate in angular.json see the section:

"architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:application",
          "options": {
            "outputPath": "dist/element",
            "index": "src/index.html",
            "browser": "src/main.ts", //<---execute this
            "polyfills": [
              "zone.js"
            ],

(really execute the script defined in package.json, the section script that it's like

"scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test"
  },
Sign up to request clarification or add additional context in comments.

1 Comment

It worked: the important part I was missing was get the html file served by a server (I used express and it worked perfectly), before I was just opening it by double clicking. Thanks for your help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.