989 lines
30 KiB
HTML
989 lines
30 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.ts" target="_self"><input type="hidden" name="files[src/app/app.component.ts]" value="import { Component } from '@angular/core';
|
||
|
|
||
|
@Component({
|
||
|
selector: 'app-root',
|
||
|
template: `
|
||
|
<label><input type="checkbox" [checked]="showHeroes" (change)="showHeroes=!showHeroes">Heroes</label>
|
||
|
<label><input type="checkbox" [checked]="showVillains" (change)="showVillains=!showVillains">Villains</label>
|
||
|
<label><input type="checkbox" [checked]="showCars" (change)="showCars=!showCars">Cars</label>
|
||
|
|
||
|
<h1>Hierarchical Dependency Injection</h1>
|
||
|
|
||
|
<app-heroes-list *ngIf="showHeroes"></app-heroes-list>
|
||
|
<app-villains-list *ngIf="showVillains"></app-villains-list>
|
||
|
<app-cars *ngIf="showCars"></app-cars>
|
||
|
`
|
||
|
})
|
||
|
export class AppComponent {
|
||
|
showCars = true;
|
||
|
showHeroes = true;
|
||
|
showVillains = 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/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 { HeroTaxReturnComponent } from './hero-tax-return.component';
|
||
|
import { HeroesListComponent } from './heroes-list.component';
|
||
|
import { VillainsListComponent } from './villains-list.component';
|
||
|
|
||
|
import { carComponents } from './car.components';
|
||
|
|
||
|
@NgModule({
|
||
|
imports: [
|
||
|
BrowserModule,
|
||
|
FormsModule
|
||
|
],
|
||
|
declarations: [
|
||
|
AppComponent,
|
||
|
carComponents,
|
||
|
HeroesListComponent,
|
||
|
HeroTaxReturnComponent,
|
||
|
VillainsListComponent
|
||
|
],
|
||
|
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/car.components.ts]" value="import { Component } from '@angular/core';
|
||
|
|
||
|
import {
|
||
|
CarService, CarService2, CarService3,
|
||
|
EngineService, EngineService2, TiresService
|
||
|
} from './car.services';
|
||
|
|
||
|
////////// CCarComponent ////////////
|
||
|
@Component({
|
||
|
selector: 'c-car',
|
||
|
template: `<div>C: {{description}}</div>`,
|
||
|
providers: [
|
||
|
{ provide: CarService, useClass: CarService3 }
|
||
|
]
|
||
|
})
|
||
|
export class CCarComponent {
|
||
|
description: string;
|
||
|
constructor(carService: CarService) {
|
||
|
this.description = `${carService.getCar().description} (${carService.name})`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////// BCarComponent ////////////
|
||
|
@Component({
|
||
|
selector: 'b-car',
|
||
|
template: `
|
||
|
<div>B: {{description}}</div>
|
||
|
<c-car></c-car>
|
||
|
`,
|
||
|
providers: [
|
||
|
{ provide: CarService, useClass: CarService2 },
|
||
|
{ provide: EngineService, useClass: EngineService2 }
|
||
|
]
|
||
|
})
|
||
|
export class BCarComponent {
|
||
|
description: string;
|
||
|
constructor(carService: CarService) {
|
||
|
this.description = `${carService.getCar().description} (${carService.name})`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////// ACarComponent ////////////
|
||
|
@Component({
|
||
|
selector: 'a-car',
|
||
|
template: `
|
||
|
<div>A: {{description}}</div>
|
||
|
<b-car></b-car>`
|
||
|
})
|
||
|
export class ACarComponent {
|
||
|
description: string;
|
||
|
constructor(carService: CarService) {
|
||
|
this.description = `${carService.getCar().description} (${carService.name})`;
|
||
|
}
|
||
|
}
|
||
|
////////// CarsComponent ////////////
|
||
|
@Component({
|
||
|
selector: 'app-cars',
|
||
|
template: `
|
||
|
<h3>Cars</h3>
|
||
|
<a-car></a-car>`
|
||
|
})
|
||
|
export class CarsComponent { }
|
||
|
|
||
|
////////////////
|
||
|
|
||
|
export const carComponents = [
|
||
|
CarsComponent,
|
||
|
ACarComponent, BCarComponent, CCarComponent
|
||
|
];
|
||
|
|
||
|
// generic car-related services
|
||
|
export const carServices = [
|
||
|
CarService, EngineService, TiresService
|
||
|
];
|
||
|
|
||
|
|
||
|
/*
|
||
|
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/car.services.ts]" value="import { Injectable } from '@angular/core';
|
||
|
|
||
|
/// Model ///
|
||
|
export class Car {
|
||
|
name = 'Avocado Motors';
|
||
|
constructor(public engine: Engine, public tires: Tires) { }
|
||
|
|
||
|
get description() {
|
||
|
return `${this.name} car with ` +
|
||
|
`${this.engine.cylinders} cylinders and ${this.tires.make} tires.`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export class Engine {
|
||
|
cylinders = 4;
|
||
|
}
|
||
|
|
||
|
export class Tires {
|
||
|
make = 'Flintstone';
|
||
|
model = 'Square';
|
||
|
}
|
||
|
|
||
|
//// Engine services ///
|
||
|
@Injectable({
|
||
|
providedIn: 'root'
|
||
|
})
|
||
|
export class EngineService {
|
||
|
id = 'E1';
|
||
|
getEngine() { return new Engine(); }
|
||
|
}
|
||
|
|
||
|
@Injectable({
|
||
|
providedIn: 'root'
|
||
|
})
|
||
|
export class EngineService2 {
|
||
|
id = 'E2';
|
||
|
getEngine() {
|
||
|
const eng = new Engine();
|
||
|
eng.cylinders = 8;
|
||
|
return eng;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//// Tire services ///
|
||
|
@Injectable({
|
||
|
providedIn: 'root'
|
||
|
})
|
||
|
export class TiresService {
|
||
|
id = 'T1';
|
||
|
getTires() { return new Tires(); }
|
||
|
}
|
||
|
|
||
|
/// Car Services ///
|
||
|
@Injectable({
|
||
|
providedIn: 'root'
|
||
|
})
|
||
|
export class CarService {
|
||
|
id = 'C1';
|
||
|
constructor(
|
||
|
protected engineService: EngineService,
|
||
|
protected tiresService: TiresService) { }
|
||
|
|
||
|
getCar() {
|
||
|
return new Car(
|
||
|
this.engineService.getEngine(),
|
||
|
this.tiresService.getTires());
|
||
|
}
|
||
|
|
||
|
get name() {
|
||
|
return `${this.id}-${this.engineService.id}-${this.tiresService.id}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Injectable({
|
||
|
providedIn: 'root'
|
||
|
})
|
||
|
export class CarService2 extends CarService {
|
||
|
id = 'C2';
|
||
|
constructor(
|
||
|
protected engineService: EngineService,
|
||
|
protected tiresService: TiresService) {
|
||
|
super(engineService, tiresService);
|
||
|
}
|
||
|
getCar() {
|
||
|
const car = super.getCar();
|
||
|
car.name = 'BamBam Motors, BroVan 2000';
|
||
|
return car;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Injectable({
|
||
|
providedIn: 'root'
|
||
|
})
|
||
|
export class CarService3 extends CarService2 {
|
||
|
id = 'C3';
|
||
|
constructor(
|
||
|
protected engineService: EngineService,
|
||
|
protected tiresService: TiresService) {
|
||
|
super(engineService, tiresService);
|
||
|
}
|
||
|
getCar() {
|
||
|
const car = super.getCar();
|
||
|
car.name = 'Chizzamm Motors, Calico UltraMax Supreme';
|
||
|
return car;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
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-tax-return.component.ts]" value="// tslint:disable: no-output-native
|
||
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||
|
import { HeroTaxReturn } from './hero';
|
||
|
import { HeroTaxReturnService } from './hero-tax-return.service';
|
||
|
|
||
|
@Component({
|
||
|
selector: 'app-hero-tax-return',
|
||
|
templateUrl: './hero-tax-return.component.html',
|
||
|
styleUrls: [ './hero-tax-return.component.css' ],
|
||
|
providers: [ HeroTaxReturnService ]
|
||
|
})
|
||
|
export class HeroTaxReturnComponent {
|
||
|
message = '';
|
||
|
|
||
|
@Output() close = new EventEmitter<void>();
|
||
|
|
||
|
get taxReturn(): HeroTaxReturn {
|
||
|
return this.heroTaxReturnService.taxReturn;
|
||
|
}
|
||
|
|
||
|
@Input()
|
||
|
set taxReturn(htr: HeroTaxReturn) {
|
||
|
this.heroTaxReturnService.taxReturn = htr;
|
||
|
}
|
||
|
|
||
|
constructor(private heroTaxReturnService: HeroTaxReturnService) { }
|
||
|
|
||
|
onCanceled() {
|
||
|
this.flashMessage('Canceled');
|
||
|
this.heroTaxReturnService.restoreTaxReturn();
|
||
|
}
|
||
|
|
||
|
onClose() { this.close.emit(); }
|
||
|
|
||
|
onSaved() {
|
||
|
this.flashMessage('Saved');
|
||
|
this.heroTaxReturnService.saveTaxReturn();
|
||
|
}
|
||
|
|
||
|
flashMessage(msg: string) {
|
||
|
this.message = msg;
|
||
|
setTimeout(() => this.message = '', 500);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
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-tax-return.service.ts]" value="import { Injectable } from '@angular/core';
|
||
|
import { HeroTaxReturn } from './hero';
|
||
|
import { HeroesService } from './heroes.service';
|
||
|
|
||
|
@Injectable()
|
||
|
export class HeroTaxReturnService {
|
||
|
private currentTaxReturn: HeroTaxReturn;
|
||
|
private originalTaxReturn: HeroTaxReturn;
|
||
|
|
||
|
constructor(private heroService: HeroesService) { }
|
||
|
|
||
|
set taxReturn(htr: HeroTaxReturn) {
|
||
|
this.originalTaxReturn = htr;
|
||
|
this.currentTaxReturn = htr.clone();
|
||
|
}
|
||
|
|
||
|
get taxReturn(): HeroTaxReturn {
|
||
|
return this.currentTaxReturn;
|
||
|
}
|
||
|
|
||
|
restoreTaxReturn() {
|
||
|
this.taxReturn = this.originalTaxReturn;
|
||
|
}
|
||
|
|
||
|
saveTaxReturn() {
|
||
|
this.taxReturn = this.currentTaxReturn;
|
||
|
this.heroService.saveTaxReturn(this.currentTaxReturn).subscribe();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
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 interface Hero {
|
||
|
id: number;
|
||
|
name: string;
|
||
|
tid: string; // tax id
|
||
|
}
|
||
|
|
||
|
//// HeroTaxReturn ////
|
||
|
let nextId = 100;
|
||
|
|
||
|
export class HeroTaxReturn {
|
||
|
constructor(
|
||
|
public id = nextId++,
|
||
|
public hero: Hero,
|
||
|
public income = 0 ) {
|
||
|
if (id === 0) { id = nextId++; }
|
||
|
}
|
||
|
|
||
|
get name() { return this.hero.name; }
|
||
|
get tax() { return this.income ? .10 * this.income : 0; }
|
||
|
get tid() { return this.hero.tid; }
|
||
|
|
||
|
toString() {
|
||
|
return `${this.hero.name}`;
|
||
|
}
|
||
|
|
||
|
clone() {
|
||
|
return new HeroTaxReturn(this.id, this.hero, this.income);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
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/heroes-list.component.ts]" value="import { Component } from '@angular/core';
|
||
|
import { Observable } from 'rxjs';
|
||
|
|
||
|
import { Hero, HeroTaxReturn } from './hero';
|
||
|
import { HeroesService } from './heroes.service';
|
||
|
|
||
|
@Component({
|
||
|
selector: 'app-heroes-list',
|
||
|
template: `
|
||
|
<div>
|
||
|
<h3>Hero Tax Returns</h3>
|
||
|
<ul>
|
||
|
<li *ngFor="let hero of heroes | async"
|
||
|
(click)="showTaxReturn(hero)">{{hero.name}}
|
||
|
</li>
|
||
|
</ul>
|
||
|
<app-hero-tax-return
|
||
|
*ngFor="let selected of selectedTaxReturns; let i = index"
|
||
|
[taxReturn]="selected"
|
||
|
(close)="closeTaxReturn(i)">
|
||
|
</app-hero-tax-return>
|
||
|
</div>
|
||
|
`,
|
||
|
styles: [ 'li {cursor: pointer;}' ]
|
||
|
})
|
||
|
export class HeroesListComponent {
|
||
|
heroes: Observable<Hero[]>;
|
||
|
selectedTaxReturns: HeroTaxReturn[] = [];
|
||
|
|
||
|
constructor(private heroesService: HeroesService) {
|
||
|
this.heroes = heroesService.getHeroes();
|
||
|
}
|
||
|
|
||
|
showTaxReturn(hero: Hero) {
|
||
|
this.heroesService.getTaxReturn(hero)
|
||
|
.subscribe(htr => {
|
||
|
// show if not currently shown
|
||
|
if (!this.selectedTaxReturns.find(tr => tr.id === htr.id)) {
|
||
|
this.selectedTaxReturns.push(htr);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
closeTaxReturn(ix: number) {
|
||
|
this.selectedTaxReturns.splice(ix, 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
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/heroes.service.ts]" value="import { Injectable } from '@angular/core';
|
||
|
|
||
|
import { Observable, Observer } from 'rxjs';
|
||
|
|
||
|
import { Hero, HeroTaxReturn } from './hero';
|
||
|
|
||
|
@Injectable({
|
||
|
providedIn: 'root'
|
||
|
})
|
||
|
export class HeroesService {
|
||
|
heroes: Hero[] = [
|
||
|
{ id: 1, name: 'RubberMan', tid: '082-27-5678'},
|
||
|
{ id: 2, name: 'Tornado', tid: '099-42-4321'}
|
||
|
];
|
||
|
|
||
|
heroTaxReturns: HeroTaxReturn[] = [
|
||
|
new HeroTaxReturn(10, this.heroes[0], 35000),
|
||
|
new HeroTaxReturn(20, this.heroes[1], 1250000)
|
||
|
];
|
||
|
|
||
|
getHeroes(): Observable<Hero[]> {
|
||
|
return new Observable<Hero[]>((observer: Observer<Hero[]>) => {
|
||
|
observer.next(this.heroes);
|
||
|
observer.complete();
|
||
|
});
|
||
|
}
|
||
|
|
||
|
getTaxReturn(hero: Hero): Observable<HeroTaxReturn> {
|
||
|
return new Observable<HeroTaxReturn>((observer: Observer<HeroTaxReturn>) => {
|
||
|
const htr = this.heroTaxReturns.find(t => t.hero.id === hero.id);
|
||
|
observer.next(htr || new HeroTaxReturn(0, hero));
|
||
|
observer.complete();
|
||
|
});
|
||
|
}
|
||
|
|
||
|
saveTaxReturn(heroTaxReturn: HeroTaxReturn): Observable<HeroTaxReturn> {
|
||
|
return new Observable<HeroTaxReturn>((observer: Observer<HeroTaxReturn>) => {
|
||
|
const htr = this.heroTaxReturns.find(t => t.id === heroTaxReturn.id);
|
||
|
if (htr) {
|
||
|
heroTaxReturn = Object.assign(htr, heroTaxReturn); // demo: mutate
|
||
|
} else {
|
||
|
this.heroTaxReturns.push(heroTaxReturn);
|
||
|
}
|
||
|
observer.next(heroTaxReturn);
|
||
|
observer.complete();
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
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/villains-list.component.ts]" value="import { Component } from '@angular/core';
|
||
|
import { Observable } from 'rxjs';
|
||
|
|
||
|
import { Villain, VillainsService } from './villains.service';
|
||
|
|
||
|
@Component({
|
||
|
selector: 'app-villains-list',
|
||
|
templateUrl: './villains-list.component.html',
|
||
|
providers: [ VillainsService ]
|
||
|
})
|
||
|
export class VillainsListComponent {
|
||
|
villains: Observable<Villain[]>;
|
||
|
|
||
|
constructor(private villainsService: VillainsService) {
|
||
|
this.villains = villainsService.getVillains();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
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/villains.service.ts]" value="import { Injectable } from '@angular/core';
|
||
|
|
||
|
import { of } from 'rxjs';
|
||
|
|
||
|
export interface Villain { id: number; name: string; }
|
||
|
|
||
|
@Injectable()
|
||
|
export class VillainsService {
|
||
|
villains: Villain[] = [
|
||
|
{ id: 1, name: 'Dr. Evil'},
|
||
|
{ id: 2, name: 'Moriarty'}
|
||
|
];
|
||
|
|
||
|
getVillains() {
|
||
|
return of(this.villains);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
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 "evergreen" 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/app/hero-tax-return.component.css]" value=".tax-return { border: thin dashed green; margin: 1em; padding: 1em; width: 18em; position: relative }
|
||
|
#name { font-weight: bold;}
|
||
|
#tid { float: right; }
|
||
|
input { font-size: 100%; padding-left: 2px; width: 6em; }
|
||
|
input.num { text-align: right; padding-left: 0; padding-right: 4px; width: 4em;}
|
||
|
fieldset { border: 0 none;}
|
||
|
|
||
|
.msg {
|
||
|
color: white;
|
||
|
font-size: 150%;
|
||
|
position: absolute;
|
||
|
/*opacity: 0.3;*/
|
||
|
left: 2px;
|
||
|
top: 3em;
|
||
|
width: 98%;
|
||
|
background-color: green;
|
||
|
text-align: center;
|
||
|
}
|
||
|
.msg.canceled {
|
||
|
color: white;
|
||
|
background-color: red;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
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="text"] {
|
||
|
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/hero-tax-return.component.html]" value="<div class="tax-return">
|
||
|
<div class="msg" [class.canceled]="message==='Canceled'">{{message}}</div>
|
||
|
<fieldset>
|
||
|
<span id=name>{{taxReturn.name}}</span>
|
||
|
<label id=tid>TID: {{taxReturn.tid}}</label>
|
||
|
</fieldset>
|
||
|
<fieldset>
|
||
|
<label>
|
||
|
Income: <input [(ngModel)]="taxReturn.income" class="num">
|
||
|
</label>
|
||
|
</fieldset>
|
||
|
<fieldset>
|
||
|
<label>Tax: {{taxReturn.tax}}</label>
|
||
|
</fieldset>
|
||
|
<fieldset>
|
||
|
<button (click)="onSaved()">Save</button>
|
||
|
<button (click)="onCanceled()">Cancel</button>
|
||
|
<button (click)="onClose()">Close</button>
|
||
|
</fieldset>
|
||
|
</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/villains-list.component.html]" value="<div>
|
||
|
<h3>Villains</h3>
|
||
|
<ul>
|
||
|
<li *ngFor="let villain of villains | async">{{villain.name}}</li>
|
||
|
</ul>
|
||
|
</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="en">
|
||
|
<head>
|
||
|
<title>Hierarchical Injectors</title>
|
||
|
<base href="/">
|
||
|
<meta charset="UTF-8">
|
||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
|
</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="{
|
||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||
|
"version": 1,
|
||
|
"newProjectRoot": "projects",
|
||
|
"projects": {
|
||
|
"angular.io-example": {
|
||
|
"projectType": "application",
|
||
|
"schematics": {
|
||
|
"@schematics/angular:application": {
|
||
|
"strict": true
|
||
|
}
|
||
|
},
|
||
|
"root": "",
|
||
|
"sourceRoot": "src",
|
||
|
"prefix": "app",
|
||
|
"architect": {
|
||
|
"build": {
|
||
|
"builder": "@angular-devkit/build-angular:browser",
|
||
|
"options": {
|
||
|
"outputPath": "dist",
|
||
|
"index": "src/index.html",
|
||
|
"main": "src/main.ts",
|
||
|
"polyfills": "src/polyfills.ts",
|
||
|
"tsConfig": "tsconfig.app.json",
|
||
|
"aot": true,
|
||
|
"assets": [
|
||
|
"src/favicon.ico",
|
||
|
"src/assets"
|
||
|
],
|
||
|
"styles": [
|
||
|
"src/styles.css"
|
||
|
],
|
||
|
"scripts": []
|
||
|
},
|
||
|
"configurations": {
|
||
|
"production": {
|
||
|
"fileReplacements": [
|
||
|
{
|
||
|
"replace": "src/environments/environment.ts",
|
||
|
"with": "src/environments/environment.prod.ts"
|
||
|
}
|
||
|
],
|
||
|
"optimization": true,
|
||
|
"outputHashing": "all",
|
||
|
"sourceMap": false,
|
||
|
"namedChunks": false,
|
||
|
"extractLicenses": true,
|
||
|
"vendorChunk": false,
|
||
|
"buildOptimizer": true,
|
||
|
"budgets": [
|
||
|
{
|
||
|
"type": "initial",
|
||
|
"maximumWarning": "500kb",
|
||
|
"maximumError": "1mb"
|
||
|
},
|
||
|
{
|
||
|
"type": "anyComponentStyle",
|
||
|
"maximumWarning": "2kb",
|
||
|
"maximumError": "4kb"
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"serve": {
|
||
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||
|
"options": {
|
||
|
"browserTarget": "angular.io-example:build"
|
||
|
},
|
||
|
"configurations": {
|
||
|
"production": {
|
||
|
"browserTarget": "angular.io-example:build:production"
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"extract-i18n": {
|
||
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||
|
"options": {
|
||
|
"browserTarget": "angular.io-example:build"
|
||
|
}
|
||
|
},
|
||
|
"test": {
|
||
|
"builder": "@angular-devkit/build-angular:karma",
|
||
|
"options": {
|
||
|
"main": "src/test.ts",
|
||
|
"polyfills": "src/polyfills.ts",
|
||
|
"tsConfig": "tsconfig.spec.json",
|
||
|
"karmaConfig": "karma.conf.js",
|
||
|
"assets": [
|
||
|
"src/favicon.ico",
|
||
|
"src/assets"
|
||
|
],
|
||
|
"styles": [
|
||
|
"src/styles.css"
|
||
|
],
|
||
|
"scripts": []
|
||
|
}
|
||
|
},
|
||
|
"lint": {
|
||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||
|
"options": {
|
||
|
"tsConfig": [
|
||
|
"tsconfig.app.json",
|
||
|
"tsconfig.spec.json",
|
||
|
"e2e/tsconfig.json"
|
||
|
],
|
||
|
"exclude": [
|
||
|
"**/node_modules/**"
|
||
|
]
|
||
|
}
|
||
|
},
|
||
|
"e2e": {
|
||
|
"builder": "@angular-devkit/build-angular:protractor",
|
||
|
"options": {
|
||
|
"protractorConfig": "e2e/protractor.conf.js",
|
||
|
"devServerTarget": "angular.io-example:serve"
|
||
|
},
|
||
|
"configurations": {
|
||
|
"production": {
|
||
|
"devServerTarget": "angular.io-example:serve:production"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"defaultProject": "angular.io-example"
|
||
|
}
|
||
|
"><input type="hidden" name="files[tsconfig.json]" value="{
|
||
|
"compileOnSave": false,
|
||
|
"compilerOptions": {
|
||
|
"baseUrl": "./",
|
||
|
"outDir": "./dist/out-tsc",
|
||
|
"forceConsistentCasingInFileNames": true,
|
||
|
"noImplicitReturns": true,
|
||
|
"noFallthroughCasesInSwitch": true,
|
||
|
"sourceMap": true,
|
||
|
"declaration": false,
|
||
|
"downlevelIteration": true,
|
||
|
"experimentalDecorators": true,
|
||
|
"moduleResolution": "node",
|
||
|
"importHelpers": true,
|
||
|
"target": "es2015",
|
||
|
"module": "es2020",
|
||
|
"lib": [
|
||
|
"es2018",
|
||
|
"dom"
|
||
|
]
|
||
|
},
|
||
|
"angularCompilerOptions": {
|
||
|
"strictInjectionParameters": true,
|
||
|
"strictInputAccessModifiers": true,
|
||
|
"strictTemplates": true,
|
||
|
"enableIvy": true
|
||
|
}
|
||
|
}"><input type="hidden" name="tags[0]" value="angular"><input type="hidden" name="tags[1]" value="example"><input type="hidden" name="tags[2]" value="dependency"><input type="hidden" name="tags[3]" value="injection"><input type="hidden" name="description" value="Angular Example - Hierarchical Dependency Injection"><input type="hidden" name="dependencies" value="{"@angular/animations":"~11.0.1","@angular/common":"~11.0.1","@angular/compiler":"~11.0.1","@angular/core":"~11.0.1","@angular/forms":"~11.0.1","@angular/platform-browser":"~11.0.1","@angular/platform-browser-dynamic":"~11.0.1","@angular/router":"~11.0.1","angular-in-memory-web-api":"~0.11.0","rxjs":"~6.6.0","tslib":"^2.0.0","zone.js":"~0.11.4","jasmine-core":"~3.6.0","jasmine-marbles":"~0.6.0"}"></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>
|