npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@hapiness/custom-elements-loader

v7.2.0

Published

Factory to load Angular Custom Elements inside JavaScript's applications like React.js, Vue.js or just standalone

Downloads

3

Readme

CUSTOM-ELEMENTS-LOADER

This module exposes a factory to use ElementsLoaderService inside JavaScript's applications like React.js, Vue.js or just standalone.

THIS MODULE IS ONLY USED IN JiT (Just-in-Time) MODE AND THE BUILD WON'T BE THE MOST OPTIMIZED - TO HAVE THE BEST WAY AND THE BEST OPTIMIZED CUSTOM ELEMENTS INTEGRATION WITH AoT (Ahead-of-Time) MODE, CHECK HERE

DON'T USE THIS MODULE FOR ANGULAR APPLICATION

Installation

$ yarn add @hapiness/custom-elements-loader

or

$ npm install --save @hapiness/custom-elements-loader

All required dependencies will be automatically installed : @angular/animations, @angular/common, @angular/core, @angular/compiler, @angular/elements, @angular/platform-browser, @angular/platform-browser-dynamic, @hapiness/ng-elements-loader, @webcomponents/webcomponentsjs, core-js, document-register-element, rxjs and zone.js.

If your custom element module must have more dependencies, you must install them by yourself

Usage

Before to use ElementsLoader exposed by @hapiness/custom-elements-loader, you must create your own custom-elements modules.

To create a new library with Angular-CLI, follow this guide.

1) made-with-love custom element

- Component

This component will be the final custom-element interpreted in your browser.

projects/made-with-love/src/lib/made-with-love.component.ts:

import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'made-with-love',
  templateUrl: './made-with-love.component.html',
  encapsulation: ViewEncapsulation.ShadowDom
})
export class MadeWithLoveComponent implements OnInit {
  private _name: string;
  private _url: string;
  private _color: string;
  private _size: number;

  constructor() {
    this.size = 1;
    this.color = 'red';
  }

  ngOnInit() {
    if (!this._name || this._name.length === 0) {
      console.error(`Name attribute must be provided!`);
    }
  }
  
  get name(): string {
    return this._name;
  }
  
  @Input()
  set name(n: string) {
    this._name = n;
  }
  
  get url(): string {
    return this._url;
  }

  @Input()
  set url(u: string) {
    this._url = u;
  }
  
  get color(): string {
    return this._color;
  }

  @Input()
  set color(c: string) {
    this._color = c;
  }
  
  get size(): number {
    return this._size;
  }

  @Input()
  set size(s: number) {
    this._size = s;
  }
}

Note: Your component must have encapsulation equals to ViewEncapsulation.ShadowDom if you want to have shadowdomv1 support else you can delete this line to have original support.

projects/made-with-love/src/lib/made-with-love.component.html:

<ng-template #noUrl>
  {{ name }}
</ng-template>
<span [style.font-size.em]="size">
  Made with <span [style.color]="color">♥</span> by
  <ng-container *ngIf="url && url.length > 0; else noUrl">
    <a [attr.href]="url" target="_blank">{{ name }}</a>
  </ng-container>
</span>

- Module

projects/made-with-love/src/lib/made-with-love.module.ts:

import { NgModule, Type } from '@angular/core';
import { CommonModule } from '@angular/common';
import { WithCustomElementComponent } from '@hapiness/ng-elements-loader';
import { MadeWithLoveComponent } from './made-with-love.component';

@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [
    MadeWithLoveComponent
  ],
  entryComponents: [
    MadeWithLoveComponent
  ],
  exports: [
    MadeWithLoveComponent
  ]
})
export class MadeWithLoveModule implements WithCustomElementComponent {
  customElementComponent: Type<MadeWithLoveComponent> = MadeWithLoveComponent;
}

Note: Your module must implement WithCustomElementComponent interface exposed by @hapiness/ng-elements-loader and, component must be declared inside entryComponents and declaration meta-data of NgModule.

- Dependencies

The minimum package.json file for your module is described below:

projects/made-with-love/package.json:

{
  "name": "made-with-love",
  "version": "1.0.0",
  "peerDependencies": {
    "@hapiness/custom-elements-loader": "^7.2.0"
  }
}

If your module has to have others dependencies not installed automatically by @hapiness/custom-elements-loader like explained in installation, you must add them in dependencies section.

- Publish your module

Your custom-element module is now ready to be used so you have to publish it before use it in your application.

Back to top

2) made-with-love custom element in your JavaScript application

Create a JavaScript application with your module and @hapiness/custom-elements-loader in dependencies.

Install all dependencies your module must have if not already installed.

- Application contains made-with-love custom element

We create a HTMLfile with our custom element inside.

index.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
    <title>Web Component</title>
</head>
<body>
<div>
    <made-with-love name="Hapiness Framework" url="https://github.com/hapinessjs/" size="2"></made-with-love>
</div>

<script src="./main.js" type="text/javascript"></script>
</body>
</html>

main.js file contains all JavaScript elements to use ElementsLoader and it's built with webpack.

main.ts

// POLYFILLS
import 'zone.js/dist/zone';
import 'core-js/es7/reflect';

/** In browsers that don't support Custom Elements natively **/
// import 'document-register-element';

/** You must add this if your application will be compiled in es5 because the specification requires developers use ES2015 classes to define Custom Elements **/ 
// import '@webcomponents/webcomponentsjs/custom-elements-es5-adapter';

import { ElementsLoader } from '@hapiness/custom-elements-loader';
import { MadeWithLoveModule } from 'made-with-love';

ElementsLoader.loadContainingCustomElements(
    {
        selector: 'made-with-love',
        module: MadeWithLoveModule
    }
).subscribe(undefined, e => console.error(e));

- Explanation

The creation of the custom element happens directly inside HTML file with all attributes we want to display:

<made-with-love name="Hapiness Framework" url="https://github.com/hapinessjs/" size="2"></made-with-love>

Loading of the component happens inside main.ts file.

  • Add required polyfills
import 'zone.js/dist/zone';
import 'core-js/es7/reflect';
  • Additional polyfills can be added if needed:
/** In browsers that don't support Custom Elements natively **/
// import 'document-register-element';

/** You must add this if your application will be compiled in es5 because the specification requires developers use ES2015 classes to define Custom Elements **/ 
// import '@webcomponents/webcomponentsjs/custom-elements-es5-adapter';

/** IE9, IE10 and IE11 requires all of the following polyfills. **/
// import 'core-js/es6/symbol';
// import 'core-js/es6/object';
// import 'core-js/es6/function';
// import 'core-js/es6/parse-int';
// import 'core-js/es6/parse-float';
// import 'core-js/es6/number';
// import 'core-js/es6/math';
// import 'core-js/es6/string';
// import 'core-js/es6/date';
// import 'core-js/es6/array';
// import 'core-js/es6/regexp';
// import 'core-js/es6/map';
// import 'core-js/es6/weak-map';
// import 'core-js/es6/set';

/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js';  // Run `npm install --save classlist.js`.

/** IE10 and IE11 requires the following for the Reflect API. */
// import 'core-js/es6/reflect';

/**
 * Web Animations `@angular/platform-browser/animations`
 * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
 * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
 **/
// import 'web-animations-js';  // Run `npm install --save web-animations-js`.
  • We call loadContainingCustomElements method of ElementsLoader from @hapiness/custom-elements-loader. This method takes in parameter CustomElementModuleSelector or CustomElementModuleSelector[] from @hapiness/ng-elements-loader.
export interface CustomElementModuleSelector {
    selector: string;
    module: Type<any>;
}

Selector is the custom tag of your custom element and module is the Angular module contains the component.

- Show the result

Launch your application and you will see your custom element displayed inside your JavaScript application:

Made with ♥ by Hapiness Framework

Back to top

3) Custom element with custom event

In the previous component we have created only @Input properties but sometimes, you'll want to emit event from your custom element to the DOM with @Ouput properties.

- Custom element

Here an example of a component emits event to its parent:

projects/hello-world/src/lib/hello-world.component.ts:

import { Component, EventEmitter, OnInit, Output, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'hello-world',
  templateUrl: './hello-world.component.html',
  styleUrls: ['./hello-world.component.scss'],
  encapsulation: ViewEncapsulation.ShadowDom
})
export class HelloWorldComponent implements OnInit {
  private _sayHello$: EventEmitter<string>;

  constructor() {
    this._sayHello$ = new EventEmitter<string>();
  }

  ngOnInit() {
  }
  
  @Output('sayHello')
  get sayHello$(): EventEmitter<string> {
    return this._sayHello$;  
  }

  sayHello() {
    this._sayHello$.emit('Hello World');
  }
}

projects/hello-world/src/lib/hello-world.component.html:

<div>
  <button type="button" (click)="sayHello()">Say Hello with Event</button>
</div>

- Use it in your application

To use it and receive event, you must do this:

index.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
    <title>Web Component</title>
</head>
<body>
<div>
    <hello-world></hello-world>
</div>

<script src="./main.js" type="text/javascript"></script>
</body>
</html>

We set a listener to catch sayHello event and do what we want:

main.ts

// POLYFILLS
import 'zone.js/dist/zone';
import 'core-js/es7/reflect';

/** In browsers that don't support Custom Elements natively **/
// import 'document-register-element';

/** You must add this if your application will be compiled in es5 because the specification requires developers use ES2015 classes to define Custom Elements **/ 
// import '@webcomponents/webcomponentsjs/custom-elements-es5-adapter';

import { ElementsLoader } from '@hapiness/custom-elements-loader';
import { HelloWorldModule } from 'hello-world';

ElementsLoader.loadContainingCustomElements(
    {
        selector: 'hello-world',
        module: HelloWorldModule
    }
).subscribe(undefined, e => console.error(e));

document.querySelector('hello-world').addEventListener('sayHello', (event: any) => alert(event.detail));

Back to top

Change History

  • v7.2.0 (2018-11-27)
    • Angular v7.1.0+
    • Add ElementsLoaderService.registerContainingCustomElements() method to be used for AoT compiler
    • ElementsLoaderService.loadContainingCustomElements() method must be used only for JiT compiler
    • Explain how to create an optimized webcomponent bundle with this tutorial
    • Documentation
  • v7.1.0 (2018-11-09)
    • Angular v7.0.3+
    • document-register-elements v1.13.1 latest version of the polyfill only require if your browser doesn't support customElement
    • @webcomponents/webcomponentsjs v2.1.3 to fix issue with es5 compilation outside Angular application like explain here
    • Allow custom elements registration in browser even if tag isn't yet present in the DOM like this, it can be created or loaded asynchronously after registration
    • Documentation
  • v7.0.0 (2018-11-02)
    • Angular v7.0.2+
    • Documentation
  • v6.4.2 (2018-10-18)
    • Angular v6.1.10+
    • Explain how to add new polyfills for reflect api to solve bug reported in this issue
    • Provide ElementsLoaderService in ElementsLoaderModule to solve bug reported in this issue
    • Documentation
  • v6.4.1 (2018-09-26)
    • Fix version to Angular v6.1.7 to avoid the bug reported in this issue
    • Documentation
  • v6.4.0 (2018-07-26)
    • Angular v6.1.0+
    • Documentation

Back to top

Maintainers

Back to top

License

Copyright (c) 2018 Hapiness Licensed under the MIT license.

Back to top