<a href="https://travis-ci.org/hapinessjs/ng-elements-loader.svg?branch=master">
<img src="https://travis-ci.org/hapinessjs/ng-elements-loader.svg?branch=master" alt="build" />
</a>
<a href="https://david-dm.org/hapinessjs/ng-elements-loader">
<img src="https://david-dm.org/hapinessjs/ng-elements-loader.svg" alt="dependencies" />
</a>
<a href="https://david-dm.org/hapinessjs/ng-elements-loader?type=dev">
<img src="https://david-dm.org/hapinessjs/ng-elements-loader/dev-status.svg" alt="devDependencies" />
</a>
<a href="https://www.typescriptlang.org/docs/tutorial.html">
<img src="https://cdn-images-1.medium.com/max/800/1*8lKzkDJVWuVbqumysxMRYw.png"
align="right" alt="Typescript logo" width="50" height="50" style="border:none;" />
</a>
<a href="http://reactivex.io/rxjs">
<img src="http://reactivex.io/assets/Rx_Logo_S.png"
align="right" alt="ReactiveX logo" width="50" height="50" style="border:none;" />
</a>
<a href="https://www.angular.io">
<img src="https://angular.io/assets/images/logos/angular/angular.svg"
align="right" alt="Angular logo" width="75" style="border:none; margin-top:-5px;" />
</a>
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 useElementsLoader
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 aJavaScript
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 HTML
file 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 ofElementsLoader
from@hapiness/custom-elements-loader
. This method takes in parameterCustomElementModuleSelector
orCustomElementModuleSelector[]
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](https://github.com/hapinessjs/ng-elements-loader/blob/master/projects/ng-elements-loader/AOT.md)
* 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](https://github.com/angular/angular/issues/24390#issuecomment-437361929)
* 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](https://github.com/angular/angular/issues/26128)
* Provide `ElementsLoaderService` in `ElementsLoaderModule` to solve bug reported in this [issue](https://github.com/angular/angular/issues/25813)
* Documentation
- v6.4.1 (2018-09-26)
* Fix version to `Angular v6.1.7` to avoid the bug reported in this [issue](https://github.com/angular/angular/issues/26128)
* Documentation
- v6.4.0 (2018-07-26)
* `Angular v6.1.0+`
* Documentation
Back to topMaintainers
Back to top
License
Copyright (c) 2018 Hapiness Licensed under the MIT license.Back to top