diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/e2e-spec.js b/public/docs/_examples/cb-a1-a2-quick-reference/e2e-spec.js new file mode 100644 index 0000000000..4ab84e3947 --- /dev/null +++ b/public/docs/_examples/cb-a1-a2-quick-reference/e2e-spec.js @@ -0,0 +1,110 @@ +describe('Angular 1 to 2 Quick Reference Tests', function () { + + beforeAll(function () { + browser.get(''); + }); + + it('should display no poster images after bootstrap', function () { + testImagesAreDisplayed(false); + }); + + it('should display proper movie data', function () { + // We check only a few samples + var expectedSamples = [ + {row: 0, column: 0, element: 'img', attr: 'src', value: 'images/hero.png', contains: true}, + {row: 0, column: 2, value: 'Celeritas'}, + {row: 1, column: 3, value: 'Dec 17, 2015'}, + {row: 1, column: 5, value: '$14.95'}, + {row: 2, column: 4, value: 'PG-13'}, + {row: 2, column: 7, value: '100%'}, + {row: 2, column: 0, element: 'img', attr: 'src', value: 'images/ng-logo.png', contains: true}, + ]; + + // Go through the samples + var movieRows = getMovieRows(); + for (var i = 0; i < expectedSamples.length; i++) { + var sample = expectedSamples[i]; + var tableCell = movieRows.get(sample.row) + .all(by.tagName('td')).get(sample.column); + // Check the cell or its nested element + var elementToCheck = sample.element + ? tableCell.element(by.tagName(sample.element)) + : tableCell; + + // Check element attribute or text + var valueToCheck = sample.attr + ? elementToCheck.getAttribute(sample.attr) + : elementToCheck.getText(); + + // Test for equals/contains + if (sample.contains) { + expect(valueToCheck).toContain(sample.value); + } else { + expect(valueToCheck).toEqual(sample.value); + } + } + }); + + it('should display images after Show Poster', function () { + testPosterButtonClick("Show Poster", true); + }); + + it('should hide images after Hide Poster', function () { + testPosterButtonClick("Hide Poster", false); + }); + + it('should display no movie when no favorite hero is specified', function () { + testFavoriteHero(null, "Please enter your favorite hero."); + }); + + it('should display no movie for Magneta', function () { + testFavoriteHero("Magneta", "No movie, sorry!"); + }); + + it('should display a movie for Mr. Nice', function () { + testFavoriteHero("Mr. Nice", "Excellent choice!"); + }); + + function testImagesAreDisplayed(isDisplayed) { + var expectedMovieCount = 3; + + var movieRows = getMovieRows(); + expect(movieRows.count()).toBe(expectedMovieCount); + for (var i = 0; i < expectedMovieCount; i++) { + var movieImage = movieRows.get(i).element(by.css('td > img')); + expect(movieImage.isDisplayed()).toBe(isDisplayed); + } + } + + function testPosterButtonClick(expectedButtonText, isDisplayed) { + var posterButton = element(by.css('movie-list tr > th > button')); + expect(posterButton.getText()).toBe(expectedButtonText); + + posterButton.click().then(function () { + testImagesAreDisplayed(isDisplayed); + }) + } + + function getMovieRows() { + return element.all(by.css('movie-list tbody > tr')); + } + + function testFavoriteHero(heroName, expectedLabel) { + var movieListComp = element(by.tagName('movie-list')); + var heroInput = movieListComp.element(by.tagName('input')); + var favoriteHeroLabel = movieListComp.element(by.tagName('h3')); + var resultLabel = movieListComp.element(by.css('span > p')); + + heroInput.clear().then(function () { + sendKeys(heroInput, heroName || '').then(function () { + expect(resultLabel.getText()).toBe(expectedLabel); + if (heroName) { + expect(favoriteHeroLabel.isDisplayed()).toBe(true); + expect(favoriteHeroLabel.getText()).toContain(heroName); + } else { + expect(favoriteHeroLabel.isDisplayed()).toBe(false); + } + }) + }) + } +}); diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/.gitignore b/public/docs/_examples/cb-a1-a2-quick-reference/ts/.gitignore new file mode 100644 index 0000000000..2cb7d2a2e9 --- /dev/null +++ b/public/docs/_examples/cb-a1-a2-quick-reference/ts/.gitignore @@ -0,0 +1 @@ +**/*.js diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.css b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.css new file mode 100644 index 0000000000..a556b81138 --- /dev/null +++ b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.css @@ -0,0 +1,15 @@ +/* route-link anchor tags */ +nav a {padding: 5px; text-decoration: none; font-family: Arial, Helvetica, sans-serif; } +nav a:visited, a:link {color: #444;} +nav a:hover {color: white; background-color: #1171a3; } +nav a.router-link-active {color: white; background-color: #52b9e9; } + +.active {font-style: italic;} +.shazam {font-weight: bold;} + +img {height: 100px;} + +table td { + padding: 4px; + border: 1px solid #e0e0e0; +} \ No newline at end of file diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.html b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.html new file mode 100644 index 0000000000..e0be283708 --- /dev/null +++ b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.html @@ -0,0 +1,112 @@ + +

{{title}}

+ +

Routed Movies

+ + + +
+ +

Example Snippets

+ + +
+ + [ngClass] active +
+ +
+ + [ngClass] active and boldly important +
+ +
+ + [class.active] +
+ +

+ +Angular Docs + + +

+
+ + + + +

Image toggle event type was {{eventType}}

+
+ +

+
+ + + +
+ +

+ +
+ + color preference #1 +
+ +
+ + color preference #2 +
+ +

Movie as JSON

+ +
{{movie | json}}
+ + +

Movie Titles via local variable

+ + + + + + +
{{movie.title}}
+ +

Sliced Movies with pipes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{movie.title | uppercase}}{{movie.title | lowercase}}{{movie.releaseDate | date}}{{movie.price | currency:'USD':true}}{{movie.starRating | number}}{{movie.starRating | number:'1.1-2'}}{{movie.approvalRating | percent: '1.0-2'}}
diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.ts b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.ts new file mode 100644 index 0000000000..d15652f5c9 --- /dev/null +++ b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.ts @@ -0,0 +1,40 @@ +import {Component} from 'angular2/core'; +import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from "angular2/router"; + +import {MovieListComponent} from './movie-list.component'; +import {MovieService} from './movie.service'; +import {IMovie} from './movie'; +import {StringSafeDatePipe} from './date.pipe'; + +@Component({ + selector: 'my-app', + templateUrl: 'app/app.component.html', + styleUrls: ['app/app.component.css'], + directives: [MovieListComponent, ROUTER_DIRECTIVES], + pipes: [StringSafeDatePipe], + providers: [MovieService, ROUTER_PROVIDERS] +}) +@RouteConfig([ + {path: '/movies', name: 'Movies', component: MovieListComponent, useAsDefault: true} +]) +export class AppComponent { + + angularDocsUrl = "https://angular.io/"; + colorPreference = 'red'; + eventType = ''; + isActive = true; + isImportant = true; + movie: IMovie = null; + movies: IMovie[] = []; + showImage = true; + title: string = "A1-A2 Quick Ref Cookbook"; + toggleImage(event:UIEvent) { + this.showImage = !this.showImage; + this.eventType = (event && event.type) || 'not provided'; + } + + constructor(movieService: MovieService) { + this.movies = movieService.getMovies(); + this.movie = this.movies[0]; + } +} \ No newline at end of file diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/date.pipe.ts b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/date.pipe.ts new file mode 100644 index 0000000000..d95d797ee2 --- /dev/null +++ b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/date.pipe.ts @@ -0,0 +1,14 @@ +import {Injectable, Pipe} from 'angular2/core'; +import {DatePipe} from 'angular2/common'; + +@Injectable() +// #docregion date-pipe +@Pipe({name: 'date', pure: true}) +export class StringSafeDatePipe extends DatePipe { + transform(value: any, args: any[]): string { + value = typeof value === 'string' ? + Date.parse(value) : value + return super.transform(value, args); + } +} +// #enddocregion date-pipe \ No newline at end of file diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/main.ts b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/main.ts new file mode 100644 index 0000000000..ec4c9d12d6 --- /dev/null +++ b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/main.ts @@ -0,0 +1,5 @@ +// #docregion +import {bootstrap} from 'angular2/platform/browser'; +import {AppComponent} from './app.component'; + +bootstrap(AppComponent); diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.css b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.css new file mode 100644 index 0000000000..70b0405200 --- /dev/null +++ b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.css @@ -0,0 +1,57 @@ +div { + font-family:Arial, Helvetica, sans-serif; + margin:20px; +} + +table { + font-family:Arial, Helvetica, sans-serif; + color:#666; + font-size:14px; + text-shadow: 1px 1px 0px #fff; + margin:20px; + border:#ccc 1px solid; + + -moz-border-radius:3px; + -webkit-border-radius:3px; + border-radius:3px; +} +table th { + padding:21px 25px 22px 25px; + border-top:1px solid #fafafa; + border-bottom:1px solid #e0e0e0; + border-left: 1px solid #e0e0e0; + font-weight: bold; +} +table th:first-child { + text-align: left; + padding-left:20px; + border-left: 0; +} +table tr { + text-align: center; + padding-left:20px; +} +table td:first-child { + text-align: left; + padding-left:20px; + border-left: 0; +} +table td { + padding:18px; + border-top: 1px solid #ffffff; + border-bottom:1px solid #e0e0e0; + border-left: 1px solid #e0e0e0; +} +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; +} \ No newline at end of file diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.html b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.html new file mode 100644 index 0000000000..d89cc0e3fb --- /dev/null +++ b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.html @@ -0,0 +1,78 @@ + +
+

Movie List

+
Who is your favorite hero?
+
+ + + + + + +

+ Excellent choice! +

+

+ No movie, sorry! +

+

+ Please enter your favorite hero. +

+
+ +
+
+ + +

+ + Your favorite hero is: {{favoriteHero}} + +

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + TitleHeroRelease DateRatingPriceStar ratingApproval rating
+ + {{movie.title}}{{movie.hero}}{{movie.releaseDate | date}}{{movie.mpaa | uppercase}}{{movie.price | currency:'USD':true}}{{movie.starRating | number:'1.1-2'}}{{movie.approvalRating | percent: '1.0-0'}}
+
\ No newline at end of file diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.ts b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.ts new file mode 100644 index 0000000000..a4a9c69e41 --- /dev/null +++ b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.ts @@ -0,0 +1,48 @@ +// #docplaster +// #docregion import +import {Component} from 'angular2/core'; +import {ROUTER_DIRECTIVES} from "angular2/router"; +// #enddocregion import +import {MovieService} from './movie.service'; +import {IMovie} from './movie'; +import {StringSafeDatePipe} from './date.pipe'; + + +// #docregion component +@Component({ + selector: 'movie-list', + templateUrl:'app/movie-list.component.html', +// #enddocregion component +// #docregion style-url + styleUrls: ['app/movie-list.component.css'], +// #enddocregion style-url +// #docregion date-pipe + pipes: [StringSafeDatePipe] +// #enddocregion date-pipe +}) +// #enddocregion component +// #docregion class +export class MovieListComponent { +// #enddocregion class + favoriteHero: string; + showImage: boolean = false; + movies: IMovie[]; + +// #docregion di + constructor(movieService: MovieService) { +// #enddocregion di + this.movies = movieService.getMovies(); +// #docregion di + } +// #enddocregion di + + toggleImage(): void { + this.showImage = !this.showImage; + } + + checkMovieHero(value: string): boolean { + return this.movies.filter(movie => movie.hero === value).length > 0 ; + } +// #docregion class +} +// #enddocregion class \ No newline at end of file diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie.service.ts b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie.service.ts new file mode 100644 index 0000000000..2b6538d985 --- /dev/null +++ b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie.service.ts @@ -0,0 +1,43 @@ +import {Injectable} from 'angular2/core'; +import {IMovie} from './movie'; + +@Injectable() +export class MovieService { + getMovies() : IMovie[] { + return [ + { + hero: "Celeritas", + imageurl: "images/hero.png", + movieId: 1, + mpaa: "pg-13", + releaseDate: "2015-12-19T00:00:00", + title: "Celeritas Reigns", + price: 12.95, + starRating: 4.925, + approvalRating: .97 + }, + { + hero: "Mr. Nice", + imageurl: "images/villain.png", + movieId: 2, + mpaa: "pg-13", + releaseDate: "2015-12-18T00:00:00", + title: "No More Mr. Nice Guy", + price: 14.95, + starRating: 4.6, + approvalRating: .94 + }, + { + hero: "Angular", + imageurl: "images/ng-logo.png", + movieId: 3, + mpaa: "pg-13", + releaseDate: "2015-12-17T00:00:00", + title: "Angular to the Rescue", + price: 15.95, + starRating: 4.98, + approvalRating: .9995 + } + ]; + } +} \ No newline at end of file diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie.ts b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie.ts new file mode 100644 index 0000000000..f7e8c0a7db --- /dev/null +++ b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie.ts @@ -0,0 +1,12 @@ +/* Defines the movie entity */ +export interface IMovie { + approvalRating: number; + hero: string; + imageurl: string; + movieId: number; + mpaa: string; + price: number; + releaseDate: string; + starRating: number; + title: string; +} \ No newline at end of file diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/example-config.json b/public/docs/_examples/cb-a1-a2-quick-reference/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/hero.png b/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/hero.png new file mode 100644 index 0000000000..b60c3ecc30 Binary files /dev/null and b/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/hero.png differ diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/ng-logo.png b/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/ng-logo.png new file mode 100644 index 0000000000..7929242740 Binary files /dev/null and b/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/ng-logo.png differ diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/villain.png b/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/villain.png new file mode 100644 index 0000000000..d1e71cf00b Binary files /dev/null and b/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/villain.png differ diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/index.html b/public/docs/_examples/cb-a1-a2-quick-reference/ts/index.html new file mode 100644 index 0000000000..71f5901c61 --- /dev/null +++ b/public/docs/_examples/cb-a1-a2-quick-reference/ts/index.html @@ -0,0 +1,35 @@ + + + + + Angular 1 to Angular 2 Quick Reference + + + + + + + + + + + + + + + + Loading app... + + + diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/plnkr.json b/public/docs/_examples/cb-a1-a2-quick-reference/ts/plnkr.json new file mode 100644 index 0000000000..ad554ad166 --- /dev/null +++ b/public/docs/_examples/cb-a1-a2-quick-reference/ts/plnkr.json @@ -0,0 +1,9 @@ +{ + "description": "Angular 1 to Angular 2 Quick Reference", + "files":[ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[1].*" + ], + "tags":["cookbook"] +} \ No newline at end of file diff --git a/public/docs/ts/latest/cookbook/_data.json b/public/docs/ts/latest/cookbook/_data.json index 5ee951914b..fa3783d3e6 100644 --- a/public/docs/ts/latest/cookbook/_data.json +++ b/public/docs/ts/latest/cookbook/_data.json @@ -5,7 +5,11 @@ "title": "Cookbook" }, + "a1-a2-quick-reference": { + "title": "Angular 1 to 2 Quick Ref" + }, + "component-communication": { "title": "Component Communication" } -} \ No newline at end of file +} diff --git a/public/docs/ts/latest/cookbook/a1-a2-quick-reference.jade b/public/docs/ts/latest/cookbook/a1-a2-quick-reference.jade new file mode 100644 index 0000000000..9643d0cf6e --- /dev/null +++ b/public/docs/ts/latest/cookbook/a1-a2-quick-reference.jade @@ -0,0 +1,795 @@ +include ../../../../_includes/_util-fns +a(id="top") +:marked + There are many conceptual and syntactical differences between Angular 1 and Angular 2. + This chapter provides a quick reference guide to some of the common Angular 1 + syntax and its equivalent in Angular 2. + +:marked + **See the Angular 2 syntax in this [live example](/resources/live-examples/cb-a1-a2-quick-reference/ts/plnkr.html)**. + + ## Contents + This chapter covers + * [Template Basics](#template-basics) - binding and local variables + + * [Template Directives](#template-directives) - built-in directives `ngIf` and ` `ngClass` + + * [Filters/Pipes](#filters-pipes) - built-in *filters*, known as *pipes* in Angular 2 + + * [Controllers/Components](#controllers-components) - *controllers* are *components* in Angular 2. + Also covers modules. + + * [Style Sheets](#style-sheets) - more options for CSS in Angular 2. + + * [String date pipe](#string-dates) - a tip for displaying string date values. + +.l-main-section +:marked + ## Template Basics + Templates are the user-facing part of an Angular application and are written in HTML. + The following are some of the key Angular 1 template features with the equivalent + template syntax in Angular 2. + +- var top="vertical-align:top" +table(width="100%") + col(width="50%") + col(width="50%") + tr + th Angular 1 + th Angular 2 + tr(style=top) + td + :marked + ### Bindings/Interpolation + code-example. + Your favorite hero is: {{vm.favoriteHero}} + :marked + In Angular 1, an expression in curly braces denotes one-way binding. + This binds the value of the element to a property in the controller + associated with this template. + + When using the `controller as` syntax, + the binding is prefixed with the controller alias (`vm`) because we + have to be specific about the source of the binding. + td + :marked + ### Bindings/Interpolation + +makeExample('cb-a1-a2-quick-reference/ts/app/movie-list.component.html', 'interpolation')(format="." ) + :marked + In Angular 2, a template expression in curly braces still denotes one-way binding. + This binds the value of the element to a property of the component. + The context of the binding is implied and is always the + associated component, so it needs no reference variable. + + For more information see [Template Syntax](../guide/template-syntax.html#interpolation). + tr(style=top) + td + :marked + ### Filters + code-example. + <td>{{movie.title | uppercase}}</td> + :marked + To filter output in our templates in Angular 1, we use the pipe character (|) and one or more filters. + + In this example, we filter the `mpaa` property to uppercase. + td + :marked + ### Pipes + +makeExample('cb-a1-a2-quick-reference/ts/app/app.component.html', 'uppercase')(format="." ) + :marked + In Angular 2, we use similar syntax with the pipe (|) character to filter output, but now we call them **pipes**. + Many (but not all) of the built-in filters from Angular 1 are + built-in pipes in Angular 2. + + See the heading [Filters / Pipes](#Pipes) below for more information. + tr(style=top) + td + :marked + ### Local variables + code-example(format=""). + <tr ng-repeat="movie in vm.movies"> + <td>{{movie.title}}</td> + </tr> + :marked + Here, `movie` is a user-defined local variable. + td + :marked + ### Local variables + +makeExample('cb-a1-a2-quick-reference/ts/app/app.component.html', 'local')(format="." ) + :marked + In Angular 2, we have true local template variables that are explicitly defined using the hash (#) symbol. + + Using a local template variable, we can move data between elements in the template. We can use the local template + variable on the same element, on sibling elements, or on any child elements. + + For more information see [Template Syntax](../guide/template-syntax.html#local-vars). +:marked + [Back to top](#top) + +.l-main-section +:marked + ## Template Directives + Angular 1 provides over seventy built-in directives for use in our templates. + Many of them are no longer needed in Angular 2 because of its more capable and expressive binding system. + The following are some of the key Angular 1 built-in directives and the equivalent feature in Angular 2. + +table(width="100%") + col(width="50%") + col(width="50%") + tr + th Angular 1 + th Angular 2 + tr(style=top) + td + :marked + ### ng-app + code-example. + <body ng-app="movieHunter"> + :marked + The application startup process is called **bootstrapping**. + + Although we can bootstrap an Angular 1 app in code, + many applications bootstrap declaratively with the `ng-app` directive, + giving it the name of the application's module (`movieHunter`). + td + :marked + ### Bootstrapping + +makeExample('cb-a1-a2-quick-reference/ts/app/main.ts')(format="." ) + :marked + Angular 2 does not have a bootstrap directive. + We always launch the app in code by explicitly calling a bootstrap function + and passing it the name of the application's module (`AppComponent`). + + For more information see [Quick Start](../quickstart.html). + tr(style=top) + td + :marked + ### ng-class + code-example(format=""). + <div ng-class="{active: isActive}"> + <div ng-class="{active: isActive, + shazam: isImportant}"> + :marked + In Angular 1, the `ng-class` directive includes/excludes CSS classes + based on an expression. That expression is often a key-value control object with each + key of the object defined as a CSS class name, and each value defined as a template expression + that evaluates to a Boolean value. + + In the first example, the `active` class is applied to the element if `isActive` is true. + + We can specify multiple classes as shown in the second example. + td + :marked + ### ngClass + +makeExample('cb-a1-a2-quick-reference/ts/app/app.component.html', 'ngClass')(format="." ) + :marked + In Angular 2, the `ngClass` directive works similarly. + It includes/excludes CSS classes based on an expression. + + In the first example, the `active` class is applied to the element if `isActive` is true. + + We can specify multiple classes as shown in the second example. + + Angular 2 also has **class binding**, which is good way to add or remove a single class + as shown in the third example. + + For more information see [Template Syntax](../guide/template-syntax.html#other-bindings). + + tr(style=top) + td + :marked + ### ng-click + code-example(format=""). + <button ng-click="vm.toggleImage()"> + <button ng-click="vm.toggleImage($event)"> + :marked + In Angular 1, the `ng-click` directive allows us to specify custom behavior when an element is clicked. + + In the first example, when the button is clicked, the `toggleImage()` method in the controller referenced by the `vm` `controller as` alias is executed. + + The second example demonstrates passing in the `$event` object, which provides details about the event + to the controller. + td + :marked + ### bind to the `click` event + +makeExample('cb-a1-a2-quick-reference/ts/app/app.component.html', 'event-binding')(format="." ) + :marked + The Angular 1 event-based directives do not exist in Angular 2. + Rather, we define one-way binding from the template view to the component using **event binding**. + + For event binding, we define the name of the target event within parenthesis and + specify a template statement in quotes to the right of the equals. Angular 2 then + sets up an event handler for the target event. When the event is raised, the handler + executes the template statement. + + In the first example, when the button is clicked, the `toggleImage()` method in the associated component is executed. + + The second example demonstrates passing in the `$event` object, which provides details about the event + to the component. + + For a list of DOM events, see: https://developer.mozilla.org/en-US/docs/Web/Events. + + For more information see [Template Syntax](../guide/template-syntax.html#event-binding). + + tr(style=top) + td + :marked + ### ng-controller + code-example(format=""). + <div ng-controller="MovieListCtrl as vm"> + :marked + In Angular 1, the `ng-controller` directive attaches a controller to the view. + Using the `ng-controller` (or defining the controller as part of the routing) ties the + view to the controller code associated with that view. + td + :marked + ### Component decorator + +makeExample('cb-a1-a2-quick-reference/ts/app/movie-list.component.ts', 'component')(format="." ) + :marked + In Angular 2, the template no longer specifies its associated controller. + Rather, the component specifies its associated template as part of the component class decorator. + + For more information see [Architecture Overview](../guide/architecture.html#component). + + tr(style=top) + td + :marked + ### ng-hide + In Angular 1, the `ng-hide` directive shows or hides the associated HTML element based on + an expression. See [ng-show](#ng-show) for more information. + td + :marked + ### bind to the `hidden` property + In Angular 2, we use property binding; there is no built-in *hide* directive. + See [ng-show](#ng-show) for more information. + tr(style=top) + td + :marked + ### ng-href + code-example(format=""). + <a ng-href="angularDocsUrl">Angular Docs</a> + :marked + The `ng-href` directive allows Angular 1 to preprocess the `href` property so it + can replace the binding expression with the appropriate URL before the browser + fetches from that URL. + + In Angular 1, the `ng-href` is often used to activate a route as part of navigation. + code-example(format=""). + <a ng-href="#movies">Movies</a> + :marked + Routing is handled differently in Angular 2. + td + :marked + ### bind to the `href` property + +makeExample('cb-a1-a2-quick-reference/ts/app/app.component.html', 'href')(format="." ) + :marked + In Angular 2, we use property binding; there is no built-in *href* directive. + We place the element's `href` property in square brackets and set it to a quoted template expression. + + For more information on property binding see [Template Syntax](../guide/template-syntax.html#property-binding). + + In Angular 2, `href` is no longer used for routing. Routing uses `routerLink` as shown in the third example. + +makeExample('cb-a1-a2-quick-reference/ts/app/app.component.html', 'router-link')(format="." ) + :marked + For more information on routing see [Routing & Navigation](../guide/router.html#router-link). + + tr(style=top) + td + :marked + ### ng-if + code-example(format=""). + <table ng-if="movies.length"> + :marked + In Angular 1, the `ng-if` directive removes or recreates a portion of the DOM + based on an expression. If the expression is false, the element is removed from the DOM. + + In this example, the `table` element is removed from the DOM unless the `movies` array has a length. + td + :marked + ### *ngIf + +makeExample('cb-a1-a2-quick-reference/ts/app/movie-list.component.html', 'ngIf')(format="." ) + :marked + The `*ngIf` directive in Angular 2 works the same as the `ng-if` directive in Angular 1, + it removes or recreates a portion of the DOM based on an expression. + + In this example, the `table` element is removed from the DOM unless the `movies` array has a length. + + The (*) before `ngIf` is required in this example. + For more information see [Structural Directives](../guide/structural-directives). + tr(style=top) + td + :marked + ### ng-model + code-example(format=""). + <input ng-model="vm.favoriteHero"/> + :marked + In Angular 1, the `ng-model` directive binds a form control to a property in the controller associated with the template. + This provides **two-way binding** whereby any changes made to the value in the view is synchronized with the model and + any changes to the model are synchronized with the value in the view. + td + :marked + ### ngModel + +makeExample('cb-a1-a2-quick-reference/ts/app/movie-list.component.html', 'ngModel')(format="." ) + :marked + In Angular 2, **two-way binding** is denoted with [()], descriptively referred to as a "banana in a box". + This syntax is a short-cut for defining both property binding (from the component to the view) + and event binding (from the view to the component), thereby giving us two-way binding. + + For more information on two-way binding with ngModel see [Template Syntax](../guide/template-syntax.html#ngModel). + tr(style=top) + td + :marked + ### ng-repeat + code-example(format=""). + <tr ng-repeat="movie in vm.movies"> + :marked + In Angular 1, the `ng-repeat` directive repeats the associated DOM element + for each item from the specified collection. + + In this example, the table row (`tr`) element is repeated for each movie object in the collection of movies. + td + :marked + ### *ngFor + +makeExample('cb-a1-a2-quick-reference/ts/app/movie-list.component.html', 'ngFor')(format="." ) + :marked + The `*ngFor` directive in Angular 2 is similar to the `ng-repeat` directive in Angular 1. + It repeats the associated DOM element for each item from the specified collection. + More accurately, it turns the defined element (`tr` in this example) and its contents into a template and + uses that template to instantiate a view for each item in the list. + + Notice the other syntax differences: + The (*) before `ngFor` is required; + the (#) identifies `movie` as a local variable; + the list preposition is `of`, not `in`. + + For more information see [Structural Directives](../guide/structural-directives). + tr(style=top) + td + :marked + ### ng-show + code-example(format=""). + <h3 ng-show="vm.favoriteHero"> + Your favorite hero is: {{vm.favoriteHero}} + </h3> + :marked + In Angular 1, the `ng-show` directive shows or hides the associated DOM element based on + an expression. + + In this example, the `div` element is shown if the `favoriteHero` variable is truthy. + td + :marked + ### bind to the `hidden` property + +makeExample('cb-a1-a2-quick-reference/ts/app/movie-list.component.html', 'hidden')(format="." ) + :marked + In Angular 2, we use property binding; there is no built-in *show* directive. + For hiding and showing elements, we bind to the HTML `hidden` property. + + To conditionally display an element, place the element's `hidden` property in square brackets and + set it to a quoted template expression that evaluates to the *opposite* of *show*. + + In this example, the `div` element is hidden if the `favoriteHero` variable is not truthy. + + For more information on property binding see [Template Syntax](../guide/template-syntax.html#property-binding). + tr(style=top) + td + :marked + ### ng-src + code-example(format=""). + <img ng-src="{{movie.imageurl}}"> + :marked + The `ng-src` directive allows Angular 1 to preprocess the `src` property so it + can replace the binding expression with the appropriate URL before the browser + fetches from that URL. + td + :marked + ### bind to the `src` property + +makeExample('cb-a1-a2-quick-reference/ts/app/app.component.html', 'src')(format="." ) + :marked + In Angular 2, we use property binding; there is no built-in *src* directive. + We place the `src` property in square brackets and set it to a quoted template expression. + + For more information on property binding see [Template Syntax](../guide/template-syntax.html#property-binding). + tr(style=top) + td + :marked + ### ng-style + code-example(format=""). + <div ng-style="{color: colorPreference}"> + :marked + In Angular 1, the `ng-style` directive sets a CSS style on an HTML element + based on an expression. That expression is often a key-value control object with each + key of the object defined as a CSS style name, and each value defined as an expression + that evaluates to a value appropriate for the style. + + In the example, the `color` style is set to the current value of the `colorPreference` variable. + td + :marked + ### ngStyle + +makeExample('cb-a1-a2-quick-reference/ts/app/app.component.html', 'ngStyle')(format="." ) + :marked + In Angular 2, the `ngStyle` directive works similarly. It sets a CSS style on an HTML element based on an expression. + + In the first example, the `color` style is set to the current value of the `colorPreference` variable. + + Angular 2 also has **style binding**, which is good way to set a single style. This is shown in the second example. + + For more information on style binding see [Template Syntax](../guide/template-syntax.html#style-binding). + + For more information on the ngStyle directive see [Template Syntax](../guide/template-syntax.html#ngStyle). + tr(style=top) + td + :marked + ### ng-switch + code-example(format=""). + <div ng-switch="vm.favoriteHero && + vm.checkMovieHero(vm.favoriteHero)"> + <div ng-switch-when="true"> + Excellent choice! + </div> + <div ng-switch-when="false"> + No movie, sorry! + </div> + <div ng-switch-default> + Please enter your favorite hero. + </div> + </div> + :marked + In Angular 1, the `ng-switch` directive swaps the contents of + an element by selecting one of the templates based on the current value of an expression. + + In this example, if `favoriteHero` is not set, the template displays "Please enter ...". + If the `favoriteHero` is set, it checks the movie hero by calling a controller method. + If that method returns `true`, the template displays "Excellent choice!". + If that methods returns `false`, the template displays "No movie, sorry!". + td + :marked + ### ngSwitch + +makeExample('cb-a1-a2-quick-reference/ts/app/movie-list.component.html', 'ngSwitch')(format="." ) + :marked + In Angular 2, the `ngSwitch` directive works similarly. + It displays an element whose `*ngSwitchWhen` matches the current `ngSwitch` expression value. + + In this example, if `favoriteHero` is not set, the `ngSwitch` value is `null` + and we see the `*ngSwitchDefault` paragraph, "Please enter ...". + If the `favoriteHero` is set, it checks the movie hero by calling a component method. + If that method returns `true`, we see "Excellent choice!". + If that methods returns `false`, we see "No movie, sorry!". + + The (*) before `ngSwitchWhen` and `ngSwitchDefault` is required in this example. + + For more information on the ngSwitch directive see [Template Syntax](../guide/template-syntax.html#ngSwitch). +:marked + [Back to top](#top) + +a(id="filters-pipes") +.l-main-section +:marked + ## Filters / Pipes + Angular 2 **pipes** provide formatting and transformation for data in our template, similar to Angular 1 **filters**. + Many of the built-in filters in Angular 1 have corresponding pipes in Angular 2. + For more information on pipes see [Pipes](../guide/pipes.html). + +table(width="100%") + col(width="50%") + col(width="50%") + tr + th Angular 1 + th Angular 2 + tr(style=top) + td + :marked + ### currency + code-example. + <td>{{movie.price | currency}}</td> + :marked + Formats a number as a currency. + td + :marked + ### currency + +makeExample('cb-a1-a2-quick-reference/ts/app/app.component.html', 'currency')(format="." ) + :marked + The Angular 2 `currency` pipe is similar although some of the parameters have changed. + tr(style=top) + td + :marked + ### date + code-example. + <td>{{movie.releaseDate | date}}</td> + :marked + Formats a date to a string based on the requested format. + td + :marked + ### date + +makeExample('cb-a1-a2-quick-reference/ts/app/app.component.html', 'date')(format=".") + :marked + The Angular 2 `date` pipe is similar. See [note](#string-dates) about string date values. + + tr(style=top) + td + :marked + ### filter + code-example. + <tr ng-repeat="movie in movieList | filter: {title:listFilter}"> + :marked + Selects a subset of items from the defined collection based on the filter criteria. + td + :marked + ### none + :marked + There is no comparable pipe in Angular 2 for performance reasons. + Filtering should be coded in the component. + Consider building a custom pipe if the same filtering code + will be reused in several templates. + + tr(style=top) + td + :marked + ### json + code-example. + <pre>{{movie | json}}</pre> + :marked + Converts a JavaScript object into a JSON string. This is useful for debugging. + td + :marked + ### json + +makeExample('cb-a1-a2-quick-reference/ts/app/app.component.html', 'json')(format=".") + :marked + The Angular 2 `json` pipe does the same thing. + tr(style=top) + td + :marked + ### limitTo + code-example. + <tr ng-repeat="movie in movieList | limitTo: 2"> + :marked + Selects the defined number of items from the collection. + td + :marked + ### slice + +makeExample('cb-a1-a2-quick-reference/ts/app/app.component.html', 'slice')(format=".") + :marked + The first parameter of the `SlicePipe` is the starting index; the second is the limit. + As in Angular 1, performance may improve if this operation is coded in the component. + tr(style=top) + td + :marked + ### lowercase + code-example. + <div>{{movie.title | lowercase}}</div> + :marked + Converts the string to lowercase. + td + :marked + ### lowercase + +makeExample('cb-a1-a2-quick-reference/ts/app/app.component.html', 'lowercase')(format=".") + :marked + The Angular 2 `lowercase` pipe does the same thing. + tr(style=top) + td + :marked + ### number + code-example. + <td>{{movie.starRating | number}}</td> + :marked + Formats a number as text. + td + :marked + ### number + +makeExample('cb-a1-a2-quick-reference/ts/app/app.component.html', 'number')(format=".") + :marked + The Angular 2 `number` pipe is similar. + It provides more functionality when defining + the decimal places as shown in the second example above. + + Angular 2 also has a `percent` pipe which formats a number as a local percentage + as shown in the third example. + tr(style=top) + td + :marked + ### orderBy + code-example. + <tr ng-repeat="movie in movieList | orderBy : 'title'"> + :marked + Orders the collection as specified by the expression. + In this example, the movieList is ordered by the movie title. + td + :marked + ### none + There is no comparable pipe in Angular 2 for performance reasons. + Ordering/sorting the results should be coded in the component. + Consider building a custom pipe if the same ordering/sorting code + will be reused in several templates. +:marked + [Back to top](#top) + +a(id="controllers-components") +.l-main-section +:marked + ## Controllers / Components + In Angular 1, we write the code that provides the model and the methods for the view in a **controller**. + In Angular 2, we build a **component**. + + Because much of our Angular 1 code is in JavaScript, JavaScript code is shown in the Angular 1 column. + The Angular 2 code is shown using TypeScript. + +table(width="100%") + col(width="50%") + col(width="50%") + tr + th Angular 1 + th Angular 2 + tr(style=top) + td + :marked + ### IIFE + code-example. + (function () { + }()); + :marked + In Angular 1, we often defined an immediately invoked function expression (or IIFE) around our controller code. + This kept our controller code out of the global namespace. + td + :marked + ### none + We don't need to worry about this in Angular 2 because we use ES 2015 modules + and modules handle the namespacing for us. + + For more information on modules see [Architecture Overview](../guide/architecture.html#module). + tr(style=top) + td + :marked + ### Angular modules + code-example. + angular.module("movieHunter", ["ngRoute"]); + :marked + In Angular 1, we define an Angular module, which keeps track of our + controllers, services, and other code. The second argument defines the list + of other modules that this module depends upon. + td + :marked + ### import + +makeExample('cb-a1-a2-quick-reference/ts/app/movie-list.component.ts', 'import')(format=".") + :marked + Angular 2 does not have its own module system. Instead we use ES 2015 modules. + ES 2015 modules are file based, so each code file is its own module. + + We `import` what we need from the module files. + + For more information on modules see [Architecture Overview](../guide/architecture.html#module). + tr(style=top) + td + :marked + ### Controller registration + code-example. + angular + .module("movieHunter") + .controller("MovieListCtrl", + ["movieService", + MovieListCtrl]); + :marked + In Angular 1, we have code in each controller that looks up an appropriate Angular module + and registers the controller with that module. + + The first argument is the controller name. The second argument defines the string names of + all dependencies injected into this controller, and a reference to the controller function. + td + :marked + ### Component Decorator + +makeExample('cb-a1-a2-quick-reference/ts/app/movie-list.component.ts', 'component')(format=".") + :marked + In Angular 2, we add a decorator to the component class to provide any required metadata. + The Component decorator declares that the class is a component and provides metadata about + that component, such as its selector (or tag) and its template. + + This is how we associate a template with code, which is defined in the component class. + + For more information on components see [Architecture Overview](../guide/architecture.html#component). + tr(style=top) + td + :marked + ### Controller function + code-example. + function MovieListCtrl(movieService) { + } + :marked + In Angular 1, we write the code for the model and methods in a controller function. + td + :marked + ### Component class + +makeExample('cb-a1-a2-quick-reference/ts/app/movie-list.component.ts', 'class')(format=".") + :marked + In Angular 2, we create a component class. + + NOTE: If you are using TypeScript with Angular 1 then the only difference here is + that the component class must be exported using the `export` keyword. + + For more information on components see [Architecture Overview](../guide/architecture.html#component). + tr(style=top) + td + :marked + ### Dependency injection + code-example. + MovieListCtrl.$inject = ['MovieService']; + function MovieListCtrl(movieService) { + } + :marked + In Angular 1, we pass in any dependencies as controller function arguments. + In this example, we inject a `MovieService`. + + We also guard against minification problems by telling Angular explicitly + that it should inject an instance of the `MovieService` in the first parameter. + td + :marked + ### Dependency injection + +makeExample('cb-a1-a2-quick-reference/ts/app/movie-list.component.ts', 'di')(format=".") + :marked + In Angular 2, we pass in dependencies as arguments to the component class constructor. + In this example, we inject a `MovieService`. + The first parameter's TypeScript type tells Angular what to inject even after minification. + + For more information on dependency injection see [Architecture Overview](../guide/architecture.html#dependency-injection). +:marked + [Back to top](#top) + +a(id="style-sheets") +.l-main-section +:marked + ## Style Sheets + Style sheets give our application a nice look. + In Angular 1, we specify the style sheets for our entire application. + As the application grows over time, the styles for the many parts of the application + are merged, which can cause unexpected results. + In Angular 2, we can still define style sheets for our entire application. But now we can + also encapculate a style sheet within a specific component. +table(width="100%") + col(width="50%") + col(width="50%") + tr + th Angular 1 + th Angular 2 + tr(style=top) + td + :marked + ### Link tag + code-example. + <link href="styles.css" rel="stylesheet" /> + :marked + In Angular 1, we use a `link` tag in the head section of our `index.html` file + to define the styles for our application. + td + :marked + ### Link tag + +makeExample('cb-a1-a2-quick-reference/ts/index.html', 'style')(format=".") + :marked + In Angular 2, we can continue to use the link tag to define the styles for our application in the `index.html` file. + But we can now also encapsulate styles for our components. + :marked + ### StyleUrls + In Angular 2, we can use the `styles` or `styleUrls` property of the `@Component` metadata to define + a style sheet for a particular component. + +makeExample('cb-a1-a2-quick-reference/ts/app/movie-list.component.ts', 'style-url')(format=".") + :marked + This allows us to set appropriate styles for individual components that won’t leak into + other parts of the application. +:marked + [Back to top](#top) + +a(id="string-dates") +.l-main-section +:marked + ## Appendix: String dates + + Currently the Angular 2 `date` pipe does not process string dates such as + "2015-12-19T00:00:00". + + As a work around, subclass the Angular `DatePipe` with a version that can convert strings + and substitute that pipe in the HTML: + ++makeExample('cb-a1-a2-quick-reference/ts/app/date.pipe.ts', 'date-pipe', 'date.pipe.ts')(format=".") +:marked + Then import and declare that pipe in the `@Component` metadata `pipes` array: +:marked ++makeExample('cb-a1-a2-quick-reference/ts/app/movie-list.component.ts', 'date-pipe')(format=".") + +:marked + [Back to top](#top) diff --git a/public/docs/ts/latest/guide/_data.json b/public/docs/ts/latest/guide/_data.json index b7f759488e..84963feb59 100644 --- a/public/docs/ts/latest/guide/_data.json +++ b/public/docs/ts/latest/guide/_data.json @@ -8,7 +8,7 @@ "cheatsheet": { "title": "Angular Cheat Sheet" }, - + "architecture": { "title": "Architecture Overview" },