angularangular-elements

Angular Elements - Uncaught TypeError: Failed to construct 'HTMLElement'


I have been trying to get an Angular elements component working, as I was considering using them in an upcoming project.

I have followed a number of tutorials (all very similar), and just cannot get them working. One of the tutorials is this one.

I have the following package.json for the Elements project

        {
      "name": "angular-webcomponents-demo",
      "version": "0.0.0",
      "scripts": {
        "ng": "ng",
        "start": "ng serve",
        "build": "ng build",
        "test": "ng test",
        "lint": "ng lint",
        "e2e": "ng e2e",
        "build:elements": "ng build --prod --output-hashing none && node build-script.js"
      },
      "private": true,
      "dependencies": {
        "@angular/animations": "~7.2.0",
        "@angular/common": "~7.2.0",
        "@angular/compiler": "~7.2.0",
        "@angular/core": "~7.2.0",
        "@angular/elements": "^7.2.15",
        "@angular/forms": "~7.2.0",
        "@angular/platform-browser": "~7.2.0",
        "@angular/platform-browser-dynamic": "~7.2.0",
        "@angular/router": "~7.2.0",
        "core-js": "^2.5.4",
        "rxjs": "~6.3.3",
        "tslib": "^1.9.0",
        "zone.js": "~0.8.26",
        "document-register-element": "^1.7.2"
      },
      "devDependencies": {
        "@angular-devkit/build-angular": "~0.13.0",
        "@angular/cli": "~7.3.8",
        "@angular/compiler-cli": "~7.2.0",
        "@angular/language-service": "~7.2.0",
        "@types/jasmine": "~2.8.8",
        "@types/jasminewd2": "~2.0.3",
        "@types/node": "~8.9.4",
        "codelyzer": "~4.5.0",
        "concat": "^1.0.3",
        "fs-extra": "^8.1.0",
        "jasmine-core": "~2.99.1",
        "jasmine-spec-reporter": "~4.2.1",
        "karma": "~4.0.0",
        "karma-chrome-launcher": "~2.2.0",
        "karma-coverage-istanbul-reporter": "~2.0.1",
        "karma-jasmine": "~1.1.2",
        "karma-jasmine-html-reporter": "^0.2.2",
        "protractor": "~5.4.0",
        "ts-node": "~7.0.0",
        "tslint": "~5.11.0",
        "typescript": "~3.2.2"
      }
    }

I built using npm un build:elements as instructed, and then attempted to host in the simplest html I could

ie

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="analytics-counter.js"></script>
</head>

<body>
  <analytics-counter></analytics-counter>
</body>
</html>

Initially I was getting errors similar to this post (except mine mentioned custom-root rather than `app-root'.

I have removed the component from the bootstrap, so I now have the following in my app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { AppComponent } from './app.component';
import { AnalyticsCounterComponent } from './analytics-counter/analytics-counter.component';

@NgModule({
  declarations: [
    AppComponent,
    AnalyticsCounterComponent
  ],
  imports: [
    BrowserModule
  ],
  entryComponents: [
    AnalyticsCounterComponent
  ],
  providers: []  
})
export class AppModule {
  constructor(private injector: Injector) {     
  }
  ngDoBootstrap() {    
    const el = createCustomElement(AnalyticsCounterComponent, { injector: this.injector });
    customElements.define('analytics-counter', el);
  }
}

I removed the <custom-root> from the index.html as well as I saw suggeted elswhere

The error I am now getting is

Uncaught TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function.
        at t [as constructor] (analytics-counter.js:4)
        at new t (analytics-counter.js:4)
        at CustomElementRegistry.e.<computed> [as define] (analytics-counter.js:2)
        at new e (analytics-counter.js:4)
        at analytics-counter.js:4
        at Mo (analytics-counter.js:4)
        at analytics-counter.js:4
        at new e (analytics-counter.js:4)
        at Object.ti [as createNgModuleRef] (analytics-counter.js:4)
        at t.create (analytics-counter.js:4)

The tutorials and explanations all look pretty straight forward, yet I cannot get the most basic example working.

What could be wrong here?


Solution

  • I was able to reproduce your error. The problem comes from build-script.js. You will have to modify it and make sure it's compiling only es2015.js files instead of es5.js. ES5 has some trouble working with native Custom Elements, therefore you will have to use ES2015.

    So it will look something like this:

    const files = [
      './dist/CustomElements/runtime-es2015.js',
      './dist/CustomElements/polyfills-es2015.js',
      './dist/CustomElements/main-es2015.js'
    ];
    

    Also feel free to check my working demo repository of Angular Elements - Angular Custom Elements. The output is already in elements/ folder so you can just run the index.html there to test it. I was able to reproduce the error by replacing es2015 to es5 in a build script on this exact project.