This commit is contained in:
parent
eff474b5b1
commit
3d12ab7d35
|
@ -11,8 +11,6 @@ table {
|
|||
margin:20px;
|
||||
border:#ccc 1px solid;
|
||||
|
||||
-moz-border-radius:3px;
|
||||
-webkit-border-radius:3px;
|
||||
border-radius:3px;
|
||||
}
|
||||
table th {
|
||||
|
@ -46,12 +44,8 @@ table tr:last-child td {
|
|||
border-bottom:0;
|
||||
}
|
||||
table tr:last-child td:first-child {
|
||||
-moz-border-radius-bottomleft:3px;
|
||||
-webkit-border-bottom-left-radius:3px;
|
||||
border-bottom-left-radius:3px;
|
||||
}
|
||||
table tr:last-child td:last-child {
|
||||
-moz-border-radius-bottomright:3px;
|
||||
-webkit-border-bottom-right-radius:3px;
|
||||
border-bottom-right-radius:3px;
|
||||
}
|
||||
|
|
|
@ -67,9 +67,7 @@
|
|||
<td>{{movie.hero}}</td>
|
||||
<td>{{movie.releaseDate | date}}</td>
|
||||
<td>{{movie.mpaa | uppercase}}</td>
|
||||
<!-- #docregion currency -->
|
||||
<td>{{movie.price | currency:'USD':true}}</td>
|
||||
<!-- #enddocregion currency -->
|
||||
<td>{{movie.starRating | number:'1.1-2'}}</td>
|
||||
<td>{{movie.approvalRating | percent: '1.0-0'}}</td>
|
||||
</tr>
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
/* tslint:disable:no-unused-variable */
|
||||
// #docplaster
|
||||
// #docregion import
|
||||
import { Component } from '@angular/core';
|
||||
// #enddocregion import
|
||||
import { IMovie } from './movie';
|
||||
import { MovieService } from './movie.service';
|
||||
|
||||
|
|
|
@ -1,18 +1,6 @@
|
|||
// #docplaster
|
||||
// #docregion imports
|
||||
import { Component, HostBinding } from '@angular/core';
|
||||
import {
|
||||
trigger,
|
||||
state,
|
||||
style,
|
||||
animate,
|
||||
transition,
|
||||
// ...
|
||||
} from '@angular/animations';
|
||||
|
||||
// #enddocregion imports
|
||||
|
||||
// #docregion decorator, toggle-app-animations
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: 'app.component.html',
|
||||
|
@ -21,15 +9,10 @@ import {
|
|||
// animation triggers go here
|
||||
]
|
||||
})
|
||||
// #enddocregion decorator
|
||||
export class AppComponent {
|
||||
@HostBinding('@.disabled')
|
||||
public animationsDisabled = false;
|
||||
// #enddocregion toggle-app-animations
|
||||
@HostBinding('@.disabled') public animationsDisabled = false;
|
||||
|
||||
toggleAnimations() {
|
||||
this.animationsDisabled = !this.animationsDisabled;
|
||||
}
|
||||
// #docregion toggle-app-animations
|
||||
}
|
||||
// #enddocregion toggle-app-animations
|
||||
|
|
|
@ -16,7 +16,6 @@ import { Hero } from './hero';
|
|||
|
||||
@Component({
|
||||
selector: 'app-hero-list-enter-leave',
|
||||
// #docregion template
|
||||
template: `
|
||||
<ul class="heroes">
|
||||
<li *ngFor="let hero of heroes"
|
||||
|
@ -28,7 +27,6 @@ import { Hero } from './hero';
|
|||
</li>
|
||||
</ul>
|
||||
`,
|
||||
// #enddocregion template
|
||||
styleUrls: ['./hero-list-page.component.css'],
|
||||
// #docregion animationdef
|
||||
animations: [
|
||||
|
|
|
@ -62,8 +62,7 @@
|
|||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
cursor: hand;
|
||||
font-family: Arial;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
|
|
|
@ -1,29 +1,12 @@
|
|||
// #docplaster
|
||||
// #docregion reusable
|
||||
import { Component } from '@angular/core';
|
||||
import { useAnimation, transition, trigger, style, animate } from '@angular/animations';
|
||||
import { transition, trigger, useAnimation } from '@angular/animations';
|
||||
import { transAnimation } from './animations';
|
||||
|
||||
@Component({
|
||||
// #enddocregion reusable
|
||||
selector: 'app-open-close-reusable',
|
||||
// #docregion runtime
|
||||
animations: [
|
||||
transition('open => closed', [
|
||||
style({
|
||||
height: '200 px',
|
||||
opacity: '{{ opacity }}',
|
||||
backgroundcolor: 'yelow'
|
||||
}),
|
||||
animate('{{ time }}'),
|
||||
], {
|
||||
params: {
|
||||
time: '1s',
|
||||
opacity: '1'
|
||||
}
|
||||
}),
|
||||
// #enddocregion runtime
|
||||
// #docregion reusable
|
||||
trigger('openClose', [
|
||||
transition('open => closed', [
|
||||
useAnimation(transAnimation, {
|
||||
|
@ -36,10 +19,9 @@ import { transAnimation } from './animations';
|
|||
})
|
||||
])
|
||||
])
|
||||
// #enddocregion reusable
|
||||
],
|
||||
templateUrl: 'open-close.component.html',
|
||||
styleUrls: ['open-close.component.css']
|
||||
// #docregion reusable
|
||||
})
|
||||
// #enddocregion reusable
|
||||
export class OpenCloseReusableComponent { }
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
<!-- #docplaster -->
|
||||
<nav>
|
||||
<button (click)="toggle()">Toggle Open/Close</button>
|
||||
</nav>
|
||||
|
||||
<!-- #docregion compare, trigger -->
|
||||
<div [@openClose]="isOpen ? 'open' : 'closed'"
|
||||
(@openClose.start)="onAnimationEvent($event)"
|
||||
(@openClose.done)="onAnimationEvent($event)"
|
||||
class="open-close-container">
|
||||
<p>The box is now {{ isOpen ? 'Open' : 'Closed' }}!</p>
|
||||
</div>
|
||||
<!-- #enddocregion compare, trigger -->
|
||||
|
|
|
@ -5,7 +5,7 @@ import { trigger, transition, state, animate, style, AnimationEvent } from '@ang
|
|||
// #docregion component, events1
|
||||
@Component({
|
||||
selector: 'app-open-close',
|
||||
// #docregion trigger, trigger-wildcard1, trigger-transition
|
||||
// #docregion trigger-wildcard1, trigger-transition
|
||||
animations: [
|
||||
trigger('openClose', [
|
||||
// #docregion state1
|
||||
|
@ -33,7 +33,7 @@ import { trigger, transition, state, animate, style, AnimationEvent } from '@ang
|
|||
transition('closed => open', [
|
||||
animate('0.5s')
|
||||
]),
|
||||
// #enddocregion transition2, trigger, component
|
||||
// #enddocregion transition2, component
|
||||
// #docregion trigger-wildcard1
|
||||
transition('* => closed', [
|
||||
animate('1s')
|
||||
|
@ -54,15 +54,14 @@ import { trigger, transition, state, animate, style, AnimationEvent } from '@ang
|
|||
),
|
||||
]),
|
||||
// #enddocregion transition4
|
||||
// #docregion transition3
|
||||
transition('* => *', [
|
||||
animate('1s')
|
||||
]),
|
||||
// #enddocregion transition3, trigger-transition
|
||||
// #docregion trigger, component, trigger-wildcard1, events1
|
||||
// #enddocregion trigger-transition
|
||||
// #docregion component, trigger-wildcard1, events1
|
||||
]),
|
||||
],
|
||||
// #enddocregion trigger, trigger-wildcard1
|
||||
// #enddocregion trigger-wildcard1
|
||||
templateUrl: 'open-close.component.html',
|
||||
styleUrls: ['open-close.component.css']
|
||||
})
|
||||
|
|
|
@ -9,6 +9,4 @@ import { Component } from '@angular/core';
|
|||
<app-sales-tax></app-sales-tax>
|
||||
`
|
||||
})
|
||||
// #docregion export
|
||||
export class AppComponent { }
|
||||
// #enddocregion export
|
||||
|
|
|
@ -22,13 +22,11 @@ import { Logger } from './logger.service';
|
|||
HeroListComponent,
|
||||
SalesTaxComponent
|
||||
],
|
||||
// #docregion providers
|
||||
providers: [
|
||||
BackendService,
|
||||
HeroService,
|
||||
Logger
|
||||
],
|
||||
// #enddocregion providers
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
// #docregion export
|
||||
|
|
|
@ -7,9 +7,7 @@ export class Logger {
|
|||
log(message: string) { console.log(message); }
|
||||
}
|
||||
|
||||
// #docregion import-core-component
|
||||
import { Component } from '@angular/core';
|
||||
// #enddocregion import-core-component
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
|
@ -35,9 +33,7 @@ import { BrowserModule } from '@angular/platform-browser';
|
|||
exports: [ AppComponent ],
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
// #docregion export
|
||||
export class AppModule { }
|
||||
// #enddocregion export
|
||||
// #enddocregion module
|
||||
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
<h1>Attribute, class, and style bindings</h1>
|
||||
<h2>Attribute binding</h2>
|
||||
<!-- #docregion attrib-binding-colspan -->
|
||||
<table border=1>
|
||||
<!-- #docregion colspan -->
|
||||
<!-- expression calculates colspan=2 -->
|
||||
|
@ -18,7 +17,6 @@
|
|||
|
||||
<tr><td>Five</td><td>Six</td></tr>
|
||||
</table>
|
||||
<!-- #enddocregion attrib-binding-colspan -->
|
||||
|
||||
<div>
|
||||
<!-- #docregion attrib-binding-aria -->
|
||||
|
@ -66,4 +64,6 @@
|
|||
<comp-with-host-binding dirWithHostBinding></comp-with-host-binding>
|
||||
<!-- #enddocregion style-delegation -->
|
||||
|
||||
|
||||
<!-- #docregion attribute-decorator -->
|
||||
<app-my-input-with-attribute-decorator type="number"></app-my-input-with-attribute-decorator>
|
||||
<!-- #enddocregion attribute-decorator -->
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { CompWithHostBindingComponent } from './comp-with-host-binding.component';
|
||||
|
||||
import { MyInputWithAttributeDecoratorComponent } from './my-input-with-attribute-decorator.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
CompWithHostBindingComponent
|
||||
CompWithHostBindingComponent,
|
||||
MyInputWithAttributeDecoratorComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule
|
||||
|
|
|
@ -4,11 +4,7 @@
|
|||
<p appHighlight>Highlight me!</p>
|
||||
<!-- #enddocregion applied -->
|
||||
|
||||
<!-- #docregion color-1 -->
|
||||
<p appHighlight highlightColor="yellow">Highlighted in yellow</p>
|
||||
<p appHighlight [highlightColor]="'orange'">Highlighted in orange</p>
|
||||
<!-- #enddocregion color-1 -->
|
||||
|
||||
<!-- #docregion color-2 -->
|
||||
<p appHighlight [highlightColor]="color">Highlighted with parent component's color</p>
|
||||
<!-- #enddocregion color-2 -->
|
|
@ -1,8 +1,8 @@
|
|||
/* tslint:disable:no-unused-variable member-ordering */
|
||||
// #docplaster
|
||||
// #docregion imports,
|
||||
// #docregion imports
|
||||
import { Directive, ElementRef, HostListener } from '@angular/core';
|
||||
// #enddocregion imports,
|
||||
// #enddocregion imports
|
||||
import { Input } from '@angular/core';
|
||||
// #docregion
|
||||
|
||||
|
@ -10,37 +10,22 @@ import { Input } from '@angular/core';
|
|||
selector: '[appHighlight]'
|
||||
})
|
||||
export class HighlightDirective {
|
||||
// #docregion ctor
|
||||
constructor(private el: ElementRef) { }
|
||||
// #enddocregion ctor
|
||||
|
||||
// #docregion mouse-methods, host
|
||||
constructor(private el: ElementRef) { }
|
||||
|
||||
// #docregion mouse-methods
|
||||
@HostListener('mouseenter') onMouseEnter() {
|
||||
// #enddocregion host
|
||||
this.highlight('yellow');
|
||||
// #docregion host
|
||||
}
|
||||
|
||||
@HostListener('mouseleave') onMouseLeave() {
|
||||
// #enddocregion host
|
||||
this.highlight(null);
|
||||
// #docregion host
|
||||
}
|
||||
// #enddocregion host
|
||||
|
||||
private highlight(color: string) {
|
||||
this.el.nativeElement.style.backgroundColor = color;
|
||||
}
|
||||
// #enddocregion mouse-methods,
|
||||
// #enddocregion mouse-methods
|
||||
|
||||
// #docregion color
|
||||
@Input() highlightColor: string;
|
||||
// #enddocregion color
|
||||
|
||||
// #docregion color-2
|
||||
@Input() appHighlight: string;
|
||||
// #enddocregion color-2
|
||||
|
||||
// #docregion
|
||||
}
|
||||
// #enddocregion
|
||||
|
|
|
@ -10,13 +10,13 @@ export class HighlightDirective {
|
|||
|
||||
constructor(private el: ElementRef) { }
|
||||
|
||||
@Input('appHighlight') highlightColor: string;
|
||||
// #docregion input
|
||||
@Input() appHighlight: string;
|
||||
// #enddocregion input
|
||||
|
||||
// #docregion mouse-enter
|
||||
@HostListener('mouseenter') onMouseEnter() {
|
||||
this.highlight(this.highlightColor || 'red');
|
||||
this.highlight(this.appHighlight || 'red');
|
||||
}
|
||||
// #enddocregion mouse-enter
|
||||
|
||||
@HostListener('mouseleave') onMouseLeave() {
|
||||
this.highlight(null);
|
||||
|
|
|
@ -12,9 +12,7 @@ export class HighlightDirective {
|
|||
@Input() defaultColor: string;
|
||||
// #enddocregion defaultColor
|
||||
|
||||
// #docregion color
|
||||
@Input('appHighlight') highlightColor: string;
|
||||
// #enddocregion color
|
||||
|
||||
// #docregion mouse-enter
|
||||
@HostListener('mouseenter') onMouseEnter() {
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
// #docplaster
|
||||
// #docregion whole-ngmodule
|
||||
|
||||
// imports
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
@ -32,5 +30,3 @@ import { ItemDirective } from './item.directive';
|
|||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
||||
// #enddocregion whole-ngmodule
|
||||
|
|
|
@ -59,7 +59,7 @@ img {
|
|||
|
||||
.study,
|
||||
.modified {
|
||||
font-family: "Brush Script MT";
|
||||
font-family: "Brush Script MT", cursive;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,8 @@
|
|||
<fieldset><h4>NgModel examples</h4>
|
||||
<p>Current item name: {{currentItem.name}}</p>
|
||||
<p>
|
||||
<!-- #docregion without-NgModel -->
|
||||
<label for="without">without NgModel:</label>
|
||||
<input [value]="currentItem.name" (input)="currentItem.name=$event.target.value" id="without">
|
||||
<!-- #enddocregion without-NgModel -->
|
||||
|
||||
<input [value]="currentItem.name" (input)="currentItem.name=getValue($event.target)" id="without">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
@ -27,10 +24,8 @@
|
|||
</p>
|
||||
|
||||
<p>
|
||||
<!-- #docregion NgModelChange -->
|
||||
<label for="example-change">(ngModelChange)="...name=$event":</label>
|
||||
<input [ngModel]="currentItem.name" (ngModelChange)="currentItem.name=$event" id="example-change">
|
||||
<!-- #enddocregion NgModelChange -->
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
@ -77,12 +72,9 @@
|
|||
|
||||
<!-- NgStyle binding -->
|
||||
<hr><h3>NgStyle Binding</h3>
|
||||
<!-- #docregion without-ng-style -->
|
||||
<div [style.font-size]="isSpecial ? 'x-large' : 'smaller'">
|
||||
This div is x-large or smaller.
|
||||
</div>
|
||||
<!-- #enddocregion without-ng-style -->
|
||||
|
||||
|
||||
<h4>[ngStyle] binding to currentStyles - CSS property names</h4>
|
||||
<p>currentStyles is {{currentStyles | json}}</p>
|
||||
|
@ -134,7 +126,6 @@
|
|||
<hr>
|
||||
|
||||
<h4>Show/hide vs. NgIf</h4>
|
||||
<!-- #docregion NgIf-3 -->
|
||||
<!-- isSpecial is true -->
|
||||
<div [class.hidden]="!isSpecial">Show with class</div>
|
||||
<div [class.hidden]="isSpecial">Hide with class</div>
|
||||
|
@ -144,7 +135,6 @@
|
|||
|
||||
<div [style.display]="isSpecial ? 'block' : 'none'">Show with style</div>
|
||||
<div [style.display]="isSpecial ? 'none' : 'block'">Hide with style</div>
|
||||
<!-- #enddocregion NgIf-3 -->
|
||||
|
||||
|
||||
<hr>
|
||||
|
|
|
@ -21,7 +21,10 @@ export class AppComponent implements OnInit {
|
|||
item: Item; // defined to demonstrate template context precedence
|
||||
items: Item[];
|
||||
|
||||
// #docregion item
|
||||
currentItem: Item;
|
||||
// #enddocregion item
|
||||
|
||||
|
||||
|
||||
// trackBy change counting
|
||||
|
@ -111,6 +114,9 @@ export class AppComponent implements OnInit {
|
|||
|
||||
trackById(index: number, item: any): number { return item.id; }
|
||||
|
||||
getValue(target: EventTarget): string {
|
||||
return (target as HTMLInputElement).value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -5,9 +5,13 @@ import { Item } from './item';
|
|||
selector: 'app-stout-item',
|
||||
template: `I'm a little {{item.name}}, short and stout!`
|
||||
})
|
||||
|
||||
// #docregion input
|
||||
export class StoutItemComponent {
|
||||
@Input() item: Item;
|
||||
}
|
||||
// #enddocregion input
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-best-item',
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { Component, Input } from '@angular/core';
|
||||
import { Hero } from './hero';
|
||||
|
||||
// #docregion styleurls
|
||||
@Component({
|
||||
selector: 'app-hero-details',
|
||||
template: `
|
||||
|
@ -12,7 +11,5 @@ import { Hero } from './hero';
|
|||
styleUrls: ['./hero-details.component.css']
|
||||
})
|
||||
export class HeroDetailsComponent {
|
||||
// #enddocregion styleurls
|
||||
@Input() hero: Hero;
|
||||
// #docregion styleurls
|
||||
}
|
||||
|
|
|
@ -5,10 +5,8 @@ import { Component, ViewEncapsulation } from '@angular/core';
|
|||
// #docregion
|
||||
@Component({
|
||||
selector: 'app-quest-summary',
|
||||
// #docregion urls
|
||||
templateUrl: './quest-summary.component.html',
|
||||
styleUrls: ['./quest-summary.component.css']
|
||||
// #enddocregion urls
|
||||
})
|
||||
export class QuestSummaryComponent { }
|
||||
// #enddocregion
|
||||
|
|
|
@ -1,26 +1,18 @@
|
|||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
// #docregion import-services
|
||||
import { LoggerService } from './logger.service';
|
||||
import { UserContextService } from './user-context.service';
|
||||
import { UserService } from './user.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
})
|
||||
export class AppComponent {
|
||||
// #enddocregion import-services
|
||||
|
||||
private userId = 1;
|
||||
|
||||
// #docregion ctor
|
||||
constructor(logger: LoggerService, public userContext: UserContextService) {
|
||||
userContext.loadUser(this.userId);
|
||||
logger.logInfo('AppComponent initialized');
|
||||
}
|
||||
// #enddocregion ctor
|
||||
// #docregion import-services
|
||||
}
|
||||
// #enddocregion import-services
|
||||
|
|
|
@ -8,9 +8,7 @@ import { LoggerService } from './logger.service';
|
|||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
// #docregion date-logger-service-signature
|
||||
export class DateLoggerService extends LoggerService
|
||||
// #enddocregion date-logger-service-signature
|
||||
{
|
||||
logInfo(msg: any) { super.logInfo(stamp(msg)); }
|
||||
logDebug(msg: any) { super.logInfo(stamp(msg)); }
|
||||
|
|
|
@ -17,11 +17,9 @@ import { LoggerService } from './logger.service';
|
|||
})
|
||||
export class HeroBiosComponent {
|
||||
// #enddocregion simple
|
||||
// #docregion ctor
|
||||
constructor(logger: LoggerService) {
|
||||
logger.logInfo('Creating HeroBiosComponent');
|
||||
}
|
||||
// #enddocregion ctor
|
||||
// #docregion simple
|
||||
}
|
||||
// #enddocregion simple
|
||||
|
@ -36,9 +34,7 @@ export class HeroBiosComponent {
|
|||
<app-hero-bio [heroId]="2"> <app-hero-contact></app-hero-contact> </app-hero-bio>
|
||||
<app-hero-bio [heroId]="3"> <app-hero-contact></app-hero-contact> </app-hero-bio>`,
|
||||
// #enddocregion template
|
||||
// #docregion class-provider
|
||||
providers: [HeroService]
|
||||
// #enddocregion class-provider
|
||||
})
|
||||
export class HeroBiosAndContactsComponent {
|
||||
constructor(logger: LoggerService) {
|
||||
|
|
|
@ -30,9 +30,7 @@ export class HeroContactComponent {
|
|||
this.hasLogger = true;
|
||||
loggerService.logInfo('HeroContactComponent can log!');
|
||||
}
|
||||
// #docregion ctor
|
||||
}
|
||||
// #enddocregion ctor
|
||||
|
||||
get phoneNumber() { return this.heroCache.hero.phone; }
|
||||
|
||||
|
|
|
@ -48,13 +48,11 @@ const someHero = new Hero(42, 'Magma', 'Had a great month!', '555-555-5555');
|
|||
export class HeroOfTheMonthComponent {
|
||||
logs: string[] = [];
|
||||
|
||||
// #docregion ctor-signature
|
||||
constructor(
|
||||
logger: MinimalLogger,
|
||||
public heroOfTheMonth: Hero,
|
||||
@Inject(RUNNERS_UP) public runnersUp: string,
|
||||
@Inject(TITLE) public title: string)
|
||||
// #enddocregion ctor-signature
|
||||
{
|
||||
this.logs = logger.logs;
|
||||
logger.logInfo('starting up');
|
||||
|
|
|
@ -35,7 +35,6 @@ export function provideTheParent
|
|||
|
||||
|
||||
///////// C - Child //////////
|
||||
// #docregion carol
|
||||
const templateC = `
|
||||
<div class="c">
|
||||
<h3>{{name}}</h3>
|
||||
|
@ -54,7 +53,6 @@ export class CarolComponent {
|
|||
// #enddocregion carol-ctor
|
||||
}
|
||||
// #enddocregion carol-class
|
||||
// #enddocregion carol
|
||||
|
||||
@Component({
|
||||
selector: 'chris',
|
||||
|
@ -132,7 +130,7 @@ export class BethComponent implements Parent {
|
|||
|
||||
///////// A - Grandparent //////
|
||||
|
||||
// #docregion alex, alex-1
|
||||
// #docregion alex-1
|
||||
@Component({
|
||||
selector: 'alex',
|
||||
template: `
|
||||
|
@ -157,11 +155,10 @@ export class AlexComponent extends Base
|
|||
{
|
||||
name = 'Alex';
|
||||
}
|
||||
// #enddocregion alex, alex-1
|
||||
// #enddocregion alex-1
|
||||
|
||||
/////
|
||||
|
||||
// #docregion alice
|
||||
@Component({
|
||||
selector: 'alice',
|
||||
template: `
|
||||
|
@ -182,7 +179,6 @@ export class AliceComponent implements Parent
|
|||
{
|
||||
name = 'Alice';
|
||||
}
|
||||
// #enddocregion alice
|
||||
|
||||
////// Cathy ///////////
|
||||
/**
|
||||
|
|
|
@ -5,9 +5,7 @@ import { InjectionToken } from '@angular/core';
|
|||
import { Hero } from './hero';
|
||||
import { HeroService } from './hero.service';
|
||||
|
||||
// #docregion runners-up
|
||||
export const RUNNERS_UP = new InjectionToken<string>('RunnersUp');
|
||||
// #enddocregion runners-up
|
||||
|
||||
// #docregion factory-synopsis
|
||||
export function runnersUpFactory(take: number) {
|
||||
|
|
|
@ -6,7 +6,7 @@ import { Hero } from './hero';
|
|||
import { HeroService } from './hero.service';
|
||||
|
||||
/////// HeroesBaseComponent /////
|
||||
// #docregion heroes-base, injection
|
||||
// #docregion heroes-base
|
||||
@Component({
|
||||
selector: 'app-unsorted-heroes',
|
||||
template: `<div *ngFor="let hero of heroes">{{hero.name}}</div>`,
|
||||
|
@ -14,7 +14,6 @@ import { HeroService } from './hero.service';
|
|||
})
|
||||
export class HeroesBaseComponent implements OnInit {
|
||||
constructor(private heroService: HeroService) { }
|
||||
// #enddocregion injection
|
||||
|
||||
heroes: Array<Hero>;
|
||||
|
||||
|
@ -26,9 +25,8 @@ export class HeroesBaseComponent implements OnInit {
|
|||
// Post-process heroes in derived class override.
|
||||
protected afterGetHeroes() {}
|
||||
|
||||
// #docregion injection
|
||||
}
|
||||
// #enddocregion heroes-base,injection
|
||||
// #enddocregion heroes-base
|
||||
|
||||
/////// SortedHeroesComponent /////
|
||||
// #docregion sorted-heroes
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
// #docregion
|
||||
import { Inject, Injectable, InjectionToken } from '@angular/core';
|
||||
|
||||
// #docregion storage-token
|
||||
export const BROWSER_STORAGE = new InjectionToken<Storage>('Browser Storage', {
|
||||
providedIn: 'root',
|
||||
factory: () => localStorage
|
||||
});
|
||||
// #enddocregion storage-token
|
||||
|
||||
// #docregion inject-storage-token
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
|
@ -31,4 +27,3 @@ export class BrowserStorageService {
|
|||
this.storage.clear();
|
||||
}
|
||||
}
|
||||
// #enddocregion inject-storage-token
|
||||
|
|
|
@ -1,27 +1,19 @@
|
|||
// #docplaster
|
||||
// #docregion
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { LoggerService } from './logger.service';
|
||||
import { UserService } from './user.service';
|
||||
|
||||
// #docregion injectables, injectable
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UserContextService {
|
||||
// #enddocregion injectables, injectable
|
||||
name: string;
|
||||
role: string;
|
||||
loggedInSince: Date;
|
||||
|
||||
// #docregion ctor, injectables
|
||||
constructor(private userService: UserService, private loggerService: LoggerService) {
|
||||
// #enddocregion ctor, injectables
|
||||
this.loggedInSince = new Date();
|
||||
// #docregion ctor, injectables
|
||||
}
|
||||
// #enddocregion ctor, injectables
|
||||
|
||||
loadUser(userId: number) {
|
||||
const user = this.userService.getUserById(userId);
|
||||
|
@ -30,6 +22,4 @@ export class UserContextService {
|
|||
|
||||
this.loggerService.logDebug('loaded User');
|
||||
}
|
||||
// #docregion injectables, injectable
|
||||
}
|
||||
// #enddocregion injectables, injectable
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
// #docregion
|
||||
// #docregion imports
|
||||
import { Component, Inject } from '@angular/core';
|
||||
|
||||
import { APP_CONFIG, AppConfig } from './app.config';
|
||||
// #enddocregion imports
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
|
@ -22,5 +19,3 @@ export class AppComponent {
|
|||
}
|
||||
// #enddocregion ctor
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
// #docplaster
|
||||
// #docregion
|
||||
// #docregion imports
|
||||
import { Component, Inject } from '@angular/core';
|
||||
|
||||
import { APP_CONFIG, AppConfig } from './app.config';
|
||||
import { UserService } from './user.service';
|
||||
// #enddocregion imports
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
|
@ -28,13 +24,11 @@ import { UserService } from './user.service';
|
|||
export class AppComponent {
|
||||
title: string;
|
||||
|
||||
// #docregion ctor
|
||||
constructor(
|
||||
@Inject(APP_CONFIG) config: AppConfig,
|
||||
private userService: UserService) {
|
||||
this.title = config.title;
|
||||
}
|
||||
// #enddocregion ctor
|
||||
|
||||
get isAuthorized() { return this.user.isAuthorized; }
|
||||
nextUser() { this.userService.getNewUser(); }
|
||||
|
|
|
@ -15,7 +15,6 @@ import { UserService } from './user.service';
|
|||
|
||||
import { ProvidersModule } from './providers.module';
|
||||
|
||||
// #docregion ngmodule
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
@ -25,14 +24,12 @@ import { ProvidersModule } from './providers.module';
|
|||
AppComponent,
|
||||
CarComponent,
|
||||
HeroesComponent,
|
||||
// #enddocregion ngmodule
|
||||
HeroesTspComponent,
|
||||
HeroListComponent,
|
||||
InjectorComponent,
|
||||
TestComponent
|
||||
// #docregion ngmodule
|
||||
],
|
||||
// #docregion providers, providers-2
|
||||
// #docregion providers
|
||||
providers: [
|
||||
// #enddocregion providers
|
||||
Logger,
|
||||
|
@ -40,7 +37,7 @@ import { ProvidersModule } from './providers.module';
|
|||
UserService,
|
||||
{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }
|
||||
],
|
||||
// #enddocregion providers, providers-2
|
||||
// #enddocregion providers
|
||||
exports: [ CarComponent, HeroesComponent ],
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
|
|
|
@ -1,47 +1,36 @@
|
|||
// Examples with car and engine variations
|
||||
|
||||
// #docplaster
|
||||
import { Car, Engine, Tires } from './car';
|
||||
|
||||
///////// example 1 ////////////
|
||||
export function simpleCar() {
|
||||
// #docregion car-ctor-instantiation
|
||||
// Simple car with 4 cylinders and Flintstone tires.
|
||||
const car = new Car(new Engine(), new Tires());
|
||||
// #enddocregion car-ctor-instantiation
|
||||
car.description = 'Simple';
|
||||
return car;
|
||||
}
|
||||
|
||||
|
||||
///////// example 2 ////////////
|
||||
// #docregion car-ctor-instantiation-with-param
|
||||
class Engine2 {
|
||||
constructor(public cylinders: number) { }
|
||||
}
|
||||
// #enddocregion car-ctor-instantiation-with-param
|
||||
|
||||
export function superCar() {
|
||||
// #docregion car-ctor-instantiation-with-param
|
||||
// Super car with 12 cylinders and Flintstone tires.
|
||||
const bigCylinders = 12;
|
||||
const car = new Car(new Engine2(bigCylinders), new Tires());
|
||||
// #enddocregion car-ctor-instantiation-with-param
|
||||
car.description = 'Super';
|
||||
return car;
|
||||
}
|
||||
|
||||
/////////// example 3 //////////
|
||||
// #docregion car-ctor-instantiation-with-mocks
|
||||
class MockEngine extends Engine { cylinders = 8; }
|
||||
class MockTires extends Tires { make = 'YokoGoodStone'; }
|
||||
|
||||
// #enddocregion car-ctor-instantiation-with-mocks
|
||||
export function testCar() {
|
||||
// #docregion car-ctor-instantiation-with-mocks
|
||||
// Test car with 8 cylinders and YokoGoodStone tires.
|
||||
const car = new Car(new MockEngine(), new MockTires());
|
||||
// #enddocregion car-ctor-instantiation-with-mocks
|
||||
car.description = 'Test';
|
||||
return car;
|
||||
}
|
||||
|
|
|
@ -3,21 +3,16 @@ import { Injector } from '@angular/core';
|
|||
import { Car, Engine, Tires } from './car';
|
||||
import { Logger } from '../logger.service';
|
||||
|
||||
// #docregion injector
|
||||
export function useInjector() {
|
||||
let injector: Injector;
|
||||
// #enddocregion injector
|
||||
/*
|
||||
// #docregion injector-no-new
|
||||
// Cannot instantiate an Injector like this!
|
||||
let injector = new Injector([
|
||||
{ provide: Car, deps: [Engine, Tires] },
|
||||
{ provide: Engine, deps: [] },
|
||||
{ provide: Tires, deps: [] }
|
||||
]);
|
||||
// #enddocregion injector-no-new
|
||||
*/
|
||||
// #docregion injector, injector-create-and-call
|
||||
injector = Injector.create({
|
||||
providers: [
|
||||
{ provide: Car, deps: [Engine, Tires] },
|
||||
|
@ -25,9 +20,7 @@ export function useInjector() {
|
|||
{ provide: Tires, deps: [] }
|
||||
]
|
||||
});
|
||||
// #docregion injector-call
|
||||
const car = injector.get(Car);
|
||||
// #enddocregion injector-call, injector-create-and-call
|
||||
car.description = 'Injector';
|
||||
|
||||
injector = Injector.create({
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
// Car without DI
|
||||
import { Engine, Tires } from './car';
|
||||
|
||||
// #docregion car
|
||||
export class Car {
|
||||
|
||||
// #docregion car-ctor
|
||||
public engine: Engine;
|
||||
public tires: Tires;
|
||||
public description = 'No DI';
|
||||
|
@ -13,7 +11,6 @@ export class Car {
|
|||
this.engine = new Engine();
|
||||
this.tires = new Tires();
|
||||
}
|
||||
// #enddocregion car-ctor
|
||||
|
||||
// Method using the engine and tires
|
||||
drive() {
|
||||
|
@ -21,4 +18,3 @@ export class Car {
|
|||
`${this.engine.cylinders} cylinders and ${this.tires.make} tires.`;
|
||||
}
|
||||
}
|
||||
// #enddocregion car
|
||||
|
|
|
@ -11,11 +11,9 @@ export class Tires {
|
|||
|
||||
@Injectable()
|
||||
export class Car {
|
||||
// #docregion car-ctor
|
||||
public description = 'DI';
|
||||
|
||||
constructor(public engine: Engine, public tires: Tires) { }
|
||||
// #enddocregion car-ctor
|
||||
|
||||
// Method using the engine and tires
|
||||
drive() {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
import { HEROES } from './mock-heroes';
|
||||
|
||||
|
@ -10,8 +9,6 @@ import { HEROES } from './mock-heroes';
|
|||
</div>
|
||||
`
|
||||
})
|
||||
// #docregion class
|
||||
export class HeroListComponent {
|
||||
heroes = HEROES;
|
||||
}
|
||||
// #enddocregion class
|
||||
|
|
|
@ -22,9 +22,7 @@ import { HeroService } from './hero.service';
|
|||
export class HeroListComponent {
|
||||
heroes: Hero[];
|
||||
|
||||
// #docregion ctor
|
||||
constructor(heroService: HeroService) {
|
||||
this.heroes = heroService.getHeroes();
|
||||
}
|
||||
// #enddocregion ctor
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// #docregion
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HEROES } from './mock-heroes';
|
||||
import { Logger } from '../logger.service';
|
||||
|
@ -8,9 +7,7 @@ import { Logger } from '../logger.service';
|
|||
})
|
||||
export class HeroService {
|
||||
|
||||
// #docregion ctor
|
||||
constructor(private logger: Logger) { }
|
||||
// #enddocregion ctor
|
||||
|
||||
getHeroes() {
|
||||
this.logger.log('Getting heroes ...');
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Injectable } from '@angular/core';
|
|||
import { HEROES } from './mock-heroes';
|
||||
|
||||
@Injectable({
|
||||
// we declare that this service should be created
|
||||
// declares that this service should be created
|
||||
// by the root application injector.
|
||||
providedIn: 'root',
|
||||
})
|
||||
|
|
|
@ -1,16 +1,10 @@
|
|||
// #docplaster
|
||||
// #docregion, v1
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
// #enddocregion v1
|
||||
import { HeroService } from './hero.service';
|
||||
|
||||
// #docregion v1
|
||||
@Component({
|
||||
selector: 'app-heroes',
|
||||
// #enddocregion v1
|
||||
providers: [ HeroService ],
|
||||
// #docregion v1
|
||||
template: `
|
||||
<h2>Heroes</h2>
|
||||
<app-hero-list></app-hero-list>
|
||||
|
|
|
@ -8,7 +8,6 @@ import { HeroService } from './heroes/hero.service';
|
|||
import { heroServiceProvider } from './heroes/hero.service.provider';
|
||||
import { Logger } from './logger.service';
|
||||
|
||||
// #docregion injector
|
||||
@Component({
|
||||
selector: 'app-injectors',
|
||||
template: `
|
||||
|
@ -40,7 +39,6 @@ export class InjectorComponent implements OnInit {
|
|||
return this.injector.get(ROUS, rousDontExist);
|
||||
}
|
||||
}
|
||||
// #enddocregion injector
|
||||
|
||||
/**
|
||||
* R.O.U.S. - Rodents Of Unusual Size
|
||||
|
|
|
@ -19,9 +19,9 @@ const template = '{{log}}';
|
|||
@Component({
|
||||
selector: 'provider-1',
|
||||
template,
|
||||
// #docregion providers-1, providers-logger
|
||||
// #docregion providers-logger
|
||||
providers: [Logger]
|
||||
// #enddocregion providers-1, providers-logger
|
||||
// #enddocregion providers-logger
|
||||
})
|
||||
export class Provider1Component {
|
||||
log: string;
|
||||
|
@ -114,11 +114,9 @@ export class OldLogger {
|
|||
selector: 'provider-6a',
|
||||
template,
|
||||
providers:
|
||||
// #docregion providers-6a
|
||||
[ NewLogger,
|
||||
// Not aliased! Creates two instances of `NewLogger`
|
||||
{ provide: OldLogger, useClass: NewLogger}]
|
||||
// #enddocregion providers-6a
|
||||
})
|
||||
export class Provider6aComponent {
|
||||
log: string;
|
||||
|
@ -193,9 +191,7 @@ export class Provider8Component {
|
|||
// must be true else this component would have blown up at runtime
|
||||
log = 'Hero service injected successfully via heroServiceProvider';
|
||||
|
||||
// #docregion provider-8-ctor
|
||||
constructor(heroService: HeroService) { }
|
||||
// #enddocregion provider-8-ctor
|
||||
}
|
||||
|
||||
/////////////////
|
||||
|
@ -221,9 +217,7 @@ export class Provider9Component implements OnInit {
|
|||
constructor(private config: AppConfig){ }
|
||||
// #enddocregion provider-9-ctor-interface
|
||||
*/
|
||||
// #docregion provider-9-ctor
|
||||
constructor(@Inject(APP_CONFIG) private config: AppConfig) { }
|
||||
// #enddocregion provider-9-ctor
|
||||
|
||||
ngOnInit() {
|
||||
this.log = 'APP_CONFIG Application title is ' + this.config.title;
|
||||
|
@ -233,9 +227,7 @@ export class Provider9Component implements OnInit {
|
|||
//////////////////////////////////////////
|
||||
// Sample providers 1 to 7 illustrate a required logger dependency.
|
||||
// Optional logger, can be null
|
||||
// #docregion import-optional
|
||||
import { Optional } from '@angular/core';
|
||||
// #enddocregion import-optional
|
||||
|
||||
const someMessage = 'Hello from the injected logger';
|
||||
|
||||
|
@ -246,13 +238,11 @@ const someMessage = 'Hello from the injected logger';
|
|||
})
|
||||
export class Provider10Component implements OnInit {
|
||||
log: string;
|
||||
// #docregion provider-10-ctor
|
||||
constructor(@Optional() private logger?: Logger) {
|
||||
if (this.logger) {
|
||||
this.logger.log(someMessage);
|
||||
}
|
||||
}
|
||||
// #enddocregion provider-10-ctor
|
||||
|
||||
ngOnInit() {
|
||||
this.log = this.logger ? this.logger.logs[0] : 'Optional logger was not available';
|
||||
|
|
|
@ -22,7 +22,6 @@ export class TestComponent {
|
|||
/////////////////////////////////////
|
||||
function runTests() {
|
||||
|
||||
// #docregion spec
|
||||
const expectedHeroes = [{name: 'A'}, {name: 'B'}]
|
||||
const mockService = <HeroService> {getHeroes: () => expectedHeroes }
|
||||
|
||||
|
@ -31,7 +30,6 @@ function runTests() {
|
|||
const component = new HeroListComponent(mockService);
|
||||
expect(component.heroes.length).toEqual(expectedHeroes.length);
|
||||
});
|
||||
// #enddocregion spec
|
||||
|
||||
return testResults;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,4 @@ if (environment.production) {
|
|||
enableProdMode();
|
||||
}
|
||||
|
||||
// #docregion bootstrap
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
// #enddocregion bootstrap
|
||||
|
|
|
@ -7,7 +7,6 @@ import { Component } from '@angular/core';
|
|||
<h2>My favorite hero is: {{myHero}}</h2>
|
||||
`
|
||||
})
|
||||
// #docregion class
|
||||
export class AppComponent {
|
||||
title: string;
|
||||
myHero: string;
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
// #docregion template
|
||||
template: `
|
||||
<h1>{{title}}</h1>
|
||||
<h2>My favorite hero is: {{myHero}}</h2>
|
||||
`
|
||||
// #enddocregion template
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'Tour of Heroes';
|
||||
|
|
|
@ -1,24 +1,18 @@
|
|||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
// #docregion template
|
||||
template: `
|
||||
<h1>{{title}}</h1>
|
||||
<h2>My favorite hero is: {{myHero}}</h2>
|
||||
<p>Heroes:</p>
|
||||
<ul>
|
||||
// #docregion li
|
||||
<li *ngFor="let hero of heroes">
|
||||
{{ hero }}
|
||||
</li>
|
||||
// #enddocregion li
|
||||
</ul>
|
||||
`
|
||||
// #enddocregion template
|
||||
})
|
||||
// #docregion class
|
||||
export class AppComponent {
|
||||
title = 'Tour of Heroes';
|
||||
heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
// #docregion import
|
||||
import { Hero } from './hero';
|
||||
// #enddocregion import
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
// #docregion template
|
||||
template: `
|
||||
<h1>{{title}}</h1>
|
||||
<h2>My favorite hero is: {{myHero.name}}</h2>
|
||||
|
@ -18,12 +14,9 @@ import { Hero } from './hero';
|
|||
</li>
|
||||
</ul>
|
||||
`
|
||||
// #enddocregion template
|
||||
})
|
||||
// #docregion class
|
||||
export class AppComponent {
|
||||
title = 'Tour of Heroes';
|
||||
// #docregion heroes
|
||||
heroes = [
|
||||
new Hero(1, 'Windstorm'),
|
||||
new Hero(13, 'Bombasto'),
|
||||
|
@ -31,5 +24,4 @@ export class AppComponent {
|
|||
new Hero(20, 'Tornado')
|
||||
];
|
||||
myHero = this.heroes[0];
|
||||
// #enddocregion heroes
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// #docplaster
|
||||
// #docregion final
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { Hero } from './hero';
|
||||
|
@ -15,9 +13,7 @@ import { Hero } from './hero';
|
|||
{{ hero.name }}
|
||||
</li>
|
||||
</ul>
|
||||
// #docregion message
|
||||
<p *ngIf="heroes.length > 3">There are many heroes!</p>
|
||||
// #enddocregion message
|
||||
`
|
||||
})
|
||||
export class AppComponent {
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
// #docregion
|
||||
export class Hero {
|
||||
constructor(
|
||||
// #docregion id
|
||||
public id: number,
|
||||
// #enddocregion id
|
||||
public name: string) { }
|
||||
}
|
||||
// #enddocregion
|
||||
|
|
|
@ -7,10 +7,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
|
||||
<!-- #docregion body -->
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
<!-- #enddocregion body -->
|
||||
|
||||
</html>
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
<!-- #docplaster -->
|
||||
<!-- #docregion -->
|
||||
<h1>{{title}}</h1>
|
||||
<h2>My Heroes</h2>
|
||||
<ul class="heroes">
|
||||
|
@ -14,8 +12,6 @@
|
|||
<div><label>id: </label>{{selectedHero.id}}</div>
|
||||
<div>
|
||||
<label>name: </label>
|
||||
<!-- #docregion selected-hero -->
|
||||
<input [(ngModel)]="selectedHero.name" placeholder="name"/>
|
||||
<!-- #enddocregion selected-hero -->
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// #docregion
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { AppComponent } from './app.component';
|
||||
|
@ -16,9 +15,7 @@ import { AdService } from './ad.service';
|
|||
HeroJobAdComponent,
|
||||
HeroProfileComponent,
|
||||
AdDirective ],
|
||||
// #docregion entry-components
|
||||
entryComponents: [ HeroJobAdComponent, HeroProfileComponent ],
|
||||
// #enddocregion entry-components
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
export class AppModule {
|
||||
|
|
|
@ -2,13 +2,9 @@
|
|||
|
||||
<div class="group">
|
||||
<h3>Target event</h3>
|
||||
<!-- #docregion event-binding-1 -->
|
||||
<button (click)="onSave($event)">Save</button>
|
||||
<!-- #enddocregion event-binding-1 -->
|
||||
|
||||
<!-- #docregion event-binding-2 -->
|
||||
<button on-click="onSave($event)">on-click Save</button>
|
||||
<!-- #enddocregion event-binding-2 -->
|
||||
|
||||
<!-- #docregion custom-directive -->
|
||||
<h4>myClick is an event on the custom ClickDirective:</h4>
|
||||
|
@ -24,9 +20,9 @@
|
|||
|
||||
<!-- #docregion event-binding-3-->
|
||||
<input [value]="currentItem.name"
|
||||
(input)="currentItem.name=$event.target.value" >
|
||||
without NgModel
|
||||
(input)="currentItem.name=getValue($event.target)">
|
||||
<!-- #enddocregion event-binding-3-->
|
||||
without NgModel
|
||||
</div>
|
||||
|
||||
<div class="group">
|
||||
|
|
|
@ -11,7 +11,7 @@ export class AppComponent {
|
|||
currentItem = { name: 'teapot'} ;
|
||||
clickMessage = '';
|
||||
|
||||
onSave(event?: KeyboardEvent) {
|
||||
onSave(event?: MouseEvent) {
|
||||
const evtMsg = event ? ' Event target is ' + (event.target as HTMLElement).textContent : '';
|
||||
alert('Saved.' + evtMsg);
|
||||
if (event) { event.stopPropagation(); }
|
||||
|
@ -21,9 +21,14 @@ export class AppComponent {
|
|||
alert(`Delete the ${item.name}.`);
|
||||
}
|
||||
|
||||
onClickMe(event?: KeyboardEvent) {
|
||||
onClickMe(event?: MouseEvent) {
|
||||
const evtMsg = event ? ' Event target class is ' + (event.target as HTMLElement).className : '';
|
||||
alert('Click me.' + evtMsg);
|
||||
}
|
||||
|
||||
// #docregion getValue
|
||||
getValue(target: EventTarget): string {
|
||||
return (target as HTMLInputElement).value;
|
||||
}
|
||||
// #enddocregion getValue
|
||||
}
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
// #docplaster
|
||||
// #docregion customer-dashboard
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
// #enddocregion customer-dashboard
|
||||
// #docregion customer-dashboard-component
|
||||
// import the new component
|
||||
import { CustomerDashboardComponent } from './customer-dashboard/customer-dashboard.component';
|
||||
// #enddocregion customer-dashboard-component
|
||||
|
||||
|
||||
// #docregion customer-dashboard-component
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule
|
||||
|
@ -28,7 +23,4 @@ import { CustomerDashboardComponent } from './customer-dashboard/customer-dashbo
|
|||
|
||||
// #enddocregion customer-dashboard-component
|
||||
|
||||
// #docregion customer-dashboard
|
||||
export class CustomerDashboardModule { }
|
||||
|
||||
// #enddocregion customer-dashboard
|
||||
|
|
|
@ -20,7 +20,6 @@ export class HeroFormReactiveComponent implements OnInit {
|
|||
heroForm: FormGroup;
|
||||
|
||||
ngOnInit(): void {
|
||||
// #docregion async-validation
|
||||
this.heroForm = new FormGroup({
|
||||
name: new FormControl(this.hero.name, [
|
||||
Validators.required,
|
||||
|
@ -33,7 +32,6 @@ export class HeroFormReactiveComponent implements OnInit {
|
|||
}),
|
||||
power: new FormControl(this.hero.power, Validators.required)
|
||||
});
|
||||
// #enddocregion async-validation
|
||||
}
|
||||
|
||||
get name() { return this.heroForm.get('name'); }
|
||||
|
@ -42,7 +40,5 @@ export class HeroFormReactiveComponent implements OnInit {
|
|||
|
||||
get alterEgo() { return this.heroForm.get('alterEgo'); }
|
||||
|
||||
// #docregion async-validation
|
||||
constructor(private alterEgoValidator: UniqueAlterEgoValidator) {}
|
||||
// #enddocregion async-validation
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* #docregion cross-validation-error-css */
|
||||
.cross-validation-error input {
|
||||
border-left: 5px solid red;
|
||||
}
|
||||
/* #enddocregion cross-validation-error-css */
|
|
@ -25,7 +25,6 @@ export class UniqueAlterEgoValidator implements AsyncValidator {
|
|||
}
|
||||
// #enddocregion async-validator
|
||||
|
||||
// #docregion async-validator-directive
|
||||
@Directive({
|
||||
selector: '[appUniqueAlterEgo]',
|
||||
providers: [
|
||||
|
@ -43,4 +42,3 @@ export class UniqueAlterEgoValidatorDirective {
|
|||
this.validator.validate(control);
|
||||
}
|
||||
}
|
||||
// #enddocregion async-validator-directive
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// #docregion
|
||||
import { Directive, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { AbstractControl, NG_VALIDATORS, Validator, ValidatorFn, Validators } from '@angular/forms';
|
||||
import { Directive, Input } from '@angular/core';
|
||||
import { AbstractControl, NG_VALIDATORS, ValidationErrors, Validator, ValidatorFn } from '@angular/forms';
|
||||
|
||||
// #docregion custom-validator
|
||||
/** A hero's name can't match the given regular expression */
|
||||
|
@ -22,7 +22,7 @@ export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
|
|||
export class ForbiddenValidatorDirective implements Validator {
|
||||
@Input('appForbiddenName') forbiddenName: string;
|
||||
|
||||
validate(control: AbstractControl): {[key: string]: any} | null {
|
||||
validate(control: AbstractControl): ValidationErrors | null {
|
||||
return this.forbiddenName ? forbiddenNameValidator(new RegExp(this.forbiddenName, 'i'))(control)
|
||||
: null;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { AbstractControl, FormGroup, NG_VALIDATORS, ValidationErrors, Validator,
|
|||
|
||||
// #docregion cross-validation-validator
|
||||
/** A hero's name can't match the hero's alter ego */
|
||||
export const identityRevealedValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {
|
||||
export const identityRevealedValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
|
||||
const name = control.get('name');
|
||||
const alterEgo = control.get('alterEgo');
|
||||
|
||||
|
|
|
@ -35,13 +35,11 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label for="alterEgo">Alter Ego</label>
|
||||
<!-- #docregion async-validation -->
|
||||
<input id="alterEgo" class="form-control" name="alterEgo"
|
||||
#alterEgo="ngModel"
|
||||
[(ngModel)]="hero.alterEgo"
|
||||
[ngModelOptions]="{ updateOn: 'blur' }"
|
||||
appUniqueAlterEgo>
|
||||
<!-- #enddocregion async-validation -->
|
||||
|
||||
<div *ngIf="alterEgo.pending">Validating...</div>
|
||||
<div *ngIf="alterEgo.invalid" class="alert alert-danger alter-ego-errors">
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
/* tslint:disable: member-ordering */
|
||||
// #docplaster
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
// #docregion component
|
||||
@Component({
|
||||
selector: 'app-hero-form-template',
|
||||
templateUrl: './hero-form-template.component.html',
|
||||
|
@ -16,4 +13,3 @@ export class HeroFormTemplateComponent {
|
|||
hero = {name: 'Dr.', alterEgo: 'Dr. What', power: this.powers[0]};
|
||||
|
||||
}
|
||||
// #enddocregion
|
||||
|
|
|
@ -102,7 +102,6 @@
|
|||
|
||||
<!-- ==================================================== -->
|
||||
<hr>
|
||||
<!-- #docregion phase1-->
|
||||
<style>
|
||||
.no-style .ng-valid {
|
||||
border-left: 1px solid #CCC
|
||||
|
@ -113,7 +112,6 @@
|
|||
}
|
||||
</style>
|
||||
<div class="no-style" style="margin-left: 4px">
|
||||
<!-- #docregion start -->
|
||||
<div class="container">
|
||||
<h1>Hero Form</h1>
|
||||
<form>
|
||||
|
@ -127,7 +125,6 @@
|
|||
<input type="text" class="form-control" id="alterEgo">
|
||||
</div>
|
||||
|
||||
<!-- #enddocregion start -->
|
||||
<!-- #docregion powers -->
|
||||
<div class="form-group">
|
||||
<label for="power">Hero Power</label>
|
||||
|
@ -137,17 +134,13 @@
|
|||
</div>
|
||||
|
||||
<!-- #enddocregion powers -->
|
||||
<!-- #docregion start -->
|
||||
<button type="submit" class="btn btn-success">Submit</button>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<!-- #enddocregion start -->
|
||||
<!-- #enddocregion phase1-->
|
||||
|
||||
<!-- ==================================================== -->
|
||||
<hr>
|
||||
<!-- #docregion phase2-->
|
||||
<div class="container">
|
||||
<h1>Hero Form</h1>
|
||||
<!-- #docregion template-variable-->
|
||||
|
@ -182,7 +175,6 @@
|
|||
|
||||
</form>
|
||||
</div>
|
||||
<!-- #enddocregion phase2-->
|
||||
|
||||
<!-- EXTRA MATERIAL FOR DOCUMENTATION -->
|
||||
<hr>
|
||||
|
@ -193,11 +185,9 @@
|
|||
TODO: remove this: {{model.name}}
|
||||
<!-- #enddocregion ngModelName-1 -->
|
||||
<hr>
|
||||
<!-- #docregion ngModel-3-->
|
||||
<input type="text" class="form-control" id="name"
|
||||
required
|
||||
[ngModel]="model.name" name="name"
|
||||
(ngModelChange)="model.name = $event">
|
||||
TODO: remove this: {{model.name}}
|
||||
<!-- #enddocregion ngModel-3-->
|
||||
</div>
|
||||
|
|
|
@ -49,9 +49,7 @@ export class HeroFormComponent {
|
|||
// Name via form.controls = {{showFormControls(heroForm)}}
|
||||
showFormControls(form: any) {
|
||||
return form && form.controls.name &&
|
||||
// #docregion form-controls
|
||||
form.controls.name.value; // Dr. IQ
|
||||
// #enddocregion form-controls
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
|
|
|
@ -7,10 +7,8 @@
|
|||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- #docregion bootstrap -->
|
||||
<link rel="stylesheet"
|
||||
href="https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css">
|
||||
<!-- #enddocregion bootstrap -->
|
||||
<!-- #docregion styles -->
|
||||
<link rel="stylesheet" href="assets/forms.css">
|
||||
<!-- #enddocregion styles -->
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
p {
|
||||
font-family: Lato;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Component } from '@angular/core';
|
|||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: [ './app.component.css' ]
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent {}
|
||||
export class AppComponent {
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ import { ProductListComponent } from './product-list/product-list.component';
|
|||
TopBarComponent,
|
||||
ProductListComponent
|
||||
],
|
||||
bootstrap: [ AppComponent ]
|
||||
bootstrap: [
|
||||
AppComponent
|
||||
]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
export const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Phone XL',
|
||||
price: 799,
|
||||
description: 'A large phone with one of the best screens'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Phone Mini',
|
||||
price: 699,
|
||||
description: 'A great phone with one of the best cameras'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Phone Standard',
|
||||
price: 299,
|
||||
description: ''
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-top-bar',
|
||||
templateUrl: './top-bar.component.html',
|
||||
styleUrls: ['./top-bar.component.css']
|
||||
})
|
||||
export class TopBarComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
export class TopBarComponent {
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.error(err));
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
// #docplaster
|
||||
// #docregion
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
// #docregion v1
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
// #docplaster
|
||||
// #docregion import-http
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
// #enddocregion import-http
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
// #docregion props, methods, inject-http, get-shipping
|
||||
export class CartService {
|
||||
// #enddocregion get-shipping
|
||||
items = [];
|
||||
// #enddocregion props, methods
|
||||
|
||||
|
@ -32,8 +33,10 @@ export class CartService {
|
|||
}
|
||||
// #enddocregion methods
|
||||
|
||||
// #docregion get-shipping
|
||||
getShippingPrices() {
|
||||
return this.http.get('/assets/shipping.json');
|
||||
return this.http.get<{type: string, price: number}[]>('/assets/shipping.json');
|
||||
}
|
||||
// #docregion props, methods, inject-http
|
||||
}
|
||||
// #enddocregion props, methods, inject-http
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-cart',
|
||||
templateUrl: './cart.component.html',
|
||||
styleUrls: ['./cart.component.css']
|
||||
})
|
||||
export class CartComponent implements OnInit {
|
||||
export class CartComponent {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,10 +9,10 @@ import { CartService } from '../cart.service';
|
|||
templateUrl: './cart.component.html',
|
||||
styleUrls: ['./cart.component.css']
|
||||
})
|
||||
// #docregion inject-cart, items, submit
|
||||
// #docregion inject-cart, items
|
||||
export class CartComponent {
|
||||
// #enddocregion inject-cart
|
||||
items;
|
||||
items = this.cartService.getItems();
|
||||
// #docregion inject-cart
|
||||
|
||||
constructor(
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
// #docplaster
|
||||
// #docregion imports
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { CartService } from '../cart.service';
|
||||
// #enddocregion imports
|
||||
|
||||
@Component({
|
||||
selector: 'app-cart',
|
||||
templateUrl: './cart.component.html',
|
||||
styleUrls: ['./cart.component.css']
|
||||
})
|
||||
// #docregion props-services, submit
|
||||
export class CartComponent implements OnInit {
|
||||
items;
|
||||
|
||||
|
@ -17,7 +13,7 @@ export class CartComponent implements OnInit {
|
|||
private cartService: CartService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
ngOnInit(): void {
|
||||
this.items = this.cartService.getItems();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
</div>
|
||||
|
||||
<!-- #docregion checkout-form-1 -->
|
||||
<form [formGroup]="checkoutForm" (ngSubmit)="onSubmit(checkoutForm.value)">
|
||||
<form [formGroup]="checkoutForm" (ngSubmit)="onSubmit()">
|
||||
<!-- #enddocregion checkout-form-1 -->
|
||||
|
||||
<div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// #docplaster
|
||||
// #docregion imports
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
|
||||
import { CartService } from '../cart.service';
|
||||
|
@ -11,38 +11,26 @@ import { CartService } from '../cart.service';
|
|||
templateUrl: './cart.component.html',
|
||||
styleUrls: ['./cart.component.css']
|
||||
})
|
||||
// #docregion props-services, submit, inject-form-builder, checkout-form, checkout-form-group
|
||||
export class CartComponent implements OnInit {
|
||||
items;
|
||||
// #enddocregion inject-form-builder
|
||||
checkoutForm;
|
||||
// #enddocregion checkout-form
|
||||
// #docregion inject-form-builder, checkout-form-group
|
||||
export class CartComponent {
|
||||
// #enddocregion inject-form-builder
|
||||
items = this.cartService.getItems();
|
||||
checkoutForm = this.formBuilder.group({
|
||||
name: '',
|
||||
address: ''
|
||||
});
|
||||
// #docregion inject-form-builder
|
||||
|
||||
constructor(
|
||||
private cartService: CartService,
|
||||
private formBuilder: FormBuilder,
|
||||
) {
|
||||
// #enddocregion inject-form-builder
|
||||
this.checkoutForm = this.formBuilder.group({
|
||||
name: '',
|
||||
address: ''
|
||||
});
|
||||
// #docregion inject-form-builder
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.items = this.cartService.getItems();
|
||||
}
|
||||
) {}
|
||||
// #enddocregion inject-form-builder, checkout-form-group
|
||||
|
||||
// #enddocregion props-services
|
||||
onSubmit(customerData) {
|
||||
onSubmit(): void {
|
||||
// Process checkout data here
|
||||
this.items = this.cartService.clearCart();
|
||||
console.warn('Your order has been submitted', this.checkoutForm.value);
|
||||
this.checkoutForm.reset();
|
||||
|
||||
console.warn('Your order has been submitted', customerData);
|
||||
}
|
||||
// #docregion props-services, inject-form-builder, checkout-form, checkout-form-group
|
||||
// #docregion inject-form-builder, checkout-form-group
|
||||
}
|
||||
|
|
|
@ -11,9 +11,10 @@ import { products } from '../products';
|
|||
templateUrl: './product-details.component.html',
|
||||
styleUrls: ['./product-details.component.css']
|
||||
})
|
||||
// #docregion props-methods, add-to-cart
|
||||
// #docregion props-methods, product-prop
|
||||
export class ProductDetailsComponent implements OnInit {
|
||||
product;
|
||||
// #enddocregion product-prop
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
|
@ -22,10 +23,15 @@ export class ProductDetailsComponent implements OnInit {
|
|||
// #enddocregion props-methods
|
||||
// #docregion get-product
|
||||
ngOnInit() {
|
||||
this.route.paramMap.subscribe(params => {
|
||||
this.product = products[+params.get('productId')];
|
||||
});
|
||||
// First get the product id from the current route.
|
||||
const routeParams = this.route.snapshot.paramMap;
|
||||
const productIdFromRoute = Number(routeParams.get('productId'));
|
||||
|
||||
// Find the product that correspond with the id provided in route.
|
||||
this.product = products.find(product => product.id === productIdFromRoute);
|
||||
}
|
||||
// #enddocregion get-product
|
||||
// #docregion product-prop
|
||||
/* ... */
|
||||
// #docregion props-methods
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
// #docplaster
|
||||
// #docregion imports, cart-service
|
||||
// #docregion cart-service
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { products } from '../products';
|
||||
// #enddocregion imports
|
||||
import { CartService } from '../cart.service';
|
||||
// #enddocregion cart-service
|
||||
|
||||
|
@ -13,34 +12,31 @@ import { CartService } from '../cart.service';
|
|||
templateUrl: './product-details.component.html',
|
||||
styleUrls: ['./product-details.component.css']
|
||||
})
|
||||
// #docregion props-methods, get-product, inject-cart-service, add-to-cart
|
||||
// #docregion inject-cart-service, add-to-cart
|
||||
export class ProductDetailsComponent implements OnInit {
|
||||
// #enddocregion add-to-cart, get-product, inject-cart-service
|
||||
// #enddocregion add-to-cart, inject-cart-service
|
||||
product;
|
||||
|
||||
// #docregion inject-cart-service
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
// #enddocregion props-methods
|
||||
private cartService: CartService
|
||||
// #docregion props-methods
|
||||
) { }
|
||||
// #enddocregion inject-cart-service
|
||||
|
||||
// #docregion get-product
|
||||
ngOnInit() {
|
||||
// #enddocregion props-methods
|
||||
this.route.paramMap.subscribe(params => {
|
||||
this.product = products[+params.get('productId')];
|
||||
});
|
||||
// #docregion props-methods
|
||||
// First get the product id from the current route.
|
||||
const routeParams = this.route.snapshot.paramMap;
|
||||
const productIdFromRoute = Number(routeParams.get('productId'));
|
||||
|
||||
// Find the product that correspond with the id provided in route.
|
||||
this.product = products.find(product => product.id === productIdFromRoute);
|
||||
}
|
||||
|
||||
// #enddocregion props-methods, get-product
|
||||
// #docregion add-to-cart
|
||||
addToCart(product) {
|
||||
this.cartService.addToCart(product);
|
||||
window.alert('Your product has been added to the cart!');
|
||||
}
|
||||
// #docregion props-methods, get-product, inject-cart-service
|
||||
// #docregion inject-cart-service
|
||||
}
|
||||
|
|
|
@ -2,13 +2,11 @@
|
|||
|
||||
<div *ngFor="let product of products">
|
||||
|
||||
<!-- #docregion product-details -->
|
||||
<h3>
|
||||
<a [title]="product.name + ' details'">
|
||||
{{ product.name }}
|
||||
</a>
|
||||
</h3>
|
||||
<!-- #enddocregion product-details -->
|
||||
|
||||
<p *ngIf="product.description">
|
||||
Description: {{ product.description }}
|
||||
|
|
|
@ -1,26 +1,28 @@
|
|||
<h2>Products</h2>
|
||||
|
||||
<!-- #docregion router-link -->
|
||||
<div *ngFor="let product of products; index as productId">
|
||||
<div *ngFor="let product of products">
|
||||
|
||||
<h3>
|
||||
<a [title]="product.name + ' details'" [routerLink]="['/products', productId]">
|
||||
<a [title]="product.name + ' details'" [routerLink]="['/products', product.id]">
|
||||
{{ product.name }}
|
||||
</a>
|
||||
</h3>
|
||||
<!-- #enddocregion router-link -->
|
||||
|
||||
<!-- #enddocregion router-link -->
|
||||
<p *ngIf="product.description">
|
||||
Description: {{ product.description }}
|
||||
</p>
|
||||
|
||||
|
||||
<button (click)="share()">
|
||||
Share
|
||||
</button>
|
||||
|
||||
|
||||
<app-product-alerts
|
||||
[product]="product"
|
||||
(notify)="onNotify()">
|
||||
</app-product-alerts>
|
||||
<!-- #docregion router-link -->
|
||||
<!-- #docregion router-link -->
|
||||
|
||||
</div>
|
||||
<!-- #enddocregion router-link -->
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
export const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Phone XL',
|
||||
price: 799,
|
||||
description: 'A large phone with one of the best screens'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Phone Mini',
|
||||
price: 699,
|
||||
description: 'A great phone with one of the best cameras'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Phone Standard',
|
||||
price: 299,
|
||||
description: ''
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-shipping',
|
||||
templateUrl: './shipping.component.html',
|
||||
styleUrls: ['./shipping.component.css']
|
||||
})
|
||||
export class ShippingComponent implements OnInit {
|
||||
export class ShippingComponent {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// #docplaster
|
||||
// #docregion imports
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { CartService } from '../cart.service';
|
||||
// #enddocregion
|
||||
|
@ -10,21 +10,18 @@ import { CartService } from '../cart.service';
|
|||
templateUrl: './shipping.component.html',
|
||||
styleUrls: ['./shipping.component.css']
|
||||
})
|
||||
// #docregion props, ctor
|
||||
export class ShippingComponent implements OnInit {
|
||||
shippingCosts;
|
||||
// #docregion props
|
||||
export class ShippingComponent {
|
||||
shippingCosts = this.cartService.getShippingPrices();
|
||||
// #enddocregion props
|
||||
|
||||
|
||||
|
||||
// #docregion inject-cart-service
|
||||
constructor(
|
||||
private cartService: CartService
|
||||
) {
|
||||
constructor(private cartService: CartService) {
|
||||
}
|
||||
// #enddocregion inject-cart-service
|
||||
|
||||
ngOnInit() {
|
||||
this.shippingCosts = this.cartService.getShippingPrices();
|
||||
}
|
||||
|
||||
// #docregion props
|
||||
}
|
||||
|
|
|
@ -29,6 +29,26 @@ const checkLogForMessage = async (message: string) => {
|
|||
};
|
||||
|
||||
describe('Http Tests', () => {
|
||||
// It seems that currently Chrome/ChromeDriver fail to click a button that is just outside the
|
||||
// viewport (or maybe only partially inside the viewport) - at least in headless mode.
|
||||
// Possible solutions:
|
||||
// 1. Click the element via JavaScript (with something like
|
||||
// `browser.executeScript('arguments[0].click', elem)`).
|
||||
// 2. Manually scroll the element into view before clicking:
|
||||
// https://stackoverflow.com/questions/47776774/element-is-not-clickable-at-point-in-headless-mode-but-when-we-remove-headless
|
||||
// 3. Explicitly set the window size to a bigger size:
|
||||
// https://stackoverflow.com/questions/62003082/elementnotinteractableexception-element-not-interactable-element-has-zero-size
|
||||
//
|
||||
// Since the default 800x600 window size in headless mode (as used on CI) causes the
|
||||
// `<app-config>` buttons to be in a position that trigger the above issue, we explicitly set the
|
||||
// window size to 1920x1080 when in headless mode.
|
||||
beforeAll(async () => {
|
||||
const config = await browser.getProcessedConfig();
|
||||
if (config.capabilities?.chromeOptions?.args?.includes('--headless')) {
|
||||
browser.driver.manage().window().setSize(1920, 1080);
|
||||
}
|
||||
});
|
||||
|
||||
beforeEach(() => browser.get(''));
|
||||
|
||||
describe('Heroes', () => {
|
||||
|
@ -66,6 +86,7 @@ describe('Http Tests', () => {
|
|||
await checkLogForMessage('GET "assets/config.json"');
|
||||
expect(await page.configSpan.getText()).toContain('Heroes API URL is "api/heroes"');
|
||||
expect(await page.configSpan.getText()).toContain('Textfile URL is "assets/textfile.txt"');
|
||||
expect(await page.configSpan.getText()).toContain('Date is "Wed Jan 29 2020" (date)');
|
||||
});
|
||||
|
||||
it('can fetch the configuration JSON file with headers', async () => {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
<span *ngIf="config">
|
||||
<p>Heroes API URL is "{{config.heroesUrl}}"</p>
|
||||
<p>Textfile URL is "{{config.textfile}}"</p>
|
||||
<p>Date is "{{config.date.toDateString()}}" ({{getType(config.date)}})</p>
|
||||
<div *ngIf="headers">
|
||||
Response headers:
|
||||
<ul>
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
import { Config, ConfigService } from './config.service';
|
||||
import { MessageService } from '../message.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-config',
|
||||
|
@ -25,7 +24,7 @@ export class ConfigComponent {
|
|||
this.headers = undefined;
|
||||
}
|
||||
|
||||
// #docregion v1, v2, v3
|
||||
// #docregion v1, v2
|
||||
showConfig() {
|
||||
this.configService.getConfig()
|
||||
// #enddocregion v1, v2
|
||||
|
@ -34,25 +33,23 @@ export class ConfigComponent {
|
|||
error => this.error = error // error path
|
||||
);
|
||||
}
|
||||
// #enddocregion v3
|
||||
|
||||
showConfig_v1() {
|
||||
this.configService.getConfig_1()
|
||||
// #docregion v1, v1_callback
|
||||
// #docregion v1
|
||||
.subscribe((data: Config) => this.config = {
|
||||
heroesUrl: data.heroesUrl,
|
||||
textfile: data.textfile
|
||||
textfile: data.textfile,
|
||||
date: data.date,
|
||||
});
|
||||
// #enddocregion v1_callback
|
||||
}
|
||||
// #enddocregion v1
|
||||
|
||||
showConfig_v2() {
|
||||
this.configService.getConfig()
|
||||
// #docregion v2, v2_callback
|
||||
// #docregion v2
|
||||
// clone the data object, using its known Config shape
|
||||
.subscribe((data: Config) => this.config = { ...data });
|
||||
// #enddocregion v2_callback
|
||||
}
|
||||
// #enddocregion v2
|
||||
|
||||
|
@ -74,5 +71,9 @@ export class ConfigComponent {
|
|||
makeError() {
|
||||
this.configService.makeIntentionalError().subscribe(null, error => this.error = error );
|
||||
}
|
||||
|
||||
getType(val: any): string {
|
||||
return val instanceof Date ? 'date' : Array.isArray(val) ? 'array' : typeof val;
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
|
|
@ -14,6 +14,7 @@ import { catchError, retry } from 'rxjs/operators';
|
|||
export interface Config {
|
||||
heroesUrl: string;
|
||||
textfile: string;
|
||||
date: any;
|
||||
}
|
||||
// #enddocregion config-interface
|
||||
// #docregion proto
|
||||
|
|
|
@ -57,8 +57,7 @@
|
|||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
cursor: hand;
|
||||
font-family: Arial;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<h3>Heroes</h3>
|
||||
<!-- #docregion add -->
|
||||
<div>
|
||||
<label>Hero name:
|
||||
<input #heroName />
|
||||
|
@ -12,9 +11,7 @@
|
|||
search
|
||||
</button>
|
||||
</div>
|
||||
<!-- #enddocregion add -->
|
||||
|
||||
<!-- #docregion list -->
|
||||
<ul class="heroes">
|
||||
<li *ngFor="let hero of heroes">
|
||||
<a (click)="edit(hero)">
|
||||
|
@ -23,10 +20,7 @@
|
|||
<input *ngIf="hero===editHero" [(ngModel)]="hero.name"
|
||||
(blur)="update()" (keyup.enter)="update()">
|
||||
</a>
|
||||
<!-- #docregion delete -->
|
||||
<button class="delete" title="delete hero"
|
||||
(click)="delete(hero)">x</button>
|
||||
<!-- #enddocregion delete -->
|
||||
</li>
|
||||
</ul>
|
||||
<!-- #enddocregion list -->
|
||||
|
|
|
@ -6,6 +6,7 @@ import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
|||
// #enddocregion interceptor-providers
|
||||
import { AuthInterceptor } from './auth-interceptor';
|
||||
import { CachingInterceptor } from './caching-interceptor';
|
||||
import { CustomJsonInterceptor , CustomJsonParser, JsonParser} from './custom-json-interceptor';
|
||||
import { EnsureHttpsInterceptor } from './ensure-https-interceptor';
|
||||
import { LoggingInterceptor } from './logging-interceptor';
|
||||
// #docregion interceptor-providers
|
||||
|
@ -21,6 +22,10 @@ export const httpInterceptorProviders = [
|
|||
// #docregion noop-provider
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: NoopInterceptor, multi: true },
|
||||
// #enddocregion noop-provider, interceptor-providers
|
||||
// #docregion custom-json-interceptor
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: CustomJsonInterceptor, multi: true },
|
||||
{ provide: JsonParser, useClass: CustomJsonParser },
|
||||
// #enddocregion custom-json-interceptor
|
||||
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: EnsureHttpsInterceptor, multi: true },
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: TrimNameInterceptor, multi: true },
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue