diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/.gitignore b/public/docs/_examples/hierarchical-dependency-injection/ts/.gitignore new file mode 100644 index 0000000000..6724ce3596 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/.gitignore @@ -0,0 +1 @@ +src/**/*.js \ No newline at end of file diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/package.json b/public/docs/_examples/hierarchical-dependency-injection/ts/package.json new file mode 100644 index 0000000000..d82952aa81 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/package.json @@ -0,0 +1,21 @@ +{ + "name": "angular2-getting-started", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "tsc": "tsc -p src -w", + "start": "live-server --open=src" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "angular2": "2.0.0-alpha.46", + "systemjs": "0.19.2" + }, + "devDependencies": { + "live-server": "^0.8.1", + "typescript": "^1.6.2" + } +} diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/edit-item.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/edit-item.ts new file mode 100644 index 0000000000..abbeabf2b0 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/edit-item.ts @@ -0,0 +1,6 @@ +// #docregion +export class EditItem { + editing: boolean + constructor (public item: T) {} +} +// #docregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-card.component.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-card.component.ts new file mode 100644 index 0000000000..e430617320 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-card.component.ts @@ -0,0 +1,16 @@ +// #docregion +import {Component, Input} from 'angular2/angular2'; +import {Hero} from './hero'; + +@Component({ + selector: 'hero-card', + template: ` +
+ Name: + {{hero.name}} +
` +}) +export class HeroCardComponent { + @Input() hero: Hero; +} +// #docregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-editor.component.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-editor.component.ts new file mode 100644 index 0000000000..2c6f6a84db --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-editor.component.ts @@ -0,0 +1,46 @@ +// #docregion +import {Component, Input, Output, EventEmitter} from 'angular2/angular2'; +import {RestoreService} from './restore-service'; +import {Hero} from './hero'; + +@Component({ + selector: 'hero-editor', + // #docregion providers + providers: [RestoreService], + // #enddocregion providers + template: ` +
+ Name: + +
+ + +
+
` +}) + +export class HeroEditorComponent { + @Output() canceled = new EventEmitter(); + @Output() saved = new EventEmitter(); + + constructor(private restoreService: RestoreService) {} + + @Input() + set hero (hero: Hero) { + this.restoreService.setItem(hero); + } + + get hero () { + return this.restoreService.getItem(); + } + + onSaved () { + this.saved.next(this.restoreService.getItem()); + } + + onCanceled () { + this.hero = this.restoreService.restoreItem(); + this.canceled.next(this.hero); + } +} +// #enddocregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero.ts new file mode 100644 index 0000000000..76f808b1c5 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero.ts @@ -0,0 +1,6 @@ +// #docregion +export class Hero { + name: string; + power: string; +} +// #enddocregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/heroes-list.component.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/heroes-list.component.ts new file mode 100644 index 0000000000..9bda26c20c --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/heroes-list.component.ts @@ -0,0 +1,53 @@ +// #docregion +import {Component, bootstrap} from 'angular2/angular2'; +import {EditItem} from './edit-item'; +import {HeroesService} from './heroes-service'; +import {HeroCardComponent} from './hero-card.component'; +import {HeroEditorComponent} from './hero-editor.component'; +import {Hero} from './hero'; + +@Component({ + selector: 'heroes-list', + template: ` +
+
    +
  • + + + + + +
  • +
+
`, + directives: [HeroCardComponent, HeroEditorComponent] +}) +export class HeroesListComponent { + heroes: Array>; + constructor(heroesService: HeroesService) { + this.heroes = heroesService.getHeroes() + .map(item => new EditItem(item)); + } + + onSaved (editItem: EditItem, updatedHero: Hero) { + editItem.item = updatedHero; + editItem.editing = false; + } + + onCanceled (editItem: EditItem) { + editItem.editing = false; + } +} + +bootstrap(HeroesListComponent, [HeroesService]); +// #enddocregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/heroes-service.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/heroes-service.ts new file mode 100644 index 0000000000..e4f9e2d213 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/heroes-service.ts @@ -0,0 +1,12 @@ +import {Hero} from './hero'; + +export class HeroesService { + heroes: Array = [ + { name: "RubberMan", power: 'flexibility'}, + { name: "Tornado", power: 'Weather changer'} + ]; + + getHeroes () { + return this.heroes; + } +} diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/restore-service.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/restore-service.ts new file mode 100644 index 0000000000..c81786b2a3 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/restore-service.ts @@ -0,0 +1,25 @@ +// #docregion +export class RestoreService { + originalItem: T; + currentItem: T; + + setItem (item: T) { + this.originalItem = item; + this.currentItem = this.clone(item); + } + + getItem () :T { + return this.currentItem; + } + + restoreItem () :T { + this.currentItem = this.originalItem; + return this.getItem(); + } + + clone (item: T) :T { + // super poor clone implementation + return JSON.parse(JSON.stringify(item)); + } +} +// #enddocregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/index.html b/public/docs/_examples/hierarchical-dependency-injection/ts/src/index.html new file mode 100644 index 0000000000..7f0313830e --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/index.html @@ -0,0 +1,22 @@ + + + + + Hierarchical Injectors + + + + + + + + loading... + + + + diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/tsconfig.json b/public/docs/_examples/hierarchical-dependency-injection/ts/src/tsconfig.json new file mode 100644 index 0000000000..6a58b35a58 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "ES5", + "module": "commonjs", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "removeComments": false, + "noImplicitAny": false + } +} \ No newline at end of file diff --git a/public/docs/ts/latest/guide/hierarchical-dependency-injection.jade b/public/docs/ts/latest/guide/hierarchical-dependency-injection.jade index 956063326f..f798f7aaed 100644 --- a/public/docs/ts/latest/guide/hierarchical-dependency-injection.jade +++ b/public/docs/ts/latest/guide/hierarchical-dependency-injection.jade @@ -1,3 +1,4 @@ + include ../../../../_includes/_util-fns :marked We learned the basics of Angular Dependency injection in an @@ -91,189 +92,47 @@ figure.image-display Let’s take a look at the `HeroesListComponent` which is the root component for this example. - ``` - import {Component, bootstrap, CORE_DIRECTIVES} from 'angular2/angular2'; - import {HeroService} from './hero.service'; - import {HeroCardComponent} from './hero-card.component'; - import {HeroEditorComponent} from './hero-editor.component'; - import {Hero} from './hero'; - - @Component({ - selector: 'heroes-list-component', - template: ` -
-
    -
  • - - - - - -
  • -
-
`, - directives: [CORE_DIRECTIVES, HeroCardComponent, HeroEditorComponent] - }) - export class HeroesListComponent { - heroes: Array; - constructor(HeroService: HeroService) { - this.heroes = HeroService.getHeroes() - .map(item => new EditItem(item)); - } - - onSaved (editItem: EditItem, updatedHero: Hero) { - editItem.item = updatedHero; - editItem.editing = false; - } - - onCanceled (editItem: EditItem) { - editItem.editing = false; - } - } - - class EditItem { - item: T; - editing: boolean - constructor (public item T) {} - } - - bootstrap(HeroesListComponent, [HeroService]); - ``` ++makeExample('hierarchical-dependency-injection/ts/src/app/heroes-list.component.ts') +:marked Notice that it imports the `HeroService` that we’ve used before so we can skip its declaration. The only difference is that we’ve used a more formal approach for our `Hero`model and defined it upfront as such. - ``` - export class Hero { - name: string; - power: string; - } - ``` ++makeExample('hierarchical-dependency-injection/ts/src/app/hero.ts') +:marked Our `HeroesListComponent` defines a template that creates a list of `HeroCardComponents` and `HeroEditorComponents`, each bound to an instance of hero that is returned from the `HeroService`. Ok, that’s not entirely true. It actually binds to an `EditItem` which is a simple generic datatype that can wrap any type and indicate if the item being wrapped is currently being edited or not. ++makeExample('hierarchical-dependency-injection/ts/src/app/edit-item.ts') + +:marked But how is `HeroCardComponent` implemented? Let’s take a look. - ``` - import {Component, bootstrap, CORE_DIRECTIVES} from 'angular2/angular2'; - import {Hero} from './hero'; - - @Component({ - selector: 'hero-card.component', - properties: ['hero'], - template: ` -
- Name: - {{hero.name}} -
`, - directives: [CORE_DIRECTIVES] - }) - export class HeroCardComponent { - hero: Hero; - } - ``` ++makeExample('hierarchical-dependency-injection/ts/src/app/hero-card.component.ts') +:marked The `HeroCardComponent` is basically a component that defines a template to render a hero. Nothing more. - Let’s get to the interesting part and take a look at the `HeroEditComponent` + Let’s get to the interesting part and take a look at the `HeroEditorComponent` - ``` - import {Component, FORM_DIRECTIVES, EventEmitter, bootstrap, CORE_DIRECTIVES} from 'angular2/angular2'; - import {RestoreService} from './restore.service'; - import {Hero} from './hero'; ++makeExample('hierarchical-dependency-injection/ts/src/app/hero-editor.component.ts') - @Component({ - selector: 'hero-editor-component', - events: ['canceled', 'saved'], - properties: ['hero'], - providers: [RestoreService], - template: ` -
- Name: - -
- - -
-
`, - directives: [CORE_DIRECTIVES, FORM_DIRECTIVES] - }) - export class HeroEditorComponent { - canceled = new EventEmitter(); - saved = new EventEmitter(); - - constructor(private restoreService: RestoreService) {} - - set hero (hero: Hero) { - this.restoreService.setItem(hero); - } - - get hero () { - return this.restoreService.getItem(); - } - - onSaved () { - this.saved.next(this.restoreService.getItem()); - } - - onCanceled () { - this.hero = this.restoreService.restoreItem(); - this.canceled.next(this.hero); - } - } - ``` - - Now here it’s getting interesting. The `HeroEditComponent`defines a template with an input to change the name of the hero and a `cancel` and a `save` button. Remember that we said we want to have the flexibility to cancel our editing and restore the old value? This means we need to maintain two copies of our `Hero` that we want to edit. Thinking ahead this is a perfect use case to abstract it into it’s own generic service since we have probably more cases like this in our app. +:marked + Now here it’s getting interesting. The `HeroEditorComponent`defines a template with an input to change the name of the hero and a `cancel` and a `save` button. Remember that we said we want to have the flexibility to cancel our editing and restore the old value? This means we need to maintain two copies of our `Hero` that we want to edit. Thinking ahead this is a perfect use case to abstract it into it’s own generic service since we have probably more cases like this in our app. And this is where the `RestoreService` enters the stage. - ``` - export class RestoreService { - originalItem: T; - currentItem: T; - - setItem (item: T) { - this.originalItem = item; - this.currentItem = this.clone(item); - } - - getItem () :T { - return this.currentItem; - } - - restoreItem () :T { - this.currentItem = this.originalItem; - return this.getItem(); - } - - clone (item: T) :T { - // super poor clone implementation - return JSON.parse(JSON.stringify(item)); - } - } - ``` ++makeExample('hierarchical-dependency-injection/ts/src/app/restore-service.ts') +:marked All this tiny service does is define an API to set a value of any type which can be altered, retrieved or set back to it’s initial value. That’s exactly what we need to implement the desired functionality. Our `HeroEditComponent` uses this services under the hood for it’s `hero` property. It intercepts the `get` and `set` method to delegate the actual work to our `RestoreService` which in turn makes sure that we won’t work on the original item but on a copy instead. At this point we may be scratching our heads asking what this has to do with component injectors? If we look closely at our `HeroEditComponent` we’ll notice this piece of code - ``` - … - providers: [RestoreService] - … - ``` ++makeExample('hierarchical-dependency-injection/ts/src/app/hero-editor.component.ts', 'providers') +:marked This creates a binding for the `RestoreService` in the injector of the `HeroEditComponent`. But couldn’t we simply alter our bootstrap call to this? ```