{"id":17056361,"url":"https://github.com/biophoton/elements","last_synced_at":"2026-01-20T15:05:20.468Z","repository":{"id":38664431,"uuid":"207866897","full_name":"BioPhoton/elements","owner":"BioPhoton","description":null,"archived":false,"fork":false,"pushed_at":"2023-01-07T11:10:36.000Z","size":4545,"stargazers_count":1,"open_issues_count":27,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-05T23:17:06.082Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BioPhoton.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-09-11T17:18:25.000Z","updated_at":"2021-03-12T05:01:20.000Z","dependencies_parsed_at":"2023-02-07T00:16:38.497Z","dependency_job_id":null,"html_url":"https://github.com/BioPhoton/elements","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/BioPhoton/elements","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BioPhoton%2Felements","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BioPhoton%2Felements/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BioPhoton%2Felements/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BioPhoton%2Felements/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BioPhoton","download_url":"https://codeload.github.com/BioPhoton/elements/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BioPhoton%2Felements/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28606094,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T14:45:23.139Z","status":"ssl_error","status_checked_at":"2026-01-20T14:44:16.929Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-14T10:24:12.796Z","updated_at":"2026-01-20T15:05:20.451Z","avatar_url":"https://github.com/BioPhoton.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Prove Of Concept for Angular elements and third party libs\n\n@TODO /demo =\u003e /demo-angular\n\n\u003c!-- npm i -g markdown-toc \u0026\u0026 markdown-toc ./README.md -i --\u003e\n\n\u003c!-- toc --\u003e\n\n  * [Project Setup and Build](#project-setup-and-build)\n    + [Version Information](#version-information)\n    + [Setup angular project structure](#setup-angular-project-structure)\n    + [Setup Consumer Angular Project](#setup-consumer-angular-project)\n    + [Setup Consumer Vanilla Project](#setup-consumer-vanilla-project)\n    + [Setup Provider Project](#setup-provider-project)\n      - [Setup Variants Bundling](#setup-variants-bundling)\n    + [Setup for Lazy Loading of Elements](#setup-for-lazy-loading-of-elements)\n      - [Setup Consumer Application to Lazy Load Elements](#setup-consumer-application-to-lazy-load-elements)\n      - [Setup Provider Application to Lazy Load Elements](#setup-provider-application-to-lazy-load-elements)\n    + [Setup for Angular Material](#setup-for-angular-material)\n    + [Setup for Angular Dynamic Forms](#setup-for-angular-dynamic-forms)\n  * [ZoneHandling and Angular Elements](#zonehandling-and-angular-elements)\n    + [Zone-less](#zone-less)\n      - [Problems with Components when Running Zone Less](#problems-with-components-when-running-zone-less)\n        * [Template Bindings](#template-bindings)\n        * [Input Bindings](#input-bindings)\n        * [Output Bindings](#output-bindings)\n        * [Dom Events](#dom-events)\n        * [Animations](#animations)\n        * [Internal Logic](#internal-logic)\n      - [Problems with WebComponents when Running Zone Less](#problems-with-webcomponents-when-running-zone-less)\n    + [Zone-full](#zone-full)\n      - [Parent-Zone Hack](#parent-zone-hack)\n      - [Context-Aware-Zones-Zones](#context-aware-zones-zones)\n      - [ViewEncapsulation and Styling](#viewencapsulation-and-styling)\n    + [View Encapsulation with Option `None`](#view-encapsulation-with-option-none)\n    + [View Encapsulation with Option `ShadowDom`](#view-encapsulation-with-option-shadowdom)\n    + [View Encapsulation with Option `Emulated`](#view-encapsulation-with-option-emulated)\n  * [Loading Strategies](#loading-strategies)\n    + [Elements Pre-compiled Eager Loaded](#elements-pre-compiled-eager-loaded)\n    + [Elements Pre-compiled Lazy Loaded](#elements-pre-compiled-lazy-loaded)\n    + [Setup Elements Un-compiled Lazy Loaded](#setup-elements-un-compiled-lazy-loaded)\n      - [Setup Provider Application for Un-Compiled Loading](#setup-provider-application-for-un-compiled-loading)\n  * [Productivity Helpers](#productivity-helpers)\n    + [Push Pipe](#push-pipe)\n    + [Let Structural Directive](#let-structural-directive)\n    + [CdOn Directive](#cdon-directive)\n  * [Browser Support and Backwards Compatibility](#browser-support-and-backwards-compatibility)\n  * [Performance](#performance)\n    + [Bundling](#bundling)\n    + [Unoptimized build like `ng serve`:](#unoptimized-build-like-ng-serve)\n- [Angular Architect API](#angular-architect-api)\n  * [Chunk Sets](#chunk-sets)\n\n\u003c!-- tocstop --\u003e\n\nIn this documnet the goal is to wrap `@angular/material` components \ncreated over `@ng-dynamic-forms/core` and use it in another angular application.\n\nFollowing things should be included:\n- [x] **Setup and Build** (A detailed documentation on how to setup things)\n- [x] **Working ChangeDetection** (ChangeDetection should work for all features. If possible zone-less)\n- [x] **Developer Workflow** (A convenient developer workflow for serving and building)\n- [x] **Styling Strategies** (Builds for all different variants of style encapsulation) \n- [x] **Loading strategies** (Loading of web components)\n- [ ] **Productivity Helpers** (A general set of helpers for more convenience)    \n\n## Project Setup and Build\n\n### Version Information\n\nAngular CLI: 8.3.3  \nNode: 10.12.0  \nOS: win32 x64  \nAngular: 8.2.5  \n... animations, common, compiler, compiler-cli, core, elements  \n... forms, language-service, platform-browser  \n... platform-browser-dynamic, router  \n  \n\nPackage                           | Version  \n----------------------------------|-------------------------  \n@angular-devkit/architect         | 0.803.3  \n@angular-devkit/build-angular     | 0.803.3  \n@angular-devkit/build-ng-packagr  | 0.803.3  \n@angular-devkit/build-optimizer   | 0.803.3  \n@angular-devkit/build-webpack     | 0.803.3  \n@angular-devkit/core              | 8.3.3  \n@angular-devkit/schematics        | 8.3.3  \n@angular/cdk                      | 8.2.0  \n@angular/cli                      | 8.3.3  \n@ngtools/webpack                  | 8.3.3  \n@schematics/angular               | 8.3.3  \n@schematics/update                | 0.803.3  \nng-packagr                        | 5.5.0  \nrxjs                              | 6.4.0  \ntypescript                        | 3.5.3  \nwebpack                           | 4.39.2   \n**Relevant modules starting here**| **version is pinned**\n@angular/elements                 | 8.2.5\n@angular-extensions/elements      | 8.7.0\n@angular/material                 | 8.2.0\n@ng-dynamic-forms/core            | 9.0.1\n@ng-dynamic-forms/ui-material     | 9.0.1\nangular2-text-mask                | 9.0.0\nnpm-run-all                       | 4.1.5\nconcat                            | 1.0.3\ngzip-all                          | 1.0.0\n\nBrowser:\n\nName   | Version\n-------|--------------\nChrome | 76.0.3809.132\n\n### Setup angular project structure\n1. `ng new elements --create-application false`\n\n### Setup Consumer Angular Project \n1. `ng generate application demo-angular`\n2. Add following lines to the scripts section in your `package.json` located in root level\n```json\n{\n  ...\n  \"scripts\": {\n    ...\n    \"serve:demo-angular\": \"ng serve --project demo-angular\",\n    \"build:demo-angular\": \"ng build --project demo-angular\"\n  },\n  ...\n}\n```\n3. Run \n```shell script\nnpm run serve:demo-angular\n```\n### Setup Consumer Vanilla Project \n\n1. Firs we have to generate a static app with as minimal configuration as possible.\n\n```shell script\nng g app demo-vanilla --style=scss --minimal=true --routing=false --skip-tests=true\n```\n2. Open `/projects/demo-vanilla/src/polyfills.ts` and comment out the code related to `zone.js`.\n```typescript\n\n/***************************************************************************************************\n * Zone JS is required by default for Angular itself.\n */\nimport 'zone.js/dist/zone';  // Included with Angular CLI.\n```\n3. Open `angular.json` and replace the following settings:\nUnder `projects.demo-vanilla.architect.build.configurations.production` place:\n```json\n{\n\"fileReplacements\": [\n{\n  \"replace\": \"projects/demo-vanilla/src/environments/environment.ts\",\n  \"with\": \"projects/demo-vanilla/src/environments/environment.prod.ts\"\n}\n],\n\"optimization\": true,\n\"sourceMap\": false,\n\"extractCss\": false,\n\"namedChunks\": false,\n\"extractLicenses\": true,\n\"vendorChunk\": false,\n\"buildOptimizer\": true,\n\"budgets\": [\n{\n  \"type\": \"initial\",\n  \"maximumWarning\": \"2mb\",\n  \"maximumError\": \"5mb\"\n},\n{\n  \"type\": \"anyComponentStyle\",\n  \"maximumWarning\": \"6kb\",\n  \"maximumError\": \"10kb\"\n}\n]\n}\n```\n4. Delete all files in `app` under `projects/demo-vanilla/src`\n5. Create an `index.ts` file  under `projects/demo-vanilla/src/app` and inset following content;\n```typescript\nconsole.log('Vanilla app started');\n```\n\n6. Replace the content of `main.ts` file  under `projects/demo-vanilla/src` with following content:\n```typescript\nimport {init} from './app';\n\n```\n9. Add following lines to the scripts section in your `package.json` located in root level\n```json\n{\n  ...\n  \"scripts\": {\n    ...\n    \"serve:demo-vanilla\": \"ng serve --project demo-vanilla\",\n    \"build:demo-vanilla\": \"ng build --project demo-vanilla\"\n  },\n  ...\n}\n```\n10. Run \n```shell script\nnpm run \"serve:demo-vanilla\": \"ng serve --project demo-vanilla\"\n``` \nYou should see the output in the console.\n### Setup Provider Project\n1. `ng generate application elements`\n2. Open `/projects/elements/src/polyfills.ts` and comment out the code related to `zone.js`.\n```typescript\n\n/***************************************************************************************************\n * Zone JS is required by default for Angular itself.\n */\nimport 'zone.js/dist/zone';  // Included with Angular CLI.\n```\n3. `ng add @angular/elements --project elements`\n4. `ng add ngx-build-plus --project elements`\n5. Create new file in root named `proxy.conf.json` and insert following content \n```json\n{\n  \"/elements\": {\n    \"target\": \"http://localhost:4300\",\n    \"secure\": false,\n    \"pathRewrite\": {\n      \"^/elements\": \"\"\n    },\n    \"logLevel\": \"debug\"\n  }\n}\n```\n6. Add `proxy.config.json` to `angular.json`. \nUnder `projects.demo.architect.serve.options` in `angular.json`:\n\n```json\n{\n  ...\n  \"proxyConfig\": \"proxy.conf.json\"\n}\n\n```\n7. Insert the following under `elements.architect.serve.options` in `angular.json`:\n```typescript \n \"port\": 4242\n```\n#### Setup Variants Bundling\n1. `npm i angular-element-variants --save`\n\n2. create a  folder `tooling` under root\n3. In the folder `tooling` create a file `angular-element-variants.ts` and insert following content:\n```typescript\nimport {getVariantsPlugin} from 'angular-element-variants/index.tooling';\n\nconst variantsPlugin = getVariantsPlugin();\nexport default variantsPlugin;\n```\n4. create a file `tsconfig.tooling.json` and insert following config:\n```json\n{\n\n  \"esModuleInterop\": true,\n  \"compilerOptions\": {\n    \"baseUrl\": \"../\",\n    \"outDir\": \"../dist/tooling\",\n    \"target\": \"es5\",\n    \"module\": \"commonjs\",\n    \"allowJs\": true,\n    \"lib\": [\n      \"dom\",\n      \"es2015\",\n      \"esnext\"\n    ],\n    \"sourceMap\": false,\n    \"strict\": false,\n    \"moduleResolution\": \"node\",\n    \"typeRoots\": [\n      \"node_module/@types\"\n    ]\n  },\n  \"files\": [\n    \"angular-element-variants.plugin.ts\"\n  ]\n}\n```\n\n5. Insert the following under `elements.architect.build.options` in `angular.json`:\n```json \n \"plugin\": \"~dist/tooling/tooling/angular-element-variants.plugin\"\n```\n6. Insert the following under `elements.architect.build.configurations` in `angular.json`:\n```json \n \"angularStyled\": {\n   \"outputPath\": \"dist/elements-angular-styled\",\n   \"fileReplacements\": [\n     {\n       \"replace\": \"projects/elements/src/environments/environment.ts\",\n       \"with\": \"projects/elements/src/environments/environment.prod.ts\"\n     },\n     {\n       \"replace\": \"projects/elements/src/variants/variant.ts\",\n       \"with\": \"projects/elements/src/variants/variant.angularStyled.ts\"\n     }\n   ],\n   \"optimization\": true,\n   \"sourceMap\": false,\n   \"namedChunks\": false,\n   \"aot\": true,\n   \"extractLicenses\": true,\n   \"vendorChunk\": false,\n   \"buildOptimizer\": true\n },\n ...\n```\n7. Insert the following under `elements.architect.serve.options` in `angular.json`:\n```json \n \"plugin\": \"~dist/tooling/tooling/angular-element-variants.plugin\"\n```\n8. Insert the following under `elements.architect.serve.configurations` in `angular.json`:\n```json \n\"angularStyled\": {\n    \"browserTarget\": \"elements:build:serveAngularStyled\",\n    \"fileReplacements\": [\n      {\n        \"replace\": \"projects/elements/src/variants/variant.ts\",\n        \"with\": \"projects/elements/src/variants/variant.angularStyled.ts\"\n      }\n    ]\n},\n```\n9. Create a folder `variants` under `projects/elements/src`\n10. In the folder `variants` create a file `variant.ts` and insert following content:\n```typescript\nimport {\n  ChangeDetection,\n  CompilationTypes,\n  EsVersions,\n  VariantConfig,\n  ViewEncapsulation,\n  ZoneHandling\n} from 'angular-element-variants';\n\nexport const variant: VariantConfig = {\n  name: 'defaultVariant',\n  // ApplicationType: 'angular' | 'vanilla' | 'unknown'\n  applicationType: 'unknown',\n// ViewEncapsulation: 0 = Emulated | 1 = Native | 2 = None | 3 = ShadowDom\n  encapsulation: ViewEncapsulation.ShadowDom,\n// ChangeDetection: 0 = OnPush | 1 = Default\n  changeDetection: ChangeDetection.OnPush,\n// ZoneHandling: 'None' | 'Injected' | 'Shipped' | 'Scoped'\n  zone: ZoneHandling.Shipped,\n// CompilationTypes: 'preCompiled' | 'unCompiled'\n  compilation: CompilationTypes.preCompiled,\n// runtimeShipped: true | false\n  runtime: true,\n// polyfillsShipped: true | false\n  polyfills: false,\n// scriptsShipped: true | false\n  scripts: false,\n  // EsVersions: 'es5' | 'es2015'\n  esVersion: EsVersions.es2015\n};\n```\n11. In the folder `variants` create another file `variant.angularStyled.ts` and insert following content:\n```typescript\nimport {ChangeDetection, CompilationTypes, EsVersions, ViewEncapsulation, ZoneHandling} from \"angular-element-variants\";\n\nexport const variant = {\n  name: 'angularStyled',\n  applicationType: 'angular',\n// ViewEncapsulation: 0 = Emulated | 1 = Native | 2 = None | 3 = ShadowDom\n  encapsulation: ViewEncapsulation.None,\n// ChangeDetection: 0 = OnPush | 1 = Default\n  changeDetection: ChangeDetection.Default,\n// ZoneHandling: 'None' | 'Injected' | 'Shipped' | 'Scoped'\n  zone: ZoneHandling.Shipped,\n// CompilationTypes: 'preCompiled' | 'unCompiled'\n  compilation: CompilationTypes.preCompiled,\n// runtimeShipped: true | false\n  runtime: false,\n// polyfillsShipped: true | false\n  polyfills: false,\n// scriptsShipped: true | false\n  scripts: false,\n  // EsVersions: 'es5' | 'es2015'\n  esVersion: EsVersions.es2015\n};\n```\n\n12. Add the following to you `main.ts` under `project/elements/src`: \n```typescript\n...\n// !!! CHANGE HERE !!!\nimport {getCompilerOptions} from 'angular-element-variants';\n...\n                                                            // !!! CHANGE HERE !!!\nplatformBrowserDynamic().bootstrapModule(AppModule, getCompilerOptions(variant))\n  .catch(err =\u003e console.error(err));\n```\n13. Add the following to you `app.module.ts` under `project/elements/src/app`: \n```typescript\nimport {Injector, Type} from '@angular/core';\nimport {createCustomElement} from '@angular/elements';\nimport {variant} from '../variants/variant';\nimport {ElementSet, createCustomElements} from 'angular-element-variants';\n...\n\nexport const angularElements: ElementSet\u003cType\u003cany\u003e\u003e = {};\n\n\n@NgModule({...})\nexport class ProviderAppModule {\n  customElementComponent = angularElements;\n\n  constructor(private injector: Injector) {\n  }\n\n  ngDoBootstrap(): void {\n    createCustomElements(variant, angularElements, (componentClass: Type\u003cany\u003e) =\u003e createCustomElement\u003cType\u003cany\u003e\u003e(componentClass, {injector: this.injector}));\n  }\n}\n```\n\n14. Add following lines to the scripts section in your `package.json` located in root level\n```json\n{\n  ...\n  \"scripts\": {\n    ...\n    \"compile:tooling\": \"tsc -p tooling/tsconfig.tooling.json\",\n    \"serve:elements:angular-styled\": \"npm run compile:tooling \u0026\u0026 ng serve --project elements -c=angularStyled\",\n    \"build:elements:angular-styled\": \"npm run compile:tooling \u0026\u0026 ng build --project elements -c=angularStyled\"\n  },\n  ...\n}\n```\n13. Add the following to you `app.module.ts` under `project/demo-angular/src/app`: \n```typescript\nimport {setupGlobalCompilerOptions} from 'angular-element-variants';\n\n@NgModule({...})\nexport class AppModule {\n  \n  constructor() {\n    setupGlobalCompilerOptions({});\n  }\n  \n}\n```\n\n\n### Setup for Lazy Loading of Elements\nAs we will need lazy loading so solve several problems in change detection and the injection tree we will setup lazy loading right now to have it solved front off.\nTo do so we need to setup both sides, the consumer and the provider.\n\n#### Setup Consumer Application to Lazy Load Elements\n\n1. `npm i -S @angular-extensions/elements`,\n3. Create file `elements-loading.component.ts` in `projects/demo/src/app/angular-elements`.\n4. Insert following content: \n```typescript\nimport {Component} from '@angular/core';\n\n@Component({\n  selector: 'elements-loading',\n  template: `\u003cdiv\u003eLoading...\u003c/div\u003e`\n})\nexport class ElementsLoadingComponent {\n\n}\n```\n5. Create file `elements-error.component.ts` in `projects/demo/src/app/angular-elements`.\n6. Insert following content: \n```typescript\nimport {Component} from '@angular/core';\n\n@Component({\n  selector: 'elements-error',\n  template: `\u003cdiv\u003eError!\u003c/div\u003e`\n})\nexport class ElementsErrorComponent {\n\n}\n```\n7. Create file `angular-elements.module.ts` in `projects/demo/src/app/angular-elements`.\n8. Insert following content: \n```typescript\nimport {NgModule} from '@angular/core';\nimport {LazyElementModuleRootOptions, LazyElementsModule} from '@angular-extensions/elements';\nimport {ElementsLoadingComponent} from './elements-loading.component';\nimport {ElementsErrorComponent} from './elements-error.component';\n\nconst BASIC_ELEMENTS_URL = 'elements/main.js';\nconst lazyElementsOptions: LazyElementModuleRootOptions = {\n  elementConfigs: [  ],\n  rootOptions: {\n    loadingComponent: ElementsLoadingComponent,\n    errorComponent: ElementsErrorComponent\n  }\n};\n@NgModule({\n  declarations: [ElementsLoadingComponent, ElementsErrorComponent],\n  imports: [\n    LazyElementsModule.forRoot(lazyElementsOptions)\n  ],\n  exports: [\n    LazyElementsModule\n  ]\n})\nexport class AngularElementsModule {\n}\n```\n9. Add following lines in `projects/demo/src/app/app.module.ts`:\n```typescript\n...\nimport {CUSTOM_ELEMENTS_SCHEMA, NgModule} from '@angular/core';\nimport {FormsModule} from '@angular/forms';\nimport {AngularElementsModule} from './angular-elements/angular-elements.module';\n\n@NgModule({\n  //  !!! CHANGES HERE !!! \n  schemas: [CUSTOM_ELEMENTS_SCHEMA],\n  ...\n  imports: [\n    // ... !!! CHANGES HERE !!!\n    FormsModule,\n    AngularElementsModule\n  ],\n  ...\n})\n...\n```\n\nYour app is now ready to work with angular elements.\nNow let's setup some content in `app.component.ts` to experiment.\n\n10. Delete files in all `app.component.*` files in `projects/demo-angular/src/app` folder.\n11. Create `app.component.ts` in `projects/demo-angular/src/app` folder and insert following content:\n```typescript\nimport { Component } from '@angular/core';\nimport {BehaviorSubject} from 'rxjs';\n\n@Component({\n  selector: 'app-root',\n  template: `\n      Primitive: \u003cinput [(ngModel)]=\"primitive\"\u003e\u003cbr/\u003e\n      \u003cbutton (click)=\"changeValueImmutable()\"\u003etrigger immutable change\u003c/button\u003e\n\n      \u003c!-- WEB COMPONENT GETS INSERTED LATER ON HERE --\u003e\n  `\n})\nexport class AppComponent {\n  primitive = 42;\n  o = {primitive: this.primitive};\n  o$ = new BehaviorSubject(this.o);\n\n  constructor() {\n  }\n\n  changeValueImmutable() {\n    this.primitive = this.primitive + 1;\n    this.o = {primitive: this.primitive};\n    this.o$.next(this.o);\n  }\n\n  log(v) {\n    console.log(v);\n  }\n}\n```\nDone with the consumer app. Now let's create a web component.\n\n#### Setup Provider Application to Lazy Load Elements\nTo have some more real life examples we set-up not only a simple web component but also include components with third party libraries.\n\n1. Delete all file in `projects/elements/src/app`.\n2. Create `web.component.ts` into `projects/elements/src/app` folder and insert following content:\n```typescript\nimport {Component, Input, Output} from '@angular/core';\nimport {Subject} from 'rxjs';\n\n@Component({\n  template: `\n      \u003ch1\u003eWebComponent\u003c/h1\u003e\n      \u003cp\u003e@Input() value: {{value | json}}\u003c/p\u003e\n      \u003cbutton (click)=\"update.next(value)\"\u003etrigger output\u003c/button\u003e\n  `\n})\nexport class WebComponent {\n  @Input() value: string;\n  @Output() update = new Subject();\n}\n```\n7. Create `app.module.ts` in `projects/elements/src/app` folder and insert following content:\n```typescript\nimport {Injector, NgModule, Type} from '@angular/core';\nimport {createCustomElement} from '@angular/elements';\nimport {createCustomElements, ElementSet} from 'angular-element-variants';\nimport {variant} from '../variants/variant';\nimport {WebComponent} from './web-component/web.component';\n\nexport const angularElements: ElementSet\u003cType\u003cany\u003e\u003e = {\n  'web-component': WebComponent,\n};\nexport const DECLARATIONS = [\n  WebComponent\n];\n\n@NgModule({\n  declarations: [DECLARATIONS],\n  imports: [],\n  entryComponents: [DECLARATIONS]\n})\nexport class ProviderAppModule {\n  customElementComponent = angularElements;\n\n  constructor(private injector: Injector) {\n  }\n\n  ngDoBootstrap(): void {\n    createCustomElements(variant, angularElements, (componentClass: Type\u003cany\u003e) =\u003e createCustomElement\u003cType\u003cany\u003e\u003e(componentClass, {injector: this.injector}));\n  }\n\n}\n```\n8. Insert the following content `app.component.ts` in `projects/demo-angular/src/app` folder:\n```typescript\n    \u003c!-- WEB COMPONENT GETS INSERTED LATER ON HERE --\u003e\n    \u003cweb-component *axLazyElement\u003e\u003c/web-component\u003e\n```\n9. Add a new scripts entry to `package.json` in the root folder to use your new configuration.\n```json\n{\n  ...\n  \"scripts\": {\n    ... !!! CHANGES HERE !!!\n    \"serve:all\": \"npm-run-all --parallel serve:demo-angular serve:elements:angular-styled\"\n   },\n  ...\n}\n```\n10. Test it and run\n```shell script\nnpm run serve:all\n```\n\n### Setup for Angular Material\n\nNow we setup Angular material. This third library not only serves javascript but also complex css animations as well as components.\nIt will give us a good foundations for style experiments and many more.\n\n1. `ng add @angular/material --project demo`\n   - Choose a prebuilt theme name, or \"custom\" for a custom theme: **Indigo/Pink**\n   - Set up HammerJS for gesture recognition? **No**\n   - Set up browser animations for Angular Material? **Yes**\n2. Revert `angular.json`\n3. Insert `@import \"~@angular/material/prebuilt-themes/indigo-pink.css\";` at the bottom of `projects/demo-angular/src/styles.scss`.\n4. Create a folder `mat-web-component` in `projects/elements/drc/app`.\n5. Create a file `mat-web-component-modules.ts` and insert following content:\n```typescript\nimport {MatFormFieldModule, MatInputModule} from '@angular/material';\nimport {FormsModule} from '@angular/forms';\nimport {BrowserAnimationsModule} from '@angular/platform-browser/animations';\n\nexport const MAT_WEB_COMPONENT_MODULES = [\n BrowserAnimationsModule,\n FormsModule,\n MatFormFieldModule,\n MatInputModule\n];\n```\n4. Insert required modules and the class and tag name of the element in `app.module.ts` in `projects/elements/src/app` folder:\n```typescript\n... \nexport const angularElements: any[] = [\n  ... !!! CHANGE HERE !!! \n  [MatWebComponent, 'mat-web-component']\n];\n @NgModule({\n   ...\n   imports: [\n     ... !!! CHANGE HERE !!!\n     MAT_WEB_COMPONENT_MODULES\n   ],\n   ...\n })\n export class AppModule implements DoBootstrap {\n  ...\n }\n```\n5. Create `mat-web.component.ts` in `projects/elements/src/app/mat-web-component` folder and insert following content:\n```typescript\nimport {ChangeDetectionStrategy, Component, Input, Output} from '@angular/core';\nimport {Subject} from 'rxjs';\n\n@Component({\n  template: `\n      \u003ch1\u003eMatWebComponent\u003c/h1\u003e\n      \u003cp\u003e@Input() value: {{value | json}}\u003c/p\u003e\n      \u003cbr/\u003e\n      \u003cmat-form-field\u003e\n          \u003cinput matInput\n                 placeholder=\"Favorite food\"\n                 [value]=\"value\"\n                 (input)=\"event.next($event)\"\u003e\n      \u003c/mat-form-field\u003e\n  `\n})\nexport class MatWebComponent {\n  @Input() value: string;\n  @Output() event = new Subject();\n}\n```  \n\n### Setup for Angular Dynamic Forms \n\nIn this section we setup another third party library for dynamic form generation.\nThe library itself reuses material and also adds other logic. \n\nInteresting here we don't know how change detection is handled internally.  \n\n1. `npm i @ng-dynamic-forms/core -S`\n2. `npm i @ng-dynamic-forms/ui-material -S`\n3. `npm i angular2-text-mask -S\n4. Create a folder `dynamic-form-component` in `projects/elements/drc/app`.\n5. Create a file `dynamic-form-component-modules.ts` and insert following content:\n```typescript\nimport {BrowserAnimationsModule} from '@angular/platform-browser/animations';\nimport {MatCardModule, MatNativeDateModule} from '@angular/material';\nimport {ReactiveFormsModule} from '@angular/forms';\nimport {DynamicFormsMaterialUIModule} from '@ng-dynamic-forms/ui-material';\n\nexport const DYNAMIC_FORM_COMPONENT_MODULES = [\n  BrowserAnimationsModule,\n  ReactiveFormsModule,\n  DynamicFormsMaterialUIModule,\n  MatNativeDateModule,\n  MatCardModule\n];\n```\n\n4. Insert required modules in `app.module.ts` in `projects/elements/src/app` folder:\n```typescript\n...\nimport {ReactiveFormsModule} from '@angular/forms';\nimport {BrowserAnimationsModule} from \"@angular/platform-browser/animations\";\nimport {DynamicFormsMaterialUIModule} from \"@ng-dynamic-forms/ui-material\";\nimport {MatNativeDateModule} from \"@angular/material\";\n ...\n\nexport const angularElements: any[] = [\n  ... !!! CHANGE HERE !!!\n  [DynamicFormWebComponent, 'dynamic-form-web-component']\n];\n\n @NgModule({\n   ...\n   imports: [\n     ... !!! CHANGE HERE !!!\n     DYNAMIC_FORM_WEB_COMPONENT_MODULES\n   ],\n   ...\n })\n export class AppModule implements DoBootstrap {\n  ...\n }\n```\n5. Create `dynamic-form-web.component.ts` in `projects/elements/src/app/dynamic-form-component` folder and insert following content:\n\n```typescript\nimport {ChangeDetectionStrategy, Component, Input, Output} from '@angular/core';\nimport {Subject} from 'rxjs';\nimport {DynamicFormService} from \"@ng-dynamic-forms/core\";\n\n@Component({\n  template: `\n      \u003ch1\u003eDynamicFormWebComponent\u003c/h1\u003e\n      \u003cform [formGroup]=\"formGroup\"\u003e\n          \u003cdynamic-material-form\n                  [group]=\"formGroup\" [model]=\"_formModel\"\n                  (change)=\"change.next($event)\"\u003e\n          \u003c/dynamic-material-form\u003e\n      \u003c/form\u003e\n  `,\n  // @NOTICE Change to .OnPush only works with reactive architecture atm\n  changeDetection: ChangeDetectionStrategy.Default\n})\nexport class DynamicFormWebComponent {\n  formGroup = this.formService.createFormGroup([]);\n\n  _formModel = [];\n  @Input() set formModel(fM) {\n    this._formModel = this.formService.fromJSON(fM);\n    this.formGroup = this.formService.createFormGroup(this._formModel);\n  };\n\n  @Output() change = new Subject();\n\n  constructor(private formService: DynamicFormService) {\n\n  }\n}\n```  \n\n## ZoneHandling and Angular Elements\n\nThere are 2 way how to manage change detection in angular components:\n1. Zone-less (change detection needs to be managed manually)\n2. Zone-full (change detection is managed by `zone.js` in 2 possible flavors)\n\nIn the following I summarized different approaches and their pros and cons:\n\n### Zone-less\n\nThis approach can be used inside an non-angular as well as angular.\nWith some changes in the code we replace `NgZone` instance with `'noop'`.\n\nChanges then have to be managed manually. Especially in a non angular project \nthis approach is good because won't `zone.js` monkey-patch a lot of global/window APIs.\n\n**Pro:**  \nNo Window API will be patched, and the bundle size is smaller (zone.js will be ~12k).  \n\n**Con:**  \nUser need to take care of Change Detection, and existing Angular Component can't be exported as Angular Element without changes.\n\nTo test this and run a angular project zone-less following steps should be made:\n1. Open `projscts/elements/src/variants/` of your **provider project** and set `zone` to `ZoneHandling.None`\n2. Test it by importing `NgZone` into `variant.angularStyled.ts` and log the instance:\n```txpescript\n constructor(private ngZone: NgZone) {\n    console.log('ngZone', this.ngZone);\n }\n```\nYou should see `NoopNgZone` as class name. \n\nThat's it. Now we run zone-less. :)\n\n#### Problems with Components when Running Zone Less\n\nNext to some edge cases with zones and web components it works change detection pretty seamless in angular.\nHowever, when exiting zone and approaching a fully reactive zone-less setup we run into several scenarios that end up problematic.\n\nLet's see what scenarios we should take a closer look:     \n- Template bindings \n- Input/Output bindings\n- Logic triggered internally\n- DOM Events\n- Internal Logic\n\n##### Template Bindings\n\nIf we test some basic template bindings, displaying a primitive or a simple object, we see no changes in the view.\n```html\np: {{primitive}}, o: {{o | json}} \n``\n\nAlso with the `async` pipe nothing gets rendered. \nThis is the case because the async pipe only triggers `ChangeDetectorRef.markForCheck()`, \nbut change detection does not look for changes, as it is disabled. \n\n```html\np$: {{primitive$ | async}}, o$: {{o$ | async | json}} \n```\n\nTo solve it we need to trigger `ChangeDetectorRef.detectChanges()` whenever we want to render.\n\nOne of the first approaches would be to implement a `tap` operator and trigger cd there before it is rendered in the view. \nBut this would end up in a off by one issue and therefore is no solution.\n\nA proper solution is trigger `detectChanges()` over a pipe,\nso rendering runs after the value arrives in the template.\n\n**Primitive Workaround**\nTo achieve it in a quick an dirty way is following:\n1. Create a file called `push.pipe.ts` into your projects `src` folder.\n2. Copy the source file for the `async` pipe from the angular repo. Here the link to the file [async_pipe.ts](https://github.com/angular/angular/blob/ab29874f09463e634b6aa8ec61fb1f607e108e2f/packages/common/src/pipes/async_pipe.ts). \n3. Replace [following line](https://github.com/angular/angular/blob/ab29874f09463e634b6aa8ec61fb1f607e108e2f/packages/common/src/pipes/async_pipe.ts#L144) with this snippet:\n```typescript\n this._ref.detectChanges();\n```\n4. Replace [following line](https://github.com/angular/angular/blob/ab29874f09463e634b6aa8ec61fb1f607e108e2f/packages/common/src/pipes/async_pipe.ts#L71-L72) with this snippet:\n```typescript\n @Pipe({name: 'push', pure: false})\n export class PushPipe implements OnDestroy, PipeTransform {\n```\n5. Add it to you `app.module.ts` declarations: \n```typescript\n...\nimport {PushPipe} from \"./push.pipe\";\n\n@NgModule({\n  declarations: [\n    ...\n    PushPipe\n  ],\n  ...\n})\nexport class AppModule {\n  ...\n}\n```\n6. Use it like this: `{{observable$ | push}}`\n\n**Needs**\nWe refactor async pipe to fulfill strict and consistent undefined handling as described in [Input Bindings](Input-Bindings).\nAlso the mentioned call of `detectChanges()` needs to be done inside. \nOptional we could schedule side effects over `requestAnimationFrame`.\n\n##### Input Bindings\n\nInput Bindings don't fire after the initial render. \nThe code below shows a setup where we can test this.\n```typescript\n...\n\n@Component({\n  selector: 'minimal',\n  template: `\n      \u003cp\u003e@Input() value: {{value$ | async}}\u003c/p\u003e\n  `\n})\nexport class MinimalComponent {\n  value$ = new ReplaySubject\u003cstring\u003e(1);\n  @Input() set value(v: string) {\n    console.log('setter fired with:', v);\n    this.value$.next(v);\n  };\n}\n```\n\nThe setter for the `value` property is only called once, no matter how often we change the input value.\nAlso a switch to `ChangeDetectionStrategy.OnPush` behaves in the same way.\n\nThe solution is to use the above explained push pipe to trigger change detection after the value arrived an the input binding:\n```html\n  \u003cminimal\n    [value]=\"observable$ | push\"\u003e\n  \u003c/minimal\u003e\n```\n\n##### Output Bindings\n\nOutput Bindings fire even without zone.js. \nBelow you see the sample:\n```typescript\n@Component({\n  selector: 'minimal',\n  template: `\n      \u003cbutton (click)=\"update$.next($event)\"\u003etrigger output\u003c/button\u003e\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class MinimalComponent {\n  update$ = new Subject();\n  @Output() update = this.update$;\n}\n```\nThis means the function is fired in the parent. You can process it but if you want to render the value you again have to use the `push` pipe:\n```typescript\n@Component({\n  selector: 'app-root',\n  template: `\n      \u003ccode\u003e{{update$ | push}}\u003c/code\u003e\n      \u003cminimal\n              (update)=\"log($event)\"\u003e\n      \u003c/minimal\u003e\n  `\n})\nexport class AppComponent {\n  update$ = new Subject();\n\n  log(v) {\n    console.log('processing possible with:', v);\n    this.update$.next(v.clientY);\n  }\n}\n\n```\n\n##### Dom Events\n\nSimilar to output bindings dom events work without zone.js. \nIn the following example we see that the DOM event get's processed in `setFocus`.\n```typescript\n@Component({\n  ...\n  template: `\n      \u003cinput\n              (focus)=\"setFocus(true)\"\n              (blur)=\"setFocus(false)\"\u003e\n  `\n  ...\n})\nexport class MinimalComponent {\n  focus = false;\n  setFocus($event) {\n    console.log('setFocus triggered', $event);\n    this.focus = $event;\n  }\n}\n```\n\nIf we want to render it we solve it in the same way as we did with output bindings. \nWe simple use the `push` pipe.\n```typescript\n@Component({\n  ...,\n  template: `\n      focus: {{focused | push}}\n      \u003cinput\n              (focus)=\"setFocus(true)\"\n              (blur)=\"setFocus(false)\"\u003e\n  `,\n ...\n})\nexport class MinimalComponent {\n  focused = new BehaviorSubject\u003cboolean\u003e(false);\n\n  setFocus($event) {\n    this.focused.next($event);\n  }\n}\n```\n\nAnother thing we could do is forward the state directly as output binding. \nHere we already know we dont need to care about change detection.\n\n```typescript\n@Component({\n  ...,\n  template: `\n      {{focused | async}}\n      \u003cinput\n          (focus)=\"focused.next(true)\"\n          (blur)=\"focused.next(false)\"\u003e\n  `,\n ...\n})\nexport class MinimalComponent {\n  @Output() focused = new BehaviorSubject\u003cboolean\u003e(false);\n}\n```\nNow the parent has to take care about chane detection and we are out of the game ;).\nWe can even use the async pipe because if change detection get's triggered from parent it will update.\n\n##### Animations\n\nAnimations in general work fine. They only need to be triggered.\nWhen we process any value coming from input bindings everything animates properly.\nAs mentioned before values from input bindings are our **save path**.\n\nHere a example opening/closing a box over height transition:\n```typescript\n@Component({\n  selector: 'app-open-close',\n  animations: [\n    trigger('openClose', [\n      state('open', style({height: '200px'})),\n      state('closed', style({height: '100px'})),\n      transition('open =\u003e closed', [animate('1s')]),\n      transition('closed =\u003e open', [animate('0.5s')]),\n    ]),\n  ],\n  template: `\n      \u003cdiv [@openClose]=\"isOpen ? 'open' : 'closed'\" class=\"open-close-container\"\u003e\n          \u003cp\u003eThe box is now {{ _isOpen ? 'Open' : 'Closed' }}!\u003c/p\u003e\n      \u003c/div\u003e\n  `,\n  styles: [`\n      .open-close-container {\n          background-color: green;\n      }\n  `]\n})\nexport class OpenCloseComponent {\n  @Input() isOpen: boolean;\n}\n```\nAs you can see to trigger the animation we use normal template bindings `[@openClose]=\"_isOpen ? 'open' : 'closed'\"`, \nno `push` pipe needed.\n\nIf we want to trigger the animation on click without values over input bindings is stops working: \n\n```typescript\n...\n@Component({\n  selector: 'app-open-close',\n  animations: [...],\n  template: `\n      \u003cdiv (click)=\"toggle()\" [@openClose]=\"isOpen ? 'open' : 'closed'\" class=\"open-close-container\"\u003e\n          \u003cp\u003eThe box is now {{ isOpen ? 'Open' : 'Closed' }}!\u003c/p\u003e\n      \u003c/div\u003e\n  `,\n  styles: [...]\n})\nexport class OpenCloseComponent {\n\n  isOpen: boolean = true;\n\n  toggle() {\n    this.isOpen = !this.isOpen;\n  }\n\n}\n```\n\nHere we need to introduce some changes. \nWe could use the `push` pipe or trigger change detection based on dom events.\n\nWith the `push` pipe it looks like this:\n```typescript\n...\n@Component({\n  ...\n  template: `\n    \u003cdiv (click)=\"toggle()\" [@openClose]=\"(isOpen$ | push$) ? 'open' : 'closed'\" class=\"open-close-container\"\u003e\n        \u003cp\u003eThe box is now {{ (isOpen$ | push$) ? 'Open' : 'Closed' }}!\u003c/p\u003e\n    \u003c/div\u003e\n  `,\n  ...\n})\nexport class OpenCloseComponent {\n\n    isOpen$$ = new BehaviorSubject\u003cany\u003e('');\n    isOpen$ = this.isOpen$$\n      .pipe(scan(acc =\u003e !acc, false));\n    \n    toggle() {\n      this.isOpen$$.next('');\n    }\n\n}\n```\n\nThe approach with events depends on the given situation. \nIn best case we have access to the component and can implement a call of `.detectChanges()` if needed:\n\n```typescript\n...\n@Component({\n  ...\n  template: `\n      \u003cdiv (click)=\"toggle()\" [@openClose]=\"isOpen ? 'open' : 'closed'\" class=\"open-close-container\"\u003e\n          \u003cp\u003eThe box is now {{ isOpen ? 'Open' : 'Closed' }}!\u003c/p\u003e\n      \u003c/div\u003e\n  `,\n  ...\n})\nexport class OpenCloseComponent {\n\n  isOpen: boolean = true;\n  toggle() {\n    this.isOpen = !this.isOpen;\n    this.cd.detectChanges();\n  }\n\n  constructor(private cd: ChangeDetectorRef) {\n  }\n\n}\n```\n\nIf this is not possible, think about third party components or directives, we need to go another path.\n\nAs the animation is triggered over a click event we can apply a event binding for the same event \nto our component from the parent view and trigger change detection from there. \n\n```typescript\n@Component({\n  selector: 'app-root',\n  template: `\n      \u003capp-open-close (click)=\"cd.detectChanges()\"\u003e\u003c/app-open-close\u003e\n  `\n})\nexport class AppComponent {\n\n  constructor(private ngZone: NgZone, private cd: ChangeDetectorRef) {\n    console.log('ngZone', this.ngZone);\n  }\n\n}\n```\n\nTo things are worth to mention here. \nFirst we can imaging when we have many different events that trigger animations (or other internal processes)\nwe end up in a very long and bulky snippet. \n\nSecond this workaround is not working for all cases. Imagine a focus event would be a trigger.\nThis would simply not work with the above solution.\n \n**Needs:**\nAbstract change detection triggering of multiple events into a directive. \nThe component can stay free from any additional imports or logic.\n\n##### Internal Logic\n\nWe can run any kind of logic internally and don't have to think about `zone.js`. \nCommunicate with services, other parts of the component. Only if we want to render\nsomething to the view we have to consider change detection. \n\nAs we already know how to use observables we put the data to render in a stream and use the `push` pipe to trigger rendering.\nThis is exactly the same thing we nearly always did so far.\n\nLet's look at a simple examples where we render the actual time to the view:\n```typescript\n@Component({\n  ...,\n  template: `{{time$ | push}}`,\n ...\n})\nexport class MinimalComponent {\n  time$ = new interval(1000)\n    .pipe(map(_ =\u003e {\n              const d = new Date();\n              return d.getHours() + \":\" + d.getMinutes() + \":\" + d.getSeconds();\n            }));\n}\n```\n\nThat easy. :)\n\n#### Problems with WebComponents when Running Zone Less\n\nWebComponent Template bindings, output bindings, internal logic, dom events \nas well as animations behave in the same way as they do for normal Angular components.\n \n**The Difference:**\nInput bindings however, behave a bit different. We see no values entering until we trigger change detection. \nBut this is not a big deal as we are already used to use the `push` pipe.  \n\nIf we use it for input bindings it works: `\u003cweb-component [value]=\"observable$ | push\"\u003e\u003cweb-component\u003e`\n\n### Zone-full  \n\nUsed inside an angular where `zone.js` is already loaded.\nThis means we can turn basically any angular component into a web-component we no effort.\n\nUnfortunately there are some problems at the moment where we need to work around. \nAs we have multiple zone instances some issues occur,\nespecially in async processes as timeouts, animations promises.\n\n**Pro:**   \nUser can develop Angular Element just like they develop normal Angular Component, \nand user can easily expose a lot of existing Angular Component to Angular Element.  \n\n**Con:**  \nIn this case, there is a limitation that the Angular Element need to run in a Angular App Host.  \nWe need to implement one of the following workarounds:\n- Parent-Zone Hack (Reuse parent zone in web-component `compilerOptions`)\n- Context-Aware-Zones Hack (Patch and restore APIs depending on component borders)\n\n#### Parent-Zone Hack\n\nThe here is to pass the zone instance from the parent or consumer app in this document called **demo** too the provider app in this document called **elements**.\nThere the bootstrap mechanism of the provider side will take over the zone instance from the consumer application and replaces it's own instance.\n\nAs we want to be flexible we setup a mechanism that handles different scenarios.\n\nHere we cover following:\n- **Consumed by Angular** - We pass the paren zone to the elements and have change detection in the web component working properly with angular. (`this.ngZone`)\n  NOTE: If the consumer app has zone disables it automatically passes `NoopNgZone`\n- **Consumed by running Zone-Less** - We pass 'noop' as string and therefore have to manage change detection in the web component on our own. (`'noop'`) \n- **Stand Alone** - We pass nothing and let the web component use the original zone instance from the elements project. (`undefined`)\n\nLet's implement the mechanism\n\n1. Insert following code into `demo-angular.module.ts` located in `projects/demo-angular/src/app/angular-elements`: \n```typescript\nexport class DemoAngularModule {\n  ... \n\n  constructor(private ngZone: NgZone) {\n    // Options are: this.ngZone, 'noop', undefined\n    (window as any).ngZone = this.ngZone;\n  }\n}\n```\n2. Insert following code into `main.ts` located in `projects/elemets/src`: \n```typescript\nplatformBrowserDynamic()\n//                          !!! CHANGE HERE !!!\n.bootstrapModule(AppModule, getCompilerOptions())\n  .catch(err =\u003e console.error(err));\n\n// !!! CHANGE HERE !!!\nfunction getCompilerOptions() {\n  const ngZone = (window as any).ngZone;\n  if (ngZone) {\n    return  {ngZone};\n  }\n  return {};\n}\n```\n\n#### Context-Aware-Zones-Zones\n@TODO\n\n#### ViewEncapsulation and Styling\n\nIn the next few sections we will quickly discuss the different ViewEncapsulation options.\nBut be aware we can control everything over our `variants.ts` over the `encapsulation` key. \n\n### View Encapsulation with Option `None`\nWhen can set `encapsulation` of our component to `ViewEncapsulation.None` like this: \n```typescript\n@Component({\n  ... !!! CHANGES HERE !!!\n  encapsulation: ViewEncapsulation.None\n})\nexport class WebComponent {\n    ...\n}\n```\nHere we can override the styles of a web component by just adding styles to our `styles.css`.\n\nAs we can see in the demo app when running `npm run start` the headlines of the components are green. \nThis style rule is placed in our `projects/styles.css` file.\n\n### View Encapsulation with Option `ShadowDom`\nWhen using `ViewEncapsulation.ShadowDom` we seal the components styles by using the [Shadow DOM](https://w3c.github.io/webcomponents/spec/shadow/).\n```typescript\n@Component({\n  ... !!! CHANGES HERE !!!\n  encapsulation: ViewEncapsulation.ShadowDom\n})\nexport class WebComponent {\n    ...\n}\n```\n\nBy definition of the shadow dom now we can't override styling of our web-components.\nWe test it by checking if we the headlines of the different web components are NOT green anymore.\n\n### View Encapsulation with Option `Emulated`\n\nWhen using `ViewEncapsulation.Emulated` is the default setting and emulates the behavior of shadow DOM by applying styles over attributes.\n\n```typescript\n@Component({\n  ... !!! CHANGES HERE !!!\n  encapsulation: ViewEncapsulation.Emulated\n})\nexport class WebComponent {\n    ...\n}\n```\nHere, same as with `ViewEncapsulation.ShadowDom` we can't override styling of our web-components. The differences is that we can't override outside of the components styling\n\n## Loading Strategies\n\nThere are different loading strategies. Some of them are not only convenient but also help to solve problems in change detection.   \nIn this document we discuss following strategies:\n- [x] bundled within the app\n- [x] lazy loaded pre compiled\n- [x] lazy loaded un-compiled \n\nLet's first clarify what `pre-compiled` and `un-compiled` means. \n\nLet's quickly clarify wording. When we speak about **pre-compiled** elements we speak about a bundle that includes the creation of the elements.\nTo be more specific we speak about a bundle that includes the call to \n```typescript\nconst element = createCustomElement(componentClass, {injector: this.injector});\ncustomElements.define(selector, element);\n```\n\nIf this is done in the consumer bundle we speak about **un-compiled** elements.\nMaybe the wording is not perfect, but huh.. we have to start somewhere. ;)\n\nSo when we speak about `pre-compiled` Angular elements we mean that the call to `createCustomElement` is done in the provider bundle:\n```typescript\n...\n@NgModule({\n  declarations: [ELEMENTS],\n  ...\n  entryComponents: [ELEMENTS]\n})\nexport class ProviderAppModule implements DoBootstrap {\n\n  constructor(private injector: Injector) {\n  \n  }\n\n  ngDoBootstrap(): void {\n      const element = createCustomElement(MyComponent, {injector: this.injector});\n      customElements.define('my-component', element);\n  }\n\n}\n```\n\nThe element gets loaded from the consumer, the JavaScript executes and the elements can be used. \nThis is a go to approach for stand-alone components and also works seamless within an Angular application.\n\nWhen we speak about `un-compiled` Angular elements we mean that the call to `createCustomElement` is done in the consumer bundle:\n\n```typescript\n...\n@NgModule({\n})\nexport class ConsumerAppModule implements DoBootstrap {\n\n  constructor(private injector: Injector) {\n  \n}\n\n  ngDoBootstrap(): void {\n      const element = createCustomElement(MyComponent, {injector: this.injector});\n      customElements.define('my-component', element);\n  }\n\n}\n```\n### Elements Pre-compiled Eager Loaded\n\nThe eager loaded strategy is already included and described in the section setup. \n\n### Elements Pre-compiled Lazy Loaded\n\nThe lazy loaded strategy is already included and described in the section setup. \nIt's performs way better than the bundled strategy and also brings points for the first meaningful pain \nas the elements are loaded only if they are needed.\n\n### Setup Elements Un-compiled Lazy Loaded\n\n1. `npm i -S @juristr/ngx-lazy-el`,\n2. Create folder `lazy-el` in `projects/demo/src/app`.\n3. Create file `lazy-el.module.ts` in `projects/demo/src/app/lazy-el`.\n4. Insert following content: \n```typescript\nimport {NgModule, NgModuleFactoryLoader, SystemJsNgModuleLoader} from '@angular/core';\nimport {fakeMatcher, NgxLazyElModule} from '@juristr/ngx-lazy-el';\n\nexport const lazyConfig = [\n  {\n    selector: 'web-component',\n    matcher: fakeMatcher,\n    loadChildren: () =\u003e import('../../../../elements/src/app/app.module')\n      .then(m =\u003e m.AppModule)\n  }\n];\n\n@NgModule({\n  imports: [\n    NgxLazyElModule.forRoot(lazyConfig),\n  ],\n  providers: [\n    {provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader},\n  ],\n  exports: [\n    NgxLazyElModule\n  ]\n})\nexport class LazyElModule {\n\n}\n```\n5. Add following lines in `projects/demo/src/app/app.module.ts`:\n```typescript\n...\nimport {LazyElModule} from './lazy-el/lazy-el.module';\n\n@NgModule({\n  ...\n  imports: [\n    // ... !!! CHANGES HERE !!!\n    LazyElModule\n  ],\n  ...\n})\n...\n```\n\nYour app is now ready to work with angular elements.\nNow let's setup some content in `app.component.ts` to experiment.\n\n7. Open your `app.component.ts` in `projects/demo/src/app` folder and insert following content:\n```typescript\n...\n@Component({\n  ...,\n  template: `\n     ...\n     \u003cweb-component *ngxLazyEl\u003e\u003c/web-component\u003e\n  `\n})\n...\n```\nDone with the consumer app. Now let's setup the provider app.\n\n#### Setup Provider Application for Un-Compiled Loading\n\nAs we did before we try to solve as much as possible over configuration. So let's implement another flag in our environment files.\n\n1. Adopt the following code in `app.module.ts` in `projects/elements/src/app` folder:\n```typescript\n...\nexport class AppModule {\n  // !!! CHANGES HERE !!!\n  customElementComponent = angularElements;\n}\n...\n```\n\nNow the LazyEl Service can find our provided components.\nTry to run the application.\n\nAfter having both of them working let's compare them:\n\nWhere the pre-compiled approach is a state of the art way to bundle and serve web components the un-compiled lazy loading approach I'm more an exot.\n\nThe reason that web components are created in addition to lazy load components is because of their usage im the template.\nWe can just place the tag there and don't have to care about creating and registering the component. \n\nThe rest, is exactly the same as with normal components. Also the injector tree is the one from the consumer app.\nThis means that for example the `BrowserAnimationsModule` that is needed for our web-component needs to be placed in the consumer app now instead of the provider app.\nAnother reason why it is better to also maintain this kind of loaded components in the consumer app and not a a separate project. \n\n**Un-compiled Lazy Loading Overview**   \n\n**Pros**   \n- Easyer than creating just dynamic components (just use tag name that's it)\n- On demand loading\n- Shared injection scope with consumer (therefore also same zone)   \n\n**Cons**   \n - Components can be developed and depolyed separately\n - Bundling has to happen at build time\n - No sealed environment. Interference with consumer apps injection scope \n   This means we have to maintain dependencies on consumer and provider und side.\n    \n \n## Productivity Helpers\n- [x] Push Pipe\n- [x] Let Directive\n- [x] CdOn Directive\n\n### Push Pipe\n\nAn Angular pipe similar to the `async` pipe but triggers `detectChanges` instead of `markForCheck`.\nThis is required to run zone-less. We render on every pushed message.\n(currently, there is an [isssue](https://github.com/angular/angular/issues/31438) with the `ChangeDetectorRef` in ivy so we have to wait for the fix.\n\nThe pipe should work as template binding `{{thing$ | push}}` \nas well as input binding `[color]=\"thing$ | push\"` and trigger the changes of the host component.\n\n```html\n\u003cdiv *ngIf=\"(thing$ | push) as thing\"\u003e\n  color: {{thing.color}}\n  shape: {{thing.shape}}\n\u003cdiv\u003e\n\n\u003capp-color [color]=\"(thing$ | push).color\"\u003e\n\u003c/app-color\u003e\n```\n\n**Included Features:**\n- subscription handling overview  life cycle\n- a unified way of handling null and undefined with streams\n- optional flag to turn off scheduling over `AnimationFrameScheduler` (on by default)\n- change detection is done manually which allows it to work zone-less too\n\n### Let Structural Directive\n\nThe `*let` directive serves a convenient way of binding multiple observables in the same view context.\nIt also helps with several default processing under the hood.\n\nThe current way of handling subscriptions in the view looks like that:\n\n```html\n\u003cng-container *ngIf=\"observable1$ | async as c\"\u003e\n  \u003capp-color [color]=\"c.color\" [shape]=\"c.shape\" [name]=\"c.name\"\u003e\n  \u003c/app-color\u003e  \n\u003c/ng-container\u003e\n```\n\nThe `*let` directive take over several things and makes it more convenient and save to work with streams in the template\n`*let=\"{o: o$, t: t$} as s;\"` \n\n```html\n\u003c!-- observables = { color: observable1$, shape: observable2$, name:  observable3$ } --\u003e\n\n\u003cng-container *let=\"observable as c\"\u003e\n  \u003capp-color [color]=\"c.color\" [shape]=\"c.shape\" [name]=\"c.name\"\u003e\n  \u003c/app-color\u003e\n\u003c/ng-container\u003e\n\n\u003cng-container *let=\"observable; let c\"\u003e\n  \u003capp-color [color]=\"c.color\" [shape]=\"c.shape\" [name]=\"c.name\"\u003e\n  \u003c/app-color\u003e\n\u003c/ng-container\u003e\n\n\u003cng-container *let=\"observable; color as c; shape as s; name as n\"\u003e\n  \u003capp-color [color]=\"c\" [shape]=\"s\" [name]=\"n\"\u003e\n  \u003c/app-color\u003e\n\u003c/ng-container\u003e\n```\n\n**Included Features:**\n- binding is always present. (`*ngIf=\"{}\"` normally effects it)\n- it takes away the multiple usages of the `async` pipe \n- propper handling of null and undefined values\n- removes state slices if bound observable completes or errors\n- an option to disable scheduling over `AnimationFrameScheduler` (on by default)\n- control change detection and therefore can run zone-less\n\n### CdOn Directive\nThe `cdOn` directive serves a convenient way of triggering change detection for multiple events.\nIt is **only used to solve edge cases in zone-less applications**,\nby taking away bulky templates and externalizing `ChangeDetectionRef` handling.\n\nThe current way of workaround looks like that:\n\n```html\n\u003cmy-component \n    (click)=\"cd.detectChanges()\"\n    (focus)=\"cd.detectChanges()\"\n    (blur)=\"cd.detectChanges()\"\n    (input)=\"cd.detectChanges()\"\u003e\n\u003c/my-component\u003e\n```\n\nThe `cdOn` directive take over the multiple bindings and reduce them to a single input binding.\n`[cdOn]=\"['eventName']\"`. Also the import of ChangeDetectionRef can be deleted now.\n\n```html\n\u003cmy-component \n    [cdOn]=\"['click','focus','blur','input']\"\u003e\n\u003c/my-component\u003e\n```\n\n**Included Features:**\n- reduce template code \n- manage multiple events\n- manage multiple outputBindings\n- controls change detection for provided events\n- optional change detection is triggered over `AnimationFrameScheduler`\n\n## Browser Support and Backwards Compatibility\n\n@TODO\n\n\n## Performance\n\n### Bundling\n\n### Unoptimized build like `ng serve`:\n\n```typescript\n\"build\": {\n  \"builder\": \"ngx-build-plus:browser\",\n  \"options\": {\n    \"outputPath\": \"dist/elements\",\n    \"index\": \"projects/elements/src/index.html\",\n    \"main\": \"projects/elements/src/main.ts\",\n    \"polyfills\": \"projects/elements/src/polyfills.ts\",\n    \"tsConfig\": \"projects/elements/tsconfig.app.json\",\n    \"aot\": false,\n    \"assets\": [],\n    \"styles\": [\n      \"projects/elements/src/styles.scss\"\n    ],\n    \"scripts\": []\n}\n```\n\n\n---\n\nDefault optimisations possible with Angular cil out of the box:\n\n```typescript\n\"prodStandAlone\": {\n    \"outputPath\": \"dist/elements-stand-alone\",\n    \"fileReplacements\": [\n    {\n      \"replace\": \"projects/elements/src/environments/environment.ts\",\n      \"with\": \"projects/elements/src/environments/environment.prodStandAlone.ts\"\n    }\n    ],\n    \"optimization\": true,\n    \"sourceMap\": false,\n    \"namedChunks\": false,\n    \"aot\": true,\n    \"extractLicenses\": true,\n    \"vendorChunk\": false,\n    \"buildOptimizer\": true\n}\n```\n\n**Webpack Bundle Analyzer:**\nmain-es2015.js (1.02 MB)\npolyfills-es2015.js (36.4 KB)\nstyles-es2015.js (3.01 KB)\nruntime-es2015.js (1.45 KB)\n\n`@angular/material`, here is uncompressed nearly the same size as `@angular/core`:\n\n@angular/material (1.27M)\n\n---\n\nIf we ignore the `styles-es2015.js` as we wont ship it we are down to 2 bundles with the following size: \n\n**Webpack Bundle Analyzer:**\nmain-es2015.js (1.02 MB)\npolyfills-es2015.js (37.23 KB)\n\nIf we ship zone-less  `palyfill-es2015.js` goes down to the following size: \n\n**Webpack Bundle Analyzer:**\npolyfills-es2015.js (37.23 KB)\n\n---\nBy excluding `zone.js` from `polyfills-es2015.js`  (We will any way inject it from the parent) we are down to the following size:\n\n**Webpack Bundle Analyzer:**\npolyfills-es2015.js (976 B)\n\n\n\n\n\n# Angular Architect API\n\n## Chunk Sets\n\nA list of chunk sets in the right order\n\n **Polyfills**\n- polyfills-es5\n\n  _Includes:_ \n  - es5-polyfills.js\n  - zone.js/dist/zone-legacy\n  - polyfills.ts  \n    \n  _Output:_\n  - polyfills-es5-es2015.js\n  - polyfills-es5-es2015.js.map\n   \n   \n - polyfills\n\n    _Includes:_\n    - polyfills.ts\n    \n    _Output:_\n    - polyfills-es2015.js\n    - polyfills-es2015.js.map\n\n**Global Styles**\n - styles\n \n    _Includes:_ \n    - styles.css  \n    \n    _Output:_\n    - styles-es2015.js\n    - styles-es2015.js.map\n\n - stylesEs5\n    \n    _Includes:_ \n    -  styles.css\n  \n    _Output:_\n    - styles-es5.js\n    - styles-es5.js.map\n\n**Scripts**\n- scripts\n    _Includes:_ \n    - all files in architect API under \"scripts\"\n    \n    _Output:_\n    - scripts.js\n    \n**Framework and Application**\n- main  \n    _Includes:_\n    - main.ts  \n    \n    _Output:_\n    - main-es2015.js\n    - main-es2015.js.map \n   \n - runtime  \n    _Includes:_  \n    - runtime.ts\n    \n    _Output:_\n    - runtime-es2015.js\n    - runtime-es2015.js.map\n\n- vendor  \n\n    _Includes:_\n    - vendor.ts\n    \n    _Output:_\n    - vendor-es2015.js\n    - vendor-es2015.js.map\n\n- mainEs5: \n\n    _Includes:_\n    - main.ts\n\n    _Output:_\n    - main-es5.js\n    - main-es2015.js.map\n    \n- runtimeEs5\n \n    _Includes:_  \n    - runtime.ts \n    \n    _Output:_\n    - runtime-es5.js\n    - runtime-es2015.js.map\n\n- vendorEs5\n\n    _Includes:_\n    - vendor.ts\n    \n    _Output:_\n    - vendor-es5.js\n    - vendor-es2015.js.map\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbiophoton%2Felements","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbiophoton%2Felements","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbiophoton%2Felements/lists"}