1383 lines
43 KiB
HTML

<html lang="en"><head></head><body>
<form id="mainForm" method="post" action="https://run.stackblitz.com/api/angular/v1?file=src/app/app.component.html" target="_self"><input type="hidden" name="files[src/app/after-content-parent.component.ts]" value="import { Component } from '@angular/core';
import { LoggerService } from './logger.service';
@Component({
selector: 'after-content-parent',
template: `
<div class=&quot;parent&quot;>
<h2>AfterContent</h2>
<div *ngIf=&quot;show&quot;>` +
`<after-content>
<app-child></app-child>
</after-content>`
+ `</div>
<h4>-- AfterContent Logs --</h4>
<p><button (click)=&quot;reset()&quot;>Reset</button></p>
<div *ngFor=&quot;let msg of logger.logs&quot;>{{msg}}</div>
</div>
`,
styles: ['.parent {background: burlywood}'],
providers: [LoggerService]
})
export class AfterContentParentComponent {
show = true;
constructor(public logger: LoggerService) { }
reset() {
this.logger.clear();
// quickly remove and reload AfterContentComponent which recreates it
this.show = false;
this.logger.tick_then(() => this.show = true);
}
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/after-content.component.ts]" value="import { AfterContentChecked, AfterContentInit, Component, ContentChild } from '@angular/core';
import { ChildComponent } from './child.component';
import { LoggerService } from './logger.service';
@Component({
selector: 'after-content',
template: `
<div>-- projected content begins --</div>
<ng-content></ng-content>
<div>-- projected content ends --</div>`
+ `
<p *ngIf=&quot;comment&quot; class=&quot;comment&quot;>
{{comment}}
</p>
`
})
export class AfterContentComponent implements AfterContentChecked, AfterContentInit {
private prevHero = '';
comment = '';
// Query for a CONTENT child of type `ChildComponent`
@ContentChild(ChildComponent) contentChild: ChildComponent;
constructor(private logger: LoggerService) {
this.logIt('AfterContent constructor');
}
ngAfterContentInit() {
// contentChild is set after the content has been initialized
this.logIt('AfterContentInit');
this.doSomething();
}
ngAfterContentChecked() {
// contentChild is updated after the content has been checked
if (this.prevHero === this.contentChild.hero) {
this.logIt('AfterContentChecked (no change)');
} else {
this.prevHero = this.contentChild.hero;
this.logIt('AfterContentChecked');
this.doSomething();
}
}
// This surrogate for real business logic sets the `comment`
private doSomething() {
this.comment = this.contentChild.hero.length > 10 ? `That's a long name` : '';
}
private logIt(method: string) {
const child = this.contentChild;
const message = `${method}: ${child ? child.hero : 'no'} child content`;
this.logger.log(message);
}
// ...
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/after-view-parent.component.ts]" value="import { Component } from '@angular/core';
import { LoggerService } from './logger.service';
@Component({
selector: 'after-view-parent',
template: `
<div class=&quot;parent&quot;>
<h2>AfterView</h2>
<after-view *ngIf=&quot;show&quot;></after-view>
<h4>-- AfterView Logs --</h4>
<p><button (click)=&quot;reset()&quot;>Reset</button></p>
<div *ngFor=&quot;let msg of logger.logs&quot;>{{msg}}</div>
</div>
`,
styles: ['.parent {background: burlywood}'],
providers: [LoggerService]
})
export class AfterViewParentComponent {
show = true;
constructor(public logger: LoggerService) { }
reset() {
this.logger.clear();
// quickly remove and reload AfterViewComponent which recreates it
this.show = false;
this.logger.tick_then(() => this.show = true);
}
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/after-view.component.ts]" value="import { AfterViewChecked, AfterViewInit, Component, ViewChild } from '@angular/core';
import { ChildViewComponent } from './child-view.component';
import { LoggerService } from './logger.service';
@Component({
selector: 'after-view',
template: `
<div>-- child view begins --</div>
<app-child-view></app-child-view>
<div>-- child view ends --</div>`
+ `
<p *ngIf=&quot;comment&quot; class=&quot;comment&quot;>
{{comment}}
</p>
`
})
export class AfterViewComponent implements AfterViewChecked, AfterViewInit {
comment = '';
private prevHero = '';
// Query for a VIEW child of type `ChildViewComponent`
@ViewChild(ChildViewComponent) viewChild: ChildViewComponent;
constructor(private logger: LoggerService) {
this.logIt('AfterView constructor');
}
ngAfterViewInit() {
// viewChild is set after the view has been initialized
this.logIt('AfterViewInit');
this.doSomething();
}
ngAfterViewChecked() {
// viewChild is updated after the view has been checked
if (this.prevHero === this.viewChild.hero) {
this.logIt('AfterViewChecked (no change)');
} else {
this.prevHero = this.viewChild.hero;
this.logIt('AfterViewChecked');
this.doSomething();
}
}
// This surrogate for real business logic sets the `comment`
private doSomething() {
const c = this.viewChild.hero.length > 10 ? `That's a long name` : '';
if (c !== this.comment) {
// Wait a tick because the component's view has already been checked
this.logger.tick_then(() => this.comment = c);
}
}
private logIt(method: string) {
const child = this.viewChild;
const message = `${method}: ${child ? child.hero : 'no'} child view`;
this.logger.log(message);
}
// ...
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/app.component.ts]" value="import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent { }
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/app.module.ts]" value="import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { AfterContentParentComponent } from './after-content-parent.component';
import { AfterContentComponent } from './after-content.component';
import { ChildComponent } from './child.component';
import { AfterViewParentComponent } from './after-view-parent.component';
import { AfterViewComponent } from './after-view.component';
import { ChildViewComponent } from './child-view.component';
import { CounterParentComponent } from './counter-parent.component';
import { MyCounterComponent } from './counter.component';
import { DoCheckParentComponent } from './do-check-parent.component';
import { DoCheckComponent } from './do-check.component';
import { OnChangesParentComponent } from './on-changes-parent.component';
import { OnChangesComponent } from './on-changes.component';
import { PeekABooParentComponent } from './peek-a-boo-parent.component';
import { PeekABooComponent } from './peek-a-boo.component';
import { SpyParentComponent } from './spy.component';
import { SpyDirective } from './spy.directive';
@NgModule({
imports: [
BrowserModule,
FormsModule
],
declarations: [
AppComponent,
AfterContentParentComponent,
AfterContentComponent,
ChildComponent,
AfterViewParentComponent,
AfterViewComponent,
ChildViewComponent,
CounterParentComponent,
MyCounterComponent,
DoCheckParentComponent,
DoCheckComponent,
OnChangesParentComponent,
OnChangesComponent,
PeekABooParentComponent,
PeekABooComponent,
SpyParentComponent,
SpyDirective
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/child-view.component.ts]" value="import { Component } from '@angular/core';
@Component({
selector: 'app-child-view',
template: '<input [(ngModel)]=&quot;hero&quot;>'
})
export class ChildViewComponent {
hero = 'Magneta';
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/child.component.ts]" value="import { Component } from '@angular/core';
@Component({
selector: 'app-child',
template: '<input [(ngModel)]=&quot;hero&quot;>'
})
export class ChildComponent {
hero = 'Magneta';
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/counter-parent.component.ts]" value="import { Component } from '@angular/core';
import { LoggerService } from './logger.service';
@Component({
selector: 'counter-parent',
template: `
<div class=&quot;parent&quot;>
<h2>Counter Spy</h2>
<button (click)=&quot;updateCounter()&quot;>Update counter</button>
<button (click)=&quot;reset()&quot;>Reset Counter</button>
<app-counter [counter]=&quot;value&quot;></app-counter>
<h4>-- Spy Lifecycle Hook Log --</h4>
<div *ngFor=&quot;let msg of spyLog&quot;>{{msg}}</div>
</div>
`,
styles: ['.parent {background: gold;}'],
providers: [LoggerService]
})
export class CounterParentComponent {
value: number;
spyLog: string[] = [];
private logger: LoggerService;
constructor(logger: LoggerService) {
this.logger = logger;
this.spyLog = logger.logs;
this.reset();
}
updateCounter() {
this.value += 1;
this.logger.tick();
}
reset() {
this.logger.log('-- reset --');
this.value = 0;
this.logger.tick();
}
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/counter.component.ts]" value="import {
Component, Input,
OnChanges, SimpleChanges,
} from '@angular/core';
@Component({
selector: 'app-counter',
template: `
<div class=&quot;counter&quot;>
Counter = {{counter}}
<h5>-- Counter Change Log --</h5>
<div *ngFor=&quot;let chg of changeLog&quot; appSpy>{{chg}}</div>
</div>
`,
styles: ['.counter {background: LightYellow; padding: 8px; margin-top: 8px}']
})
export class MyCounterComponent implements OnChanges {
@Input() counter: number;
changeLog: string[] = [];
ngOnChanges(changes: SimpleChanges) {
// Empty the changeLog whenever counter goes to zero
// hint: this is a way to respond programmatically to external value changes.
if (this.counter === 0) {
this.changeLog = [];
}
// A change to `counter` is the only change we care about
const chng = changes.counter;
const cur = chng.currentValue;
const prev = JSON.stringify(chng.previousValue); // first time is {}; after is integer
this.changeLog.push(`counter: currentValue = ${cur}, previousValue = ${prev}`);
}
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/do-check-parent.component.ts]" value="import { Component, ViewChild } from '@angular/core';
import { DoCheckComponent } from './do-check.component';
import { Hero } from './hero';
@Component({
selector: 'do-check-parent',
templateUrl: './do-check-parent.component.html',
styles: ['.parent {background: Lavender}']
})
export class DoCheckParentComponent {
hero: Hero;
power: string;
title = 'DoCheck';
@ViewChild(DoCheckComponent) childView: DoCheckComponent;
constructor() {
this.reset();
}
reset() {
this.hero = new Hero('Windstorm');
this.power = 'sing';
if (this.childView) {
this.childView.reset();
}
}
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/do-check.component.ts]" value="/* tslint:disable:forin */
import { Component, DoCheck, Input } from '@angular/core';
import { Hero } from './hero';
@Component({
selector: 'do-check',
template: `
<div class=&quot;hero&quot;>
<p>{{hero.name}} can {{power}}</p>
<h4>-- Change Log --</h4>
<div *ngFor=&quot;let chg of changeLog&quot;>{{chg}}</div>
</div>
`,
styles: [
'.hero {background: LightYellow; padding: 8px; margin-top: 8px}',
'p {background: Yellow; padding: 8px; margin-top: 8px}'
]
})
export class DoCheckComponent implements DoCheck {
@Input() hero: Hero;
@Input() power: string;
changeDetected = false;
changeLog: string[] = [];
oldHeroName = '';
oldPower = '';
oldLogLength = 0;
noChangeCount = 0;
ngDoCheck() {
if (this.hero.name !== this.oldHeroName) {
this.changeDetected = true;
this.changeLog.push(`DoCheck: Hero name changed to &quot;${this.hero.name}&quot; from &quot;${this.oldHeroName}&quot;`);
this.oldHeroName = this.hero.name;
}
if (this.power !== this.oldPower) {
this.changeDetected = true;
this.changeLog.push(`DoCheck: Power changed to &quot;${this.power}&quot; from &quot;${this.oldPower}&quot;`);
this.oldPower = this.power;
}
if (this.changeDetected) {
this.noChangeCount = 0;
} else {
// log that hook was called when there was no relevant change.
const count = this.noChangeCount += 1;
const noChangeMsg = `DoCheck called ${count}x when no change to hero or power`;
if (count === 1) {
// add new &quot;no change&quot; message
this.changeLog.push(noChangeMsg);
} else {
// update last &quot;no change&quot; message
this.changeLog[this.changeLog.length - 1] = noChangeMsg;
}
}
this.changeDetected = false;
}
reset() {
this.changeDetected = true;
this.changeLog = [];
}
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/hero.ts]" value="export class Hero {
constructor(public name: string) { }
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/logger.service.ts]" value="import { Injectable } from '@angular/core';
@Injectable()
export class LoggerService {
logs: string[] = [];
prevMsg = '';
prevMsgCount = 1;
log(msg: string) {
if (msg === this.prevMsg) {
// Repeat message; update last log entry with count.
this.logs[this.logs.length - 1] = msg + ` (${this.prevMsgCount += 1}x)`;
} else {
// New message; log it.
this.prevMsg = msg;
this.prevMsgCount = 1;
this.logs.push(msg);
}
}
clear() { this.logs = []; }
// schedules a view refresh to ensure display catches up
tick() { this.tick_then(() => { }); }
tick_then(fn: () => any) { setTimeout(fn, 0); }
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/on-changes-parent.component.ts]" value="import { Component, ViewChild } from '@angular/core';
import { Hero } from './hero';
import { OnChangesComponent } from './on-changes.component';
@Component({
selector: 'on-changes-parent',
templateUrl: './on-changes-parent.component.html',
styles: ['.parent {background: Lavender;}']
})
export class OnChangesParentComponent {
hero: Hero;
power: string;
title = 'OnChanges';
@ViewChild(OnChangesComponent) childView: OnChangesComponent;
constructor() {
this.reset();
}
reset() {
// new Hero object every time; triggers onChanges
this.hero = new Hero('Windstorm');
// setting power only triggers onChanges if this value is different
this.power = 'sing';
if (this.childView) {
this.childView.reset();
}
}
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/on-changes.component.ts]" value="/* tslint:disable:forin */
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import { Hero } from './hero';
@Component({
selector: 'on-changes',
template: `
<div class=&quot;hero&quot;>
<p>{{hero.name}} can {{power}}</p>
<h4>-- Change Log --</h4>
<div *ngFor=&quot;let chg of changeLog&quot;>{{chg}}</div>
</div>
`,
styles: [
'.hero {background: LightYellow; padding: 8px; margin-top: 8px}',
'p {background: Yellow; padding: 8px; margin-top: 8px}'
]
})
export class OnChangesComponent implements OnChanges {
@Input() hero: Hero;
@Input() power: string;
changeLog: string[] = [];
ngOnChanges(changes: SimpleChanges) {
for (const propName in changes) {
const chng = changes[propName];
const cur = JSON.stringify(chng.currentValue);
const prev = JSON.stringify(chng.previousValue);
this.changeLog.push(`${propName}: currentValue = ${cur}, previousValue = ${prev}`);
}
}
reset() { this.changeLog = []; }
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/peek-a-boo-parent.component.ts]" value="import { Component } from '@angular/core';
import { LoggerService } from './logger.service';
@Component({
selector: 'peek-a-boo-parent',
template: `
<div class=&quot;parent&quot;>
<h2>Peek-A-Boo</h2>
<button (click)=&quot;toggleChild()&quot;>
{{hasChild ? 'Destroy' : 'Create'}} PeekABooComponent
</button>
<button (click)=&quot;updateHero()&quot; [hidden]=&quot;!hasChild&quot;>Update Hero</button>
<peek-a-boo *ngIf=&quot;hasChild&quot; [name]=&quot;heroName&quot;>
</peek-a-boo>
<h4>-- Lifecycle Hook Log --</h4>
<div *ngFor=&quot;let msg of hookLog&quot;>{{msg}}</div>
</div>
`,
styles: ['.parent {background: moccasin}'],
providers: [ LoggerService ]
})
export class PeekABooParentComponent {
hasChild = false;
hookLog: string[];
heroName = 'Windstorm';
private logger: LoggerService;
constructor(logger: LoggerService) {
this.logger = logger;
this.hookLog = logger.logs;
}
toggleChild() {
this.hasChild = !this.hasChild;
if (this.hasChild) {
this.heroName = 'Windstorm';
this.logger.clear(); // clear log on create
}
this.hookLog = this.logger.logs;
this.logger.tick();
}
updateHero() {
this.heroName += '!';
this.logger.tick();
}
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/peek-a-boo.component.ts]" value="// tslint:disable: no-conflicting-lifecycle
import {
AfterContentChecked,
AfterContentInit,
AfterViewChecked,
AfterViewInit,
Component,
DoCheck,
Input,
OnChanges,
OnDestroy,
OnInit,
SimpleChanges
} from '@angular/core';
import { LoggerService } from './logger.service';
import { PeekABooDirective } from './peek-a-boo.directive';
@Component({
selector: 'peek-a-boo',
template: '<p>Now you see my hero, {{name}}</p>',
styles: ['p {background: LightYellow; padding: 8px}']
})
// Don't HAVE to mention the Lifecycle Hook interfaces
// unless we want typing and tool support.
export class PeekABooComponent extends PeekABooDirective implements
OnChanges, OnInit, DoCheck,
AfterContentInit, AfterContentChecked,
AfterViewInit, AfterViewChecked,
OnDestroy {
@Input() name: string;
private verb = 'initialized';
constructor(logger: LoggerService) {
super(logger);
const is = this.name ? 'is' : 'is not';
this.logIt(`name ${is} known at construction`);
}
// only called for/if there is an @input variable set by parent.
ngOnChanges(changes: SimpleChanges) {
const changesMsgs: string[] = [];
for (const propName in changes) {
if (propName === 'name') {
const name = changes.name.currentValue;
changesMsgs.push(`name ${this.verb} to &quot;${name}&quot;`);
} else {
changesMsgs.push(propName + ' ' + this.verb);
}
}
this.logIt(`OnChanges: ${changesMsgs.join('; ')}`);
this.verb = 'changed'; // next time it will be a change
}
// Beware! Called frequently!
// Called in every change detection cycle anywhere on the page
ngDoCheck() { this.logIt(`DoCheck`); }
ngAfterContentInit() { this.logIt(`AfterContentInit`); }
// Beware! Called frequently!
// Called in every change detection cycle anywhere on the page
ngAfterContentChecked() { this.logIt(`AfterContentChecked`); }
ngAfterViewInit() { this.logIt(`AfterViewInit`); }
// Beware! Called frequently!
// Called in every change detection cycle anywhere on the page
ngAfterViewChecked() { this.logIt(`AfterViewChecked`); }
ngOnDestroy() { this.logIt(`OnDestroy`); }
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/peek-a-boo.directive.ts]" value="import { Directive, OnInit } from '@angular/core';
import { LoggerService } from './logger.service';
let nextId = 1;
@Directive()
export class PeekABooDirective implements OnInit {
constructor(private logger: LoggerService) { }
// implement OnInit's `ngOnInit` method
ngOnInit() {
this.logIt(`OnInit`);
}
logIt(msg: string) {
this.logger.log(`#${nextId++} ${msg}`);
}
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/spy.component.ts]" value="import { Component } from '@angular/core';
import { LoggerService } from './logger.service';
@Component({
selector: 'spy-parent',
templateUrl: './spy.component.html',
styles: [
'.parent {background: khaki;}',
'.heroes {background: LightYellow; padding: 0 8px}'
],
providers: [LoggerService]
})
export class SpyParentComponent {
newName = 'Herbie';
heroes: string[] = ['Windstorm', 'Magneta'];
constructor(public logger: LoggerService) {
}
addHero() {
if (this.newName.trim()) {
this.heroes.push(this.newName.trim());
this.newName = '';
this.logger.tick();
}
}
removeHero(hero: string) {
this.heroes.splice(this.heroes.indexOf(hero), 1);
this.logger.tick();
}
reset() {
this.logger.log('-- reset --');
this.heroes = [];
this.logger.tick();
}
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/spy.directive.ts]" value="import { Directive, OnInit, OnDestroy } from '@angular/core';
import { LoggerService } from './logger.service';
let nextId = 1;
// Spy on any element to which it is applied.
// Usage: <div appSpy>...</div>
@Directive({selector: '[appSpy]'})
export class SpyDirective implements OnInit, OnDestroy {
private id = nextId++;
constructor(private logger: LoggerService) { }
ngOnInit() {
this.logger.log(`Spy #${this.id} onInit`);
}
ngOnDestroy() {
this.logger.log(`Spy #${this.id} onDestroy`);
}
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/environments/environment.prod.ts]" value="export const environment = {
production: true
};
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/environments/environment.ts]" value="// This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false
};
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
*
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/main.ts]" value="import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/polyfills.ts]" value="/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called &quot;evergreen&quot; browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/guide/browser-support
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/** IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/**
* Web Animations `@angular/platform-browser/animations`
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
*/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
* because those flags need to be set before `zone.js` being loaded, and webpack
* will put import in the top of bundle, so user need to create a separate file
* in this directory (for example: zone-flags.ts), and put the following flags
* into that file, and then add the following code before importing zone.js.
* import './zone-flags';
*
* The flags allowed in zone-flags.ts are listed here.
*
* The following flags will work for all browsers.
*
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch
* requestAnimationFrame
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch
* specified eventNames
*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*
* (window as any).__Zone_enable_cross_context_check = true;
*
*/
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/assets/sample.css]" value=".parent {
color: #666;
margin: 14px 0;
padding: 8px;
}
input {
margin: 4px;
padding: 4px;
}
.comment {
color: red;
font-style: italic;
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/styles.css]" value="/* Global Styles */
* {
font-family: Arial, Helvetica, sans-serif;
}
h1 {
color: #264D73;
font-size: 2.5rem;
}
h2, h3 {
color: #444;
font-weight: lighter;
}
h3 {
font-size: 1.3rem;
}
body {
padding: .5rem;
max-width: 1000px;
margin: auto;
}
@media (min-width: 600px) {
body {
padding: 2rem;
}
}
body, input[text] {
color: #333;
font-family: Cambria, Georgia, serif;
}
a {
cursor: pointer;
}
button {
background-color: #eee;
border: none;
border-radius: 4px;
cursor: pointer;
color: black;
font-size: 1.2rem;
padding: 1rem;
margin-right: 1rem;
margin-bottom: 1rem;
}
button:hover {
background-color: black;
color: white;
}
button:disabled {
background-color: #eee;
color: #aaa;
cursor: auto;
}
/* Navigation link styles */
nav a {
padding: 5px 10px;
text-decoration: none;
margin-right: 10px;
margin-top: 10px;
display: inline-block;
background-color: #e8e8e8;
color: #3d3d3d;
border-radius: 4px;
}
nav a:hover {
color: white;
background-color: #42545C;
}
nav a.active {
background-color: black;
color: white;
}
hr {
margin: 1.5rem 0;
}
input[type=&quot;text&quot;] {
box-sizing: border-box;
width: 100%;
padding: .5rem;
}
/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
*/"><input type="hidden" name="files[src/app/app.component.html]" value="<a id=&quot;top&quot;></a>
<h1>Component Lifecycle Hooks</h1>
<a href=&quot;#hooks&quot;>Peek-a-boo: (most) lifecycle hooks</a><br>
<a href=&quot;#spy&quot;>Spy: directive with OnInit &amp; OnDestroy</a><br>
<a href=&quot;#onchanges&quot;>OnChanges</a><br>
<a href=&quot;#docheck&quot;>DoCheck</a><br>
<a href=&quot;#after-view&quot;>AfterViewInit &amp; AfterViewChecked</a><br>
<a href=&quot;#after-content&quot;>AfterContentInit &amp; AfterContentChecked</a><br>
<a href=&quot;#counter&quot;>Counter: OnChanges + Spy directive</a><br>
<a id=&quot;hooks&quot;></a>
<peek-a-boo-parent></peek-a-boo-parent>
<a href=&quot;#top&quot;>back to top</a>
<a id=&quot;spy&quot;></a>
<spy-parent></spy-parent>
<a href=&quot;#top&quot;>back to top</a>
<a id=&quot;onchanges&quot;></a>
<on-changes-parent></on-changes-parent>
<a href=&quot;#top&quot;>back to top</a>
<a id=&quot;docheck&quot;></a>
<do-check-parent></do-check-parent>
<a href=&quot;#top&quot;>back to top</a>
<a id=&quot;after-view&quot;></a>
<after-view-parent></after-view-parent>
<a href=&quot;#top&quot;>back to top</a>
<a id=&quot;after-content&quot;></a>
<after-content-parent></after-content-parent>
<a href=&quot;#top&quot;>back to top</a>
<a id=&quot;counter&quot;></a>
<counter-parent></counter-parent>
<a href=&quot;#top&quot;>back to top</a>
<!--
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
-->"><input type="hidden" name="files[src/app/do-check-parent.component.html]" value="<div class=&quot;parent&quot;>
<h2>{{title}}</h2>
<table>
<tr><td>Power: </td><td><input [(ngModel)]=&quot;power&quot;></td></tr>
<tr><td>Hero.name: </td><td><input [(ngModel)]=&quot;hero.name&quot;></td></tr>
</table>
<p><button (click)=&quot;reset()&quot;>Reset Log</button></p>
<do-check [hero]=&quot;hero&quot; [power]=&quot;power&quot;></do-check>
</div>
<!--
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
-->"><input type="hidden" name="files[src/app/on-changes-parent.component.html]" value="<div class=&quot;parent&quot;>
<h2>{{title}}</h2>
<table>
<tr><td>Power: </td><td><input [(ngModel)]=&quot;power&quot;></td></tr>
<tr><td>Hero.name: </td><td><input [(ngModel)]=&quot;hero.name&quot;></td></tr>
</table>
<p><button (click)=&quot;reset()&quot;>Reset Log</button></p>
<on-changes [hero]=&quot;hero&quot; [power]=&quot;power&quot;></on-changes>
</div>
<!--
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
-->"><input type="hidden" name="files[src/app/spy.component.html]" value="<div class=&quot;parent&quot;>
<h2>Spy Directive</h2>
<input [(ngModel)]=&quot;newName&quot; (keyup.enter)=&quot;addHero()&quot;>
<button (click)=&quot;addHero()&quot;>Add Hero</button>
<button (click)=&quot;reset()&quot;>Reset Heroes</button>
<p></p>
<div *ngFor=&quot;let hero of heroes&quot; appSpy class=&quot;heroes&quot;>
{{hero}}
</div>
<h4>-- Spy Lifecycle Hook Log --</h4>
<div *ngFor=&quot;let msg of logger.logs&quot;>{{msg}}</div>
</div>
<!--
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
-->"><input type="hidden" name="files[src/index.html]" value="<!DOCTYPE html>
<html lang=&quot;en&quot;>
<head>
<title>Angular Lifecycle Hooks</title>
<base href=&quot;/&quot;>
<meta charset=&quot;UTF-8&quot;>
<meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;>
<link rel=&quot;stylesheet&quot; href=&quot;assets/sample.css&quot;>
</head>
<body>
<app-root></app-root>
</body>
</html>
<!--
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://angular.io/license
-->"><input type="hidden" name="files[angular.json]" value="{
&quot;$schema&quot;: &quot;./node_modules/@angular/cli/lib/config/schema.json&quot;,
&quot;version&quot;: 1,
&quot;newProjectRoot&quot;: &quot;projects&quot;,
&quot;projects&quot;: {
&quot;angular.io-example&quot;: {
&quot;projectType&quot;: &quot;application&quot;,
&quot;schematics&quot;: {
&quot;@schematics/angular:application&quot;: {
&quot;strict&quot;: true
}
},
&quot;root&quot;: &quot;&quot;,
&quot;sourceRoot&quot;: &quot;src&quot;,
&quot;prefix&quot;: &quot;app&quot;,
&quot;architect&quot;: {
&quot;build&quot;: {
&quot;builder&quot;: &quot;@angular-devkit/build-angular:browser&quot;,
&quot;options&quot;: {
&quot;outputPath&quot;: &quot;dist&quot;,
&quot;index&quot;: &quot;src/index.html&quot;,
&quot;main&quot;: &quot;src/main.ts&quot;,
&quot;polyfills&quot;: &quot;src/polyfills.ts&quot;,
&quot;tsConfig&quot;: &quot;tsconfig.app.json&quot;,
&quot;aot&quot;: true,
&quot;assets&quot;: [
&quot;src/favicon.ico&quot;,
&quot;src/assets&quot;
],
&quot;styles&quot;: [
&quot;src/styles.css&quot;
],
&quot;scripts&quot;: []
},
&quot;configurations&quot;: {
&quot;production&quot;: {
&quot;fileReplacements&quot;: [
{
&quot;replace&quot;: &quot;src/environments/environment.ts&quot;,
&quot;with&quot;: &quot;src/environments/environment.prod.ts&quot;
}
],
&quot;optimization&quot;: true,
&quot;outputHashing&quot;: &quot;all&quot;,
&quot;sourceMap&quot;: false,
&quot;namedChunks&quot;: false,
&quot;extractLicenses&quot;: true,
&quot;vendorChunk&quot;: false,
&quot;buildOptimizer&quot;: true,
&quot;budgets&quot;: [
{
&quot;type&quot;: &quot;initial&quot;,
&quot;maximumWarning&quot;: &quot;500kb&quot;,
&quot;maximumError&quot;: &quot;1mb&quot;
},
{
&quot;type&quot;: &quot;anyComponentStyle&quot;,
&quot;maximumWarning&quot;: &quot;2kb&quot;,
&quot;maximumError&quot;: &quot;4kb&quot;
}
]
}
}
},
&quot;serve&quot;: {
&quot;builder&quot;: &quot;@angular-devkit/build-angular:dev-server&quot;,
&quot;options&quot;: {
&quot;browserTarget&quot;: &quot;angular.io-example:build&quot;
},
&quot;configurations&quot;: {
&quot;production&quot;: {
&quot;browserTarget&quot;: &quot;angular.io-example:build:production&quot;
}
}
},
&quot;extract-i18n&quot;: {
&quot;builder&quot;: &quot;@angular-devkit/build-angular:extract-i18n&quot;,
&quot;options&quot;: {
&quot;browserTarget&quot;: &quot;angular.io-example:build&quot;
}
},
&quot;test&quot;: {
&quot;builder&quot;: &quot;@angular-devkit/build-angular:karma&quot;,
&quot;options&quot;: {
&quot;main&quot;: &quot;src/test.ts&quot;,
&quot;polyfills&quot;: &quot;src/polyfills.ts&quot;,
&quot;tsConfig&quot;: &quot;tsconfig.spec.json&quot;,
&quot;karmaConfig&quot;: &quot;karma.conf.js&quot;,
&quot;assets&quot;: [
&quot;src/favicon.ico&quot;,
&quot;src/assets&quot;
],
&quot;styles&quot;: [
&quot;src/styles.css&quot;
],
&quot;scripts&quot;: []
}
},
&quot;lint&quot;: {
&quot;builder&quot;: &quot;@angular-devkit/build-angular:tslint&quot;,
&quot;options&quot;: {
&quot;tsConfig&quot;: [
&quot;tsconfig.app.json&quot;,
&quot;tsconfig.spec.json&quot;,
&quot;e2e/tsconfig.json&quot;
],
&quot;exclude&quot;: [
&quot;**/node_modules/**&quot;
]
}
},
&quot;e2e&quot;: {
&quot;builder&quot;: &quot;@angular-devkit/build-angular:protractor&quot;,
&quot;options&quot;: {
&quot;protractorConfig&quot;: &quot;e2e/protractor.conf.js&quot;,
&quot;devServerTarget&quot;: &quot;angular.io-example:serve&quot;
},
&quot;configurations&quot;: {
&quot;production&quot;: {
&quot;devServerTarget&quot;: &quot;angular.io-example:serve:production&quot;
}
}
}
}
}
},
&quot;defaultProject&quot;: &quot;angular.io-example&quot;
}
"><input type="hidden" name="files[tsconfig.json]" value="{
&quot;compileOnSave&quot;: false,
&quot;compilerOptions&quot;: {
&quot;baseUrl&quot;: &quot;./&quot;,
&quot;outDir&quot;: &quot;./dist/out-tsc&quot;,
&quot;forceConsistentCasingInFileNames&quot;: true,
&quot;noImplicitReturns&quot;: true,
&quot;noFallthroughCasesInSwitch&quot;: true,
&quot;sourceMap&quot;: true,
&quot;declaration&quot;: false,
&quot;downlevelIteration&quot;: true,
&quot;experimentalDecorators&quot;: true,
&quot;moduleResolution&quot;: &quot;node&quot;,
&quot;importHelpers&quot;: true,
&quot;target&quot;: &quot;es2015&quot;,
&quot;module&quot;: &quot;es2020&quot;,
&quot;lib&quot;: [
&quot;es2018&quot;,
&quot;dom&quot;
]
},
&quot;angularCompilerOptions&quot;: {
&quot;strictInjectionParameters&quot;: true,
&quot;strictInputAccessModifiers&quot;: true,
&quot;strictTemplates&quot;: true,
&quot;enableIvy&quot;: true
}
}"><input type="hidden" name="tags[0]" value="angular"><input type="hidden" name="tags[1]" value="example"><input type="hidden" name="tags[2]" value="lifecycle"><input type="hidden" name="tags[3]" value="hooks"><input type="hidden" name="tags[4]" value="OnInit"><input type="hidden" name="tags[5]" value="OnDestroy"><input type="hidden" name="tags[6]" value="OnChange"><input type="hidden" name="tags[7]" value="DoCheck"><input type="hidden" name="tags[8]" value="AfterContentInit"><input type="hidden" name="tags[9]" value="AfterContentChecked"><input type="hidden" name="tags[10]" value="AfterViewInit"><input type="hidden" name="tags[11]" value="AfterViewChecked"><input type="hidden" name="description" value="Angular Example - Lifecycle Hooks"><input type="hidden" name="dependencies" value="{&quot;@angular/animations&quot;:&quot;~11.0.1&quot;,&quot;@angular/common&quot;:&quot;~11.0.1&quot;,&quot;@angular/compiler&quot;:&quot;~11.0.1&quot;,&quot;@angular/core&quot;:&quot;~11.0.1&quot;,&quot;@angular/forms&quot;:&quot;~11.0.1&quot;,&quot;@angular/platform-browser&quot;:&quot;~11.0.1&quot;,&quot;@angular/platform-browser-dynamic&quot;:&quot;~11.0.1&quot;,&quot;@angular/router&quot;:&quot;~11.0.1&quot;,&quot;angular-in-memory-web-api&quot;:&quot;~0.11.0&quot;,&quot;rxjs&quot;:&quot;~6.6.0&quot;,&quot;tslib&quot;:&quot;^2.0.0&quot;,&quot;zone.js&quot;:&quot;~0.11.4&quot;,&quot;jasmine-core&quot;:&quot;~3.6.0&quot;,&quot;jasmine-marbles&quot;:&quot;~0.6.0&quot;}"></form>
<script>
var embedded = 'ctl=1';
var isEmbedded = window.location.search.indexOf(embedded) > -1;
if (isEmbedded) {
var form = document.getElementById('mainForm');
var action = form.action;
var actionHasParams = action.indexOf('?') > -1;
var symbol = actionHasParams ? '&' : '?'
form.action = form.action + symbol + embedded;
}
document.getElementById("mainForm").submit();
</script>
</body></html>