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);
}
}