docs: add custom elements documentation (#22966)

PR Close #22966
This commit is contained in:
Judy Bogart 2018-02-27 13:33:41 -08:00 committed by Alex Rickabaugh
parent ad9ce5cb41
commit ff34d5ea7a
11 changed files with 447 additions and 168 deletions

View File

@ -0,0 +1,26 @@
// #docregion
import { Component, Injector } from '@angular/core';
import { createNgElementConstructor } from '../elements-dist';
import { PopupService } from './popup.service';
import { PopupComponent } from './popup.component';
@Component({
selector: 'app-root',
template: `
<input #input value="Message">
<button (click)="popup.showAsComponent(input.value)">
Show as component </button>
<button (click)="popup.showAsElement(input.value)">
Show as element </button>
`
})
export class AppComponent {
constructor(private injector: Injector, public popup: PopupService) {
// on init, convert PopupComponent to a custom element
const PopupElement =
createNgElementConstructor(PopupComponent, {injector: this.injector});
// register the custom element with the browser.
customElements.define('popup-element', PopupElement);
}
}

View File

@ -0,0 +1,22 @@
// #docregion
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { PopupService } from './popup.service';
import { PopupComponent } from './popup.component';
// include the PopupService provider,
// but exclude PopupComponent from compilation,
// because it will be added dynamically
@NgModule({
declarations: [AppComponent, PopupComponent],
imports: [BrowserModule, BrowserAnimationsModule],
providers: [PopupService],
bootstrap: [AppComponent],
entryComponents: [PopupComponent],
})
export class AppModule {}

View File

@ -0,0 +1,58 @@
// #docregion
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { AnimationEvent } from '@angular/animations';
import { animate, state, style, transition, trigger } from '@angular/animations';
@Component({
selector: 'my-popup',
template: 'Popup: {{message}}',
host: {
'[@state]': 'state',
'(@state.done)': 'onAnimationDone($event)',
},
animations: [
trigger('state', [
state('opened', style({transform: 'translateY(0%)'})),
state('void, closed', style({transform: 'translateY(100%)', opacity: 0})),
transition('* => *', animate('100ms ease-in')),
])
],
styles: [`
:host {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: #009cff;
height: 48px;
padding: 16px;
display: flex;
align-items: center;
border-top: 1px solid black;
font-size: 24px;
}
`]
})
export class PopupComponent {
private state: 'opened' | 'closed' = 'closed';
@Input()
set message(message: string) {
this._message = message;
this.state = 'opened';
setTimeout(() => this.state = 'closed', 2000);
}
get message(): string { return this._message; }
_message: string;
@Output()
closed = new EventEmitter();
onAnimationDone(e: AnimationEvent) {
if (e.toState === 'closed') {
this.closed.next();
}
}
}

View File

@ -0,0 +1,54 @@
// #docregion
import { ApplicationRef, ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
import { PopupComponent } from './popup.component';
import { NgElementConstructor } from '../elements-dist';
@Injectable()
export class PopupService {
constructor(private injector: Injector,
private applicationRef: ApplicationRef,
private componentFactoryResolver: ComponentFactoryResolver) {}
// Previous dynamic-loading method required you to set up infrastructure
// before adding the popup to the DOM.
showAsComponent(message: string) {
// Create element
const popup = document.createElement('popup-component');
// Create the component and wire it up with the element
const factory = this.componentFactoryResolver.resolveComponentFactory(PopupComponent);
const popupComponentRef = factory.create(this.injector, [], popup);
// Attach to the view so that the change detector knows to run
this.applicationRef.attachView(popupComponentRef.hostView);
// Listen to the close event
popupComponentRef.instance.closed.subscribe(() => {
document.body.removeChild(popup);
this.applicationRef.detachView(popupComponentRef.hostView);
});
// Set the message
popupComponentRef.instance.message = message;
// Add to the DOM
document.body.appendChild(popup);
}
// This uses the new custom-element method to add the popup to the DOM.
showAsElement(message: string) {
// Create element
const popupEl = document.createElement('popup-element');
// Listen to the close event
popupEl.addEventListener('closed', () => document.body.removeChild(popupEl));
// Set the message
popupEl.message = message;
// Add to the DOM
document.body.appendChild(popupEl);
}
}

View File

@ -1,65 +0,0 @@
# Elements
## Release Status
**Angular Labs Project** - experimental and unstable. **Breaking Changes Possible**
Targeted to land in the [6.x release cycle](https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md) of Angular - subject to change
## Overview
Elements provides an API that allows developers to register Angular Components as Custom Elements
("Web Components"), and bridges the built-in DOM API to Angular's component interface and change
detection APIs.
```ts
//hello-world.ts
import { Component, Input, NgModule } from '@angular/core';
@Component({
selector: 'hello-world',
template: `<h1>Hello {{name}}</h1>`
})
export class HelloWorld {
@Input() name: string = 'World!';
}
@NgModule({
declarations: [ HelloWorld ],
entryComponents: [ HelloWorld ]
})
export class HelloWorldModule {}
```
```ts
//app.component.ts
import { Component, NgModuleRef } from '@angular/core';
import { createNgElementConstructor } from '@angular/elements';
import { HelloWorld } from './hello-world';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(injector: Injector) {
const NgElementConstructor = createNgElementConstructor(HelloWorld, {injector});
customElements.register('hello-world', NgElementConstructor);
}
}
```
Once registered, these components can be used just like built-in HTML elements, because they *are*
HTML Elements!
They can be used in any HTML page:
```html
<hello-world name="Angular"></hello-world>
<hello-world name="Typescript"></hello-world>
```
Custom Elements are "self-bootstrapping" - they are automatically started when they are added to the
DOM, and automatically destroyed when removed from the DOM.

View File

@ -0,0 +1,155 @@
# Custom Elements Overview
[Custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) are a Web Platform feature currently supported by Chrome, Opera, and Safari, and available in other browsers through polyfills (see [Browser Support](#browser-support)).
A custom element extends HTML by allowing you to define a tag whose content is created and controlled by JavaScript code.
The browser maintains a `CustomElementRegistry` of defined custom elements (also called Web Components), which maps an instantiable JavaScript class to an HTML tag.
The `createCustomElement()` API provides a bridge from Angular's component interface and change detection functionality to the built-in DOM API.
Transforming a component to a custom element makes all of the required Angular infrastructure available to the browser. Creating a custom element is simple and straightforward, and automatically connects your component-defined view with change detection and data binding, mapping Angular functionality to the corresponding native HTML equivalents.
## Using custom elements
Custom elements bootstrap themselves - they start automatically when they are added to the DOM, and are automatically destroyed when removed from the DOM. Once a custom element is added to the DOM for any page, it looks and behaves like any other HTML element, and does not require any special knowledge of Angular terms or usage conventions.
- <b>Easy dynamic content in an Angular app</b>
Transforming a component to a custom element provides an easy path to creating dynamic HTML content in your Angular app. HTML content that you add directly to the DOM in an Angular app is normally displayed without Angular processing, unless you define a _dynamic component_, adding your own code to connect the HTML tag to your app data, and participate in change detection. With a custom element, all of that wiring is taken care of automatically.
- <b>Content-rich applications</b>
If you have a content-rich app, such as the Angular app that presents this documentation, custom elements let you give your content providers sophisticated Angular functionality without requiring knowledge of Angular. For example, an Angular guide like this one is added directly to the DOM by the Angular navigation tools, but can include special elements like `<code-snippet>` that perform complex operations. All you need to tell your content provider is the syntax of your custom element. They don't need to know anything about Angular, or anything about your component's data structures or implementation.
### How it works
Use the `createCustomElement()` function to convert a component into a class that can be registered with the browser as a custom element.
After you register your configured class with the browser's custom-element registry, you can use the new element just like a built-in HTML element in content that you add directly into the DOM:
```
<my-popup message="Use Angular!"></my-popup>
```
When your custom element is placed on a page, the browser creates an instance of the registered class and adds it to the DOM. The content is provided by the component's template, which uses Angular template syntax, and is rendered using the component and DOM data. Input properties in the component correspond to input attributes for the element.
<figure>
<img src="generated/images/guide/elements/customElement1.png" alt="Custom element in browser" class="left">
</figure>
<hr class="clear">
<div class="l-sub-section">
We are working on custom elements that can be used by web apps built on other frameworks.
A minimal, self-contained version of the Angular framework will be injected as a service to support the component's change-detection and data-binding functionality.
For more about the direction of development, check out this [video presentation](https://www.youtube.com/watch?v=vHI5C-9vH-E).
</div>
## Transforming components to custom elements
Angular provides the `createCustomElement()` function for converting an Angular component,
together with its dependencies, to a custom element. The function collects the component's
observable properties, along with the Angular functionality the browser needs to
create and destroy instances, and to detect and respond to changes.
The conversion process implements the `NgElementConstructor` interface, and creates a
constructor class that is configured to produce a self-bootstrapping instance of your component.
Use a JavaScript function, `customElements.define()`, to register the configured constructor
and its associated custom-element tag with the browser's `CustomElementRegistry`.
When the browser encounters the tag for the registered element, it uses the constructor to create a custom-element instance.
<figure>
<img src="generated/images/guide/elements/createElement.png" alt="Transform a component to a custom element" class="left">
</figure>
### Mapping
A custom element _hosts_ an Angular component, providing a bridge between the data and logic defined in the component and standard DOM APIs. Component properties and logic maps directly into HTML attributes and the browser's event system.
- The creation API parses the component looking for input properties, and defines corresponding attributes for the custom element. It transforms the property names to make them compatible with custom elements, which do not recognize case distinctions. The resulting attribute names use dash-separated lowercase. For example, for a component with `@Input('myInputProp') inputProp`, the corresponding custom element defines an attribute `my-input-prop`.
- Component outputs are dispatched as HTML [Custom Events](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent), with the name of the custom event matching the output name. For example, for a component with `@Output() valueChanged = new EventEmitter()`, the corresponding custom element will dispatch events with the name "valueChanged", and the emitted data will be stored on the events `detail` property. If you provide an alias, that value is used; for example, `@Output('myClick') clicks = new EventEmitter<string>();` results in dispatch events with the name "myClick".
For more information, see Web Component documentation for [Creating custom events](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events#Creating_custom_events).
{@a browser-support}
## Browser support for custom elements
The recently-developed [custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) Web Platform feature is currently supported natively in a number of browsers. Support is pending or planned in other browsers.
<table>
<tr>
<th>Browser</th>
<th>Custom Element Support</th>
</tr>
<tr>
<td>Chrome</td>
<td>Supported natively.</td>
</tr>
<tr>
<td>Opera</td>
<td>Supported natively.</td>
</tr>
<tr>
<td>Safari</td>
<td>Supported natively.</td>
</tr>
<tr>
<td>Firefox</td>
<td> Set the <code>dom.webcomponents.enabled</code> and <code>dom.webcomponents.customelements.enabled</code> preferences to true. Planned to be enabled by default in version 60/61.</td>
</tr>
<tr>
<td>Edge</td>
<td>Working on an implementation. <br>
Use the <a href="https://cli.angular.io/" target="_blanks">CLI</a> to automatically set up your project with the correct polyfill: <code>ng add @angular/elements</code>.
</td>
</tr>
</table>
- For more information about polyfills, see [polyfill documentation](https://www.webcomponents.org/polyfills).
- For more information about Angular browser support, see [Browser Support](guide/browser-support).
## Example: A Popup Service
Previously, when you wanted to add a component to an app at runtime, you had to define a _dynamic component_. The app module would have to list your dynamic component under `entryComponents`, so that the app wouldn't expect it to be present at startup, and then you would have to load it, attach it to an element in the DOM, and wire up all of the dependencies, change detection, and event handling, as described in [Dynamic Component Loader](guide/dynamic-component-loader).
Using an Angular custom element makes the process much simpler and more transparent, by providing all of the infrastructure and framework automatically&mdash;all you have to do is define the kind of event handling you want. (You do still have to exclude the component from compilation, if you are not going to use it in your app.)
The Popup Service example app defines a component that you can either load dynamically or convert to a custom element.
- `popup.component.ts` defines a simple pop-up element that displays an input message, with some animation and styling.
- `popup.service.ts` creates an injectable service that provides two different ways to invoke the PopupComponent; as a dynamic component, or as a custom element. Notice how much more setup is required for the dynamic-loading method.
- `app.module.ts` adds the PopupComponent in the module's `entryComponents` list, to exclude it from compilation and avoid startup warnings or errors.
- `app.component.ts` defines the app's root component, which uses the PopupService to add the pop-up to the DOM at run time. When the app runs, the root component's constructor converts PopupComponent to a custom element.
For comparison, the demo shows both methods. One button adds the popup using the dynamic-loading method, and the other uses the custom element. You can see that the result is the same; only the preparation is different.
<code-tabs>
<code-pane title="popup.component.ts" path="elements/src/app/popup.component.ts">
</code-pane>
<code-pane title="popup.service.ts" path="elements/src/app/popup.service.ts">
</code-pane>
<code-pane title="app.module.ts" path="elements/src/app/app.module.ts">
</code-pane>
<code-pane title="app.component.ts" path="elements/src/app/app.component.ts">
</code-pane>
</code-tabs>

View File

@ -19,12 +19,11 @@ unexpected definitions.
## Ahead-of-time (AOT) compilation
You can compile Angular applications at build time.
You can compile Angular applications at build time.
By compiling your application using the compiler-cli, `ngc`, you can bootstrap directly to a module factory, meaning you don't need to include the Angular compiler in your JavaScript bundle.
Ahead-of-time compiled applications also benefit from decreased load time and increased performance.
## Annotation
In practice, a synonym for [Decoration](guide/glossary#decorator).
@ -52,7 +51,7 @@ Learn about them in the [_Attribute Directives_](guide/attribute-directives) gui
## Barrel
A way to *roll up exports* from several ES2015 modules into a single convenient ES2015 module.
The barrel itself is an ES2015 module file that re-exports *selected* exports of other ES2015 modules.
The barrel itself is an ES2015 module file that re-exports selected exports of other ES2015 modules.
For example, imagine three ES2015 modules in a `heroes` folder:
@ -67,8 +66,6 @@ For example, imagine three ES2015 modules in a `heroes` folder:
export class HeroService {}
</code-example>
Without a barrel, a consumer needs three import statements:
<code-example>
@ -96,20 +93,14 @@ Now a consumer can import what it needs from the barrel.
</code-example>
The Angular [scoped packages](guide/glossary#scoped-package) each have a barrel named `index`.
<div class="alert is-important">
You can often achieve the same result using [NgModules](guide/glossary#ngmodule) instead.
</div>
## Binding
Usually refers to [data binding](guide/glossary#data-binding) and the act of
@ -121,7 +112,6 @@ between a "token"&mdash;also referred to as a "key"&mdash;and a dependency [prov
## Bootstrap
You launch an Angular application by "bootstrapping" it using the application root NgModule (`AppModule`).
Bootstrapping identifies an application's top level "root" [component](guide/glossary#component),
@ -132,15 +122,21 @@ You can bootstrap multiple apps in the same `index.html`, each app with its own
{@a C}
## camelCase
The practice of writing compound words or phrases such that each word or abbreviation begins with a capital letter
_except the first letter, which is lowercase_.
{@a dash-case}
Function, property, and method names are typically spelled in camelCase. For example, `square`, `firstName`, and `getHeroes`. Notice that `square` is an example of how you write a single word in camelCase.
{@a camelcase}
camelCase is also known as *lower camel case* to distinguish it from *upper camel case*, or [PascalCase](guide/glossary#pascalcase).
In Angular documentation, "camelCase" always means *lower camel case*.
## Case conventions
Angular uses capitalization conventions to distinguish the names of various types, as described in the [Style Guide "Naming" section](guide/styleguide#02-01).
- camelCase : symbols, properties, methods, pipe names, interfaces, non-component directive selectors, constants
- UpperCamelCase (also called PascalCase): Class names
- dash-case (also called "kebab-case"): descriptive part of file names, component selectors
- underscore_case (or "snake_case"): not typically used in Angular
- UPPER_SNAKE_CASE : traditional for constants (acceptable, but prefer camelCase)
## CLI
@ -151,7 +147,6 @@ Learn more in the [Getting Started](guide/quickstart) guide.
{@a component}
## Component
An Angular class responsible for exposing data to a [view](guide/glossary#view) and handling most of the views display and user-interaction logic.
@ -167,22 +162,25 @@ as a view.
Those familiar with "MVC" and "MVVM" patterns will recognize
the component in the role of "controller" or "view model".
{@a custom-element}
## Custom element
A Web Platform feature, currently supported by most browsers, and available in other browsers through polyfills (see [Browser Support](guide/browser-support)).
The custom element feature extends HTML by allowing you to define a tag whose content is created and controlled by JavaScript code. A custom element (also called a *web component*) is recognized by a browser when it is added to the [CustomElementRegistry](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry).
You can use the API to transform an Angular component so that it can be registered with the browser and used in any HTML that you add directly to the DOM within an Angular app. The custom element tag inserts the component's view, with change-detection and data-binding functionality, into content that would otherwise be displayed without Angular processing.
See also [Dynamic components](guide/glossary#dynamic-components).
{@a D}
## dash-case
The practice of writing compound words or phrases such that each word is separated by a dash or hyphen (`-`).
This form is also known as kebab-case.
[Directive](guide/glossary#directive) selectors (like `my-app`) and
the root of filenames (such as `hero-list.component.ts`) are often
spelled in dash-case.
## Data binding
Applications display data values to a user and respond to user
Data binding allow apps to display data values to a user and respond to user
actions (such as clicks, touches, and keystrokes).
In data binding, you declare the relationship between an HTML widget and data source
@ -215,7 +213,7 @@ operations and supporting declaration syntax.
A *function* that adds metadata to a class, its members (properties, methods) and function arguments.
Decorators are an experimental (stage 2), JavaScript language [feature](https://github.com/wycats/javascript-decorators). TypeScript adds support for decorators.
Decorators (also called annotations) are an experimental (stage 2), JavaScript language [feature](https://github.com/wycats/javascript-decorators). TypeScript adds support for decorators.
To apply a decorator, position it immediately above or to the left of the item it decorates.
@ -223,6 +221,7 @@ Angular has its own set of decorators to help it interoperate with your applicat
The following example is a `@Component` decorator that identifies a
class as an Angular [component](guide/glossary#component) and an `@Input` decorator applied to the `name` property
of that component. The elided object argument to the `@Component` decorator would contain the pertinent component metadata.
```
@Component({...})
export class AppComponent {
@ -230,6 +229,7 @@ export class AppComponent {
@Input() name:string;
}
```
The scope of a decorator is limited to the language feature
that it decorates. None of the decorations shown here will "leak" to other
classes that follow it in the file.
@ -334,39 +334,34 @@ as HTML attributes, hence the name.
shaping or reshaping HTML layout, typically by adding, removing, or manipulating
elements and their children.
{@a dynamic-components}
## Dynamic component loading
A technique for adding a component to the DOM at run time, which requires that you exclude the component from compilation, then connect it to Angular's change-detection and event handling framework when you add it to the DOM.
See also [Custom element](guide/glossary#custom-element), which provides an easier path with the same result.
{@a E}
{@a ecma}
## ECMAScript
The [official JavaScript language specification](https://en.wikipedia.org/wiki/ECMAScript).
The latest approved version of JavaScript is
[ECMAScript 2017](http://www.ecma-international.org/ecma-262/8.0/)
(also known as "ES2017" or "ES8"). Many Angular developers write their applications
in ES8 or a dialect that strives to be
compatible with it, such as [TypeScript](guide/glossary#typescript).
Most modern browsers only support the much older "ECMAScript 5" (also known as "ES5") standard.
Applications written in ES2017, ES2016, ES2015, or one of their dialects must be [transpiled](guide/glossary#transpile)
to ES5 JavaScript.
Angular developers can write in ES5 directly.
Not all browsers support the latest ECMAScript standard, but you can use transpilers (like [TypeScript](guide/glossary#typescript)) to write code using the latest features, which will then be transpiled to code that runs on versions that are supported by browsers.
## ES2015
{@a element}
Short hand for [ECMAScript](guide/glossary#ecmascript) 2015.
## Element
Angular defines an `ElementRef` class to wrap render-specific native UI elements. This allows you use Angular templates and data-binding to access DOM elements without reference to the native element in most cases.
## ES5
The documentation generally refers to either elements (`ElementRef` instances) or DOM elements (which could be accessed directly if necessary).
Short hand for [ECMAScript](guide/glossary#ecmascript) 5, the version of JavaScript run by most modern browsers.
## ES6
Short hand for [ECMAScript](guide/glossary#ecmascript) 2015.
Compare [Custom element](guide/glossary#custom-element).
{@a F}
@ -383,7 +378,7 @@ Short hand for [ECMAScript](guide/glossary#ecmascript) 2015.
An object in the Angular [dependency-injection system](guide/glossary#dependency-injection)
that can find a named dependency in its cache or create a dependency
with a registered [provider](guide/glossary#provider).
with a registered [provider](guide/glossary#provider). Injectors are created for NgModules automatically as part of the bootstrap process, and inherited through the component hierarchy.
## Input
@ -411,13 +406,17 @@ or displayed between element tags, as in this example.
</code-example>
Read more about [interpolation](guide/template-syntax#interpolation) in the
[Template Syntax](guide/template-syntax) page.
{@a J}
## JavaScript
See [ECMAScript](guide/glossary#ecma), [TypeScript](guide/glossary#typescript).
{@a jit}
@ -430,10 +429,6 @@ Consider using the [ahead-of-time](guide/glossary#aot) mode for production apps.
{@a K}
## kebab-case
See [dash-case](guide/glossary#dash-case).
{@a L}
@ -477,11 +472,8 @@ For details and examples, see the [NgModules](guide/ngmodules) page.
For a comparison, see [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
</div>
A cohesive block of code dedicated to a single purpose.
Angular apps are modular.
@ -522,18 +514,19 @@ For details and examples, see [NgModules](guide/ngmodules) and the
related files in that section.
{@a O}
## Observable
An array whose items arrive asynchronously over time.
An subscribable message publisher, which provides multiple items that arrive asynchronously over time.
Observables help you manage asynchronous data, such as data coming from a backend service.
Observables are used within Angular itself, including Angular's event system and its HTTP client service.
To use observables, Angular uses a third-party library called Reactive Extensions (RxJS).
Observables are a proposed feature for ES2016, the next version of JavaScript.
Currently, Angular depends on a third-party library called Reactive Extensions (RxJS) to provide observables.
For more information, see the [Observables guide](guide/observables).
## Output
@ -549,15 +542,6 @@ See the [Input and output properties](guide/template-syntax#inputs-outputs) sect
{@a P}
## PascalCase
The practice of writing individual words, compound words, or phrases such that each word or abbreviation begins with a capital letter.
Class names are typically spelled in PascalCase. For example, `Person` and `HeroDetailComponent`.
This form is also known as *upper camel case* to distinguish it from *lower camel case* or simply [camelCase](guide/glossary#camelcase).
In this documentation, "PascalCase" means *upper camel case* and "camelCase" means *lower camel case*.
## Pipe
An Angular pipe is a function that transforms input values to output values for
@ -676,15 +660,6 @@ Applications often require services such as a data service or a logging service.
For more information, see the [Services](tutorial/toh-pt4) page of the [Tour of Heroes](tutorial) tutorial.
{@a snake-case}
## snake_case
The practice of writing compound words or phrases such that an
underscore (`_`) separates one word from the next. This form is also known as *underscore case*.
{@a structural-directive}
@ -740,23 +715,22 @@ of the [Template Syntax](guide/template-syntax) page.
## Transpile
The process of transforming code written in one form of JavaScript
(such as TypeScript) into another form of JavaScript (such as [ES5](guide/glossary#es5)).
(such as TypeScript) into another form of JavaScript. (See also [ECMAScript](guide/glossary#ecma)).
{@a typescript}
## TypeScript
A version of JavaScript that supports most [ECMAScript 2015](guide/glossary#es2015)
A version of JavaScript that supports most [ECMAScript 2015](guide/glossary#ecma)
language features such as [decorators](guide/glossary#decorator).
TypeScript is also notable for its optional typing system, which provides
TypeScript is notable for its optional typing system, which provides
compile-time type checking and strong tooling support (such as "intellisense,"
code completion, refactoring, and intelligent search). Many code editors
and IDEs support TypeScript either natively or with plugins.
TypeScript is the preferred language for Angular development, although
you can use other JavaScript dialects such as [ES5](guide/glossary#es5).
Read more about TypeScript at [typescriptlang.org](http://www.typescriptlang.org/).
TypeScript is the preferred language for Angular development. Read more about TypeScript at [typescriptlang.org](http://www.typescriptlang.org/).
{@a U}
@ -780,6 +754,10 @@ under the control of a [router](guide/glossary#router).
{@a W}
## Web component
See [Custom element](guide/glossary#custom-element)
{@a X}

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

@ -184,6 +184,11 @@
"title": "Component Styles",
"tooltip": "Add CSS styles that are specific to a component."
},
{
"url": "guide/elements",
"title": "Custom Elements",
"tooltip": "Convert components to custom elements."
},
{
"url": "guide/dynamic-component-loader",
"title": "Dynamic Components",

View File

@ -14,33 +14,66 @@ import {NgElementStrategy, NgElementStrategyFactory} from './element-strategy';
import {createCustomEvent, getComponentInputs, getDefaultAttributeToPropertyInputs} from './utils';
/**
* Class constructor based on an Angular Component to be used for custom element registration.
* Prototype for a class constructor based on an Angular component
* that can be used for custom element registration. Implemented and returned
* by the {@link createCustomElement createCustomElement() function}.
*
* @experimental
*/
export interface NgElementConstructor<P> {
/**
* An array of observed attribute names for the custom element,
* derived by transforming input property names from the source component.
*/
readonly observedAttributes: string[];
/**
* Initializes a constructor instance.
* @param injector The source component's injector.
*/
new (injector: Injector): NgElement&WithProperties<P>;
}
/**
* Class that extends HTMLElement and implements the functionality needed for a custom element.
* Implements the functionality needed for a custom element.
*
* @experimental
*/
export abstract class NgElement extends HTMLElement {
/**
* The strategy that controls how a component is transformed in a custom element.
*/
protected ngElementStrategy: NgElementStrategy;
/**
* A subscription to change, connect, and disconnect events in the custom element.
*/
protected ngElementEventsSubscription: Subscription|null = null;
/**
* Prototype for a handler that responds to a change in an observed attribute.
* @param attrName The name of the attribute that has changed.
* @param oldValue The previous value of the attribute.
* @param newValue The new value of the attribute.
* @param namespace The namespace in which the attribute is defined.
* @returns Nothing.
*/
abstract attributeChangedCallback(
attrName: string, oldValue: string|null, newValue: string, namespace?: string): void;
/**
* Prototype for a handler that responds to the insertion of the custom element in the DOM.
* @returns Nothing.
*/
abstract connectedCallback(): void;
/**
* Prototype for a handler that responds to the deletion of the custom element from the DOM.
* @returns Nothing.
*/
abstract disconnectedCallback(): void;
}
/**
* Additional type information that can be added to the NgElement class for properties added based
* Additional type information that can be added to the NgElement class,
* for properties that are added based
* on the inputs and methods of the underlying component.
*
* @experimental
@ -50,28 +83,41 @@ export type WithProperties<P> = {
};
/**
* Initialization configuration for the NgElementConstructor which contains the injector to be used
* for retrieving the component's factory as well as the default context for the component. May
* provide a custom strategy factory to be used instead of the default.
* A configuration that initializes an NgElementConstructor with the
* dependencies and strategy it needs to transform a component into
* a custom element class.
*
* @experimental
*/
export interface NgElementConfig {
/**
* The injector to use for retrieving the component's factory.
*/
injector: Injector;
/**
* An optional custom strategy factory to use instead of the default.
* The strategy controls how the tranformation is performed.
*/
strategyFactory?: NgElementStrategyFactory;
}
/**
* @whatItDoes Creates a custom element class based on an Angular Component. Takes a configuration
* that provides initialization information to the created class. E.g. the configuration's injector
* will be the initial injector set on the class which will be used for each created instance.
* @description Creates a custom element class based on an Angular component.
*
* @description Builds a class that encapsulates the functionality of the provided component and
* uses the config's information to provide more context to the class. Takes the component factory's
* inputs and outputs to convert them to the proper custom element API and add hooks to input
* changes. Passes the config's injector to each created instance (may be overridden with the
* Builds a class that encapsulates the functionality of the provided component and
* uses the configuration information to provide more context to the class.
* Takes the component factory's inputs and outputs to convert them to the proper
* custom element API and add hooks to input changes.
*
* The configuration's injector is the initial injector set on the class,
* and used by default for each created instance.This behavior can be overridden with the
* static property to affect all newly created instances, or as a constructor argument for
* one-off creations).
* one-off creations.
*
* @param component The component to transform.
* @param config A configuration that provides initialization information to the created class.
* @returns The custom-element construction class, which can be registered with
* a browser's `CustomElementRegistry`.
*
* @experimental
*/
@ -130,4 +176,4 @@ export function createCustomElement<P>(
});
return (NgElementImpl as any) as NgElementConstructor<P>;
}
}