diff --git a/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-bootstrap/app.module.ts b/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-bootstrap/app.module.ts index b4926d8c69..6ac76407b1 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-bootstrap/app.module.ts +++ b/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-bootstrap/app.module.ts @@ -1,18 +1,29 @@ declare var angular: any; +// #docregion ngmodule +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +@NgModule({ + imports: [ BrowserModule ] +}) +export class AppModule {} +// #enddocregion ngmodule +angular.module('heroApp', []) + .controller('MainCtrl', function() { + this.message = 'Hello world'; + }); + // #docregion bootstrap import { UpgradeAdapter } from '@angular/upgrade'; // #enddocregion bootstrap -angular.module('heroApp', []) - .controller('MainCtrl', function() { - this.message = 'Hello world'; - }); +// This blank is expected to trigger the docplaster // #docregion bootstrap -const upgradeAdapter = new UpgradeAdapter(); +const upgradeAdapter = new UpgradeAdapter(AppModule); upgradeAdapter.bootstrap(document.body, ['heroApp'], {strictDi: true}); // #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-shared-adapter-bootstrap/upgrade_adapter.ts b/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-shared-adapter-bootstrap/upgrade_adapter.ts index f6066f9109..6ccaa31b9c 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-shared-adapter-bootstrap/upgrade_adapter.ts +++ b/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-shared-adapter-bootstrap/upgrade_adapter.ts @@ -1,3 +1,16 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +@NgModule({ + imports: [ BrowserModule ] +}) +export class AppModule {} + +angular.module('heroApp', []) + .controller('MainCtrl', function() { + this.message = 'Hello world'; + }); + // #docregion import { UpgradeAdapter } from '@angular/upgrade'; -export const upgradeAdapter = new UpgradeAdapter(); +export const upgradeAdapter = new UpgradeAdapter(AppModule); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-projection/app.module.ts b/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-projection/app.module.ts index ad48568e09..5daeb671e3 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-projection/app.module.ts +++ b/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-projection/app.module.ts @@ -1,10 +1,18 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; import { UpgradeAdapter } from '@angular/upgrade'; import { MainController } from './main.controller'; import { HeroDetailComponent } from './hero-detail.component'; +@NgModule({ + imports: [ BrowserModule ], + declarations: [ HeroDetailComponent ] +}) +export class AppModule {} + declare var angular: any; -const upgradeAdapter = new UpgradeAdapter(); +const upgradeAdapter = new UpgradeAdapter(AppModule); angular.module('heroApp', []) .controller('MainController', MainController) diff --git a/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-providers/upgrade_adapter.ts b/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-providers/upgrade_adapter.ts index f6066f9109..c98ab182a8 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-providers/upgrade_adapter.ts +++ b/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-providers/upgrade_adapter.ts @@ -1,3 +1,19 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { HeroDetailComponent } from './hero-detail.component'; + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ HeroDetailComponent ] +}) +export class AppModule {} + +angular.module('heroApp', []) + .controller('MainCtrl', function() { + this.message = 'Hello world'; + }); + // #docregion import { UpgradeAdapter } from '@angular/upgrade'; -export const upgradeAdapter = new UpgradeAdapter(); +export const upgradeAdapter = new UpgradeAdapter(AppModule); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/app.module.ts b/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/app.module.ts index 9ab3f70e94..16b77819c5 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/app.module.ts +++ b/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/app.module.ts @@ -5,8 +5,6 @@ import { upgradeAdapter } from './upgrade_adapter'; declare var angular: any; // #docregion register -upgradeAdapter.addProvider(Heroes); - angular.module('heroApp', []) .factory('heroes', upgradeAdapter.downgradeNg2Provider(Heroes)) .component('heroDetail', heroDetailComponent); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/upgrade_adapter.ts b/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/upgrade_adapter.ts index f6066f9109..d99d587f0f 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/upgrade_adapter.ts +++ b/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/upgrade_adapter.ts @@ -1,3 +1,19 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +// #docregion ngmodule +import { Heroes } from './heroes'; + +@NgModule({ + imports: [ BrowserModule ], + providers: [ Heroes ] +}) +export class AppModule {} +// #enddocregion ngmodule +angular.module('heroApp', []) + .controller('MainCtrl', function() { + this.message = 'Hello world'; + }); + // #docregion import { UpgradeAdapter } from '@angular/upgrade'; -export const upgradeAdapter = new UpgradeAdapter(); +export const upgradeAdapter = new UpgradeAdapter(AppModule); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/container.component.ts b/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/container.component.ts index a468898e5f..1b740d6554 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/container.component.ts +++ b/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/container.component.ts @@ -1,10 +1,7 @@ // #docregion import { Component } from '@angular/core'; -import { upgradeAdapter } from './upgrade_adapter'; import { Hero } from '../hero'; -const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail'); - @Component({ selector: 'my-container', template: ` @@ -12,8 +9,7 @@ const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail');

{{hero.description}}

- `, - directives: [HeroDetail] + ` }) export class ContainerComponent { hero = new Hero(1, 'Windstorm', 'Specific powers of controlling winds'); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/upgrade_adapter.ts b/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/upgrade_adapter.ts index f6066f9109..b0f947c8e5 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/upgrade_adapter.ts +++ b/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/upgrade_adapter.ts @@ -1,3 +1,20 @@ // #docregion import { UpgradeAdapter } from '@angular/upgrade'; -export const upgradeAdapter = new UpgradeAdapter(); +import { NgModule, forwardRef } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { ContainerComponent } from './container.component'; + +export const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule)); +const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail'); + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ ContainerComponent, HeroDetail ] +}) +export class AppModule {} + +angular.module('heroApp', []) + .controller('MainCtrl', function() { + this.message = 'Hello world'; + }); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/downgrade-io/app.module.ts b/public/docs/_examples/upgrade-adapter/ts/app/downgrade-io/app.module.ts index d9af4e0104..a09db040d1 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/downgrade-io/app.module.ts +++ b/public/docs/_examples/upgrade-adapter/ts/app/downgrade-io/app.module.ts @@ -1,11 +1,21 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + import { MainController } from './main.controller'; // #docregion downgradecomponent import { HeroDetailComponent } from './hero-detail.component'; // #enddocregion downgradecomponent + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ HeroDetailComponent ] +}) +export class AppModule {} + import { UpgradeAdapter } from '@angular/upgrade'; -const upgradeAdapter = new UpgradeAdapter(); +const upgradeAdapter = new UpgradeAdapter(AppModule); // #docregion downgradecomponent diff --git a/public/docs/_examples/upgrade-adapter/ts/app/downgrade-static/app.module.ts b/public/docs/_examples/upgrade-adapter/ts/app/downgrade-static/app.module.ts index 44935340f0..d5f173b5b5 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/downgrade-static/app.module.ts +++ b/public/docs/_examples/upgrade-adapter/ts/app/downgrade-static/app.module.ts @@ -1,10 +1,19 @@ -// #docregion downgradecomponent +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +// #docregion downgradecomponent, ngmodule import { HeroDetailComponent } from './hero-detail.component'; // #enddocregion downgradecomponent +@NgModule({ + imports: [ BrowserModule ], + declarations: [ HeroDetailComponent ] +}) +export class AppModule {} +// #enddocregion ngmodule import { UpgradeAdapter } from '@angular/upgrade'; -const upgradeAdapter = new UpgradeAdapter(); +const upgradeAdapter = new UpgradeAdapter(AppModule); // #docregion downgradecomponent diff --git a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/container.component.ts b/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/container.component.ts index 0055370ea8..8d76085174 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/container.component.ts +++ b/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/container.component.ts @@ -1,10 +1,7 @@ // #docregion import { Component } from '@angular/core'; -import { upgradeAdapter } from './upgrade_adapter'; import { Hero } from '../hero'; -const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail'); - @Component({ selector: 'my-container', template: ` @@ -12,8 +9,7 @@ const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail'); - `, - directives: [HeroDetail] + ` }) export class ContainerComponent { hero = new Hero(1, 'Windstorm'); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/upgrade_adapter.ts b/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/upgrade_adapter.ts index f6066f9109..b0f947c8e5 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/upgrade_adapter.ts +++ b/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/upgrade_adapter.ts @@ -1,3 +1,20 @@ // #docregion import { UpgradeAdapter } from '@angular/upgrade'; -export const upgradeAdapter = new UpgradeAdapter(); +import { NgModule, forwardRef } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { ContainerComponent } from './container.component'; + +export const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule)); +const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail'); + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ ContainerComponent, HeroDetail ] +}) +export class AppModule {} + +angular.module('heroApp', []) + .controller('MainCtrl', function() { + this.message = 'Hello world'; + }); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/container.component.ts b/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/container.component.ts index ca8a93dd26..1e3ebf509b 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/container.component.ts +++ b/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/container.component.ts @@ -1,16 +1,12 @@ // #docregion import { Component } from '@angular/core'; -import { upgradeAdapter } from './upgrade_adapter'; - -const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail'); @Component({ selector: 'my-container', template: `

Tour of Heroes

- `, - directives: [HeroDetail] + ` }) export class ContainerComponent { diff --git a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/upgrade_adapter.ts b/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/upgrade_adapter.ts index f6066f9109..c9173347bc 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/upgrade_adapter.ts +++ b/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/upgrade_adapter.ts @@ -1,3 +1,23 @@ // #docregion import { UpgradeAdapter } from '@angular/upgrade'; -export const upgradeAdapter = new UpgradeAdapter(); +import { NgModule, forwardRef } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { ContainerComponent } from './container.component'; + +export const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule)); + +// #docregion heroupgrade +const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail'); + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ ContainerComponent, HeroDetail ] +}) +export class AppModule {} +// #enddocregion heroupgrade + +angular.module('heroApp', []) + .controller('MainCtrl', function() { + this.message = 'Hello world'; + }); diff --git a/public/docs/_examples/upgrade-adapter/ts/index-1-2-hybrid-bootstrap.html b/public/docs/_examples/upgrade-adapter/ts/index-1-2-hybrid-bootstrap.html index ff5481a40d..fc090c9eb9 100644 --- a/public/docs/_examples/upgrade-adapter/ts/index-1-2-hybrid-bootstrap.html +++ b/public/docs/_examples/upgrade-adapter/ts/index-1-2-hybrid-bootstrap.html @@ -16,9 +16,6 @@ - - - - - - - - - - - + diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/karma-test-shim.1.js b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/karma-test-shim.1.js index 31589119d2..19fcc89fe9 100644 --- a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/karma-test-shim.1.js +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/karma-test-shim.1.js @@ -1,21 +1,25 @@ // #docregion // /*global jasmine, __karma__, window*/ -Error.stackTraceLimit = Infinity; +Error.stackTraceLimit = 0; // "No stacktrace"" is usually best for app testing. + +// Uncomment to get full stacktrace output. Sometimes helpful, usually not. +// Error.stackTraceLimit = Infinity; // + jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000; -__karma__.loaded = function () { -}; +var builtPath = '/base/app/'; + +__karma__.loaded = function () { }; function isJsFile(path) { return path.slice(-3) == '.js'; } function isSpecFile(path) { - return /\.spec\.js$/.test(path); + return /\.spec\.(.*\.)?js$/.test(path); } function isBuiltFile(path) { - var builtPath = '/base/app/'; return isJsFile(path) && (path.substr(0, builtPath.length) == builtPath); } @@ -25,27 +29,61 @@ var allSpecFiles = Object.keys(window.__karma__.files) System.config({ baseURL: '/base', - packageWithIndex: true // sadly, we can't use umd packages (yet?) + // Extend usual application package list with test folder + packages: { 'testing': { main: 'index.js', defaultExtension: 'js' } }, + + // Assume npm: is set in `paths` in systemjs.config + // Map the angular testing umd bundles + map: { + '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js', + '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js', + '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js', + '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js', + '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js', + '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js', + '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js', + '@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js', + }, }); System.import('systemjs.config.js') - .then(() => Promise.all([ - System.import('@angular/core/testing'), - System.import('@angular/platform-browser-dynamic/testing') - ])) - .then((providers) => { - var coreTesting = providers[0]; + .then(importSystemJsExtras) + .then(initTestBed) + .then(initTesting); + +/** Optional SystemJS configuration extras. Keep going w/o it */ +function importSystemJsExtras(){ + return System.import('systemjs.config.extras.js') + .catch(function(reason) { + console.log( + 'Warning: System.import could not load the optional "systemjs.config.extras.js". Did you omit it by accident? Continuing without it.' + ); + console.log(reason); + }); +} + +function initTestBed(){ + return Promise.all([ + System.import('@angular/core/testing'), + System.import('@angular/platform-browser-dynamic/testing') + ]) + + .then(function (providers) { + var coreTesting = providers[0]; var browserTesting = providers[1]; + coreTesting.TestBed.initTestEnvironment( browserTesting.BrowserDynamicTestingModule, browserTesting.platformBrowserDynamicTesting()); }) - .then(function () { - // Finally, load all spec files. - // This will run the tests directly. - return Promise.all( - allSpecFiles.map(function (moduleName) { - return System.import(moduleName); - })); - }) +} + +// Import all spec files and start karma +function initTesting () { + return Promise.all( + allSpecFiles.map(function (moduleName) { + return System.import(moduleName); + }) + ) .then(__karma__.start, __karma__.error); +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/karma.conf.ng1.js b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/karma.conf.ng1.js index 48cc490f89..3decfbdd3e 100644 --- a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/karma.conf.ng1.js +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/karma.conf.ng1.js @@ -63,11 +63,10 @@ module.exports = function(config) { frameworks: ['jasmine'], - browsers: ['Chrome', 'Firefox'], + browsers: ['Chrome'], plugins: [ 'karma-chrome-launcher', - 'karma-firefox-launcher', 'karma-jasmine' ] diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js index a54f8bb20c..18b947dbb5 100644 --- a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js @@ -1,59 +1,47 @@ /** - * System configuration for Angular 2 samples + * System configuration for Angular samples * Adjust as necessary for your application needs. */ -(function(global) { - - // map tells the System loader where to look for things +(function (global) { // #docregion paths - var map = { - 'app': '/app', // 'dist', - - '@angular': '/node_modules/@angular', - 'angular-in-memory-web-api': '/node_modules/angular-in-memory-web-api', - 'rxjs': '/node_modules/rxjs' - }; - - var packages = { - '/app': { main: 'main.js', defaultExtension: 'js' }, - 'rxjs': { defaultExtension: 'js' }, - 'angular-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' }, - }; - // #enddocregion paths - - var ngPackageNames = [ - 'common', - 'compiler', - 'core', - 'forms', - 'http', - 'platform-browser', - 'platform-browser-dynamic', - 'router', - 'router-deprecated', - 'upgrade', - ]; - - // Individual files (~300 requests): - function packIndex(pkgName) { - packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' }; - } - - // Bundled (~40 requests): - function packUmd(pkgName) { - packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' }; - } - - var setPackageConfig = System.packageWithIndex ? packIndex : packUmd; - - // Add package entries for angular packages - ngPackageNames.forEach(setPackageConfig); - - var config = { - map: map, - packages: packages - } - - System.config(config); + System.config({ + paths: { + // paths serve as alias + 'npm:': '/node_modules/' + }, + map: { + app: '/app', + // #enddocregion paths + // angular bundles + '@angular/core': 'npm:@angular/core/bundles/core.umd.js', + '@angular/common': 'npm:@angular/common/bundles/common.umd.js', + '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', + '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', + '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', + '@angular/http': 'npm:@angular/http/bundles/http.umd.js', + '@angular/router': 'npm:@angular/router/bundles/router.umd.js', + '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', + '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js', + // other libraries + 'rxjs': 'npm:rxjs', + 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api', + // #docregion paths + }, + // #enddocregion paths + // packages tells the System loader how to load when no filename and/or no extension + packages: { + 'app': { + main: './main.js', + defaultExtension: 'js' + }, + rxjs: { + defaultExtension: 'js' + }, + 'angular-in-memory-web-api': { + main: './index.js', + defaultExtension: 'js' + } + } + }); })(this); diff --git a/public/docs/_examples/upgrade-phonecat-3-final/e2e-spec.ts.disabled b/public/docs/_examples/upgrade-phonecat-3-final/e2e-spec.ts similarity index 100% rename from public/docs/_examples/upgrade-phonecat-3-final/e2e-spec.ts.disabled rename to public/docs/_examples/upgrade-phonecat-3-final/e2e-spec.ts diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/app-routing.module.ts b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/app-routing.module.ts new file mode 100644 index 0000000000..16a72b069e --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/app-routing.module.ts @@ -0,0 +1,23 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; +import { APP_BASE_HREF, HashLocationStrategy, LocationStrategy } from '@angular/common'; + +import { PhoneDetailComponent } from './phone-detail/phone-detail.component'; +import { PhoneListComponent } from './phone-list/phone-list.component'; + +const routes: Routes = [ + { path: '', redirectTo: 'phones', pathMatch: 'full' }, + { path: 'phones', component: PhoneListComponent }, + { path: 'phones/:phoneId', component: PhoneDetailComponent } +]; + +@NgModule({ + imports: [ RouterModule.forRoot(routes) ], + exports: [ RouterModule ], + providers: [ + { provide: APP_BASE_HREF, useValue: '!' }, + { provide: LocationStrategy, useClass: HashLocationStrategy }, + ] +}) +export class AppRoutingModule {} diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/app.component.ts b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/app.component.ts index af4e91c80f..fa4e5f7f4b 100644 --- a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/app.component.ts +++ b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/app.component.ts @@ -1,18 +1,9 @@ // #docregion import { Component } from '@angular/core'; -import { RouteConfig, ROUTER_DIRECTIVES } from '@angular/router-deprecated'; -import { PhoneListComponent } from './phone-list/phone-list.component'; -import { PhoneDetailComponent } from './phone-detail/phone-detail.component'; -@RouteConfig([ - {path: '/phones', name: 'Phones', component: PhoneListComponent}, - {path: '/phones/:phoneId', name: 'Phone', component: PhoneDetailComponent}, - {path: '/', redirectTo: ['Phones']} -]) @Component({ selector: 'phonecat-app', - template: '', - directives: [ROUTER_DIRECTIVES] + template: '' }) export class AppComponent { } diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/app.module.ts b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/app.module.ts new file mode 100644 index 0000000000..58acb5bce3 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/app.module.ts @@ -0,0 +1,34 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { HttpModule } from '@angular/http'; + +import { AppRoutingModule } from './app-routing.module'; +import { AppComponent } from './app.component'; +import { CheckmarkPipe } from './core/checkmark/checkmark.pipe'; +import { Phone } from './core/phone/phone.service'; +import { PhoneDetailComponent } from './phone-detail/phone-detail.component'; +import { PhoneListComponent } from './phone-list/phone-list.component'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + HttpModule, + AppRoutingModule + ], + declarations: [ + AppComponent, + PhoneListComponent, + CheckmarkPipe, + PhoneDetailComponent + ], + providers: [ + Phone, + ], + // #docregion bootstrap + bootstrap: [ AppComponent ] + // #enddocregion bootstrap +}) +export class AppModule {} diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/core/checkmark/checkmark.pipe.spec.ts b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/core/checkmark/checkmark.pipe.spec.ts index b3a1c59a8d..75150500a6 100644 --- a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/core/checkmark/checkmark.pipe.spec.ts +++ b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/core/checkmark/checkmark.pipe.spec.ts @@ -1,21 +1,10 @@ -import { - describe, - beforeEachProviders, - it, - inject, - expect -} from '@angular/core/testing'; import { CheckmarkPipe } from './checkmark.pipe'; describe('CheckmarkPipe', function() { - beforeEachProviders(() => [CheckmarkPipe]); - - it('should convert boolean values to unicode checkmark or cross', - inject([CheckmarkPipe], function(checkmarkPipe: CheckmarkPipe) { - expect(checkmarkPipe.transform(true)).toBe('\u2713'); - expect(checkmarkPipe.transform(false)).toBe('\u2718'); - }) - ); - + it('should convert boolean values to unicode checkmark or cross', function () { + const checkmarkPipe = new CheckmarkPipe(); + expect(checkmarkPipe.transform(true)).toBe('\u2713'); + expect(checkmarkPipe.transform(false)).toBe('\u2718'); + }); }); diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/core/phone/phone.service.spec.ts b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/core/phone/phone.service.spec.ts index c9f511913b..e3a422965b 100644 --- a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/core/phone/phone.service.spec.ts +++ b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/core/phone/phone.service.spec.ts @@ -1,10 +1,4 @@ -import { - describe, - beforeEach, - beforeEachProviders, - it, - inject -} from '@angular/core/testing'; +import { inject, TestBed } from '@angular/core/testing'; import { Http, BaseRequestOptions, @@ -23,15 +17,19 @@ describe('Phone', function() { ]; let mockBackend: MockBackend; - beforeEachProviders(() => [ - Phone, - MockBackend, - BaseRequestOptions, - { provide: Http, - useFactory: (backend: MockBackend, options: BaseRequestOptions) => new Http(backend, options), - deps: [MockBackend, BaseRequestOptions] - } - ]); + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + Phone, + MockBackend, + BaseRequestOptions, + { provide: Http, + useFactory: (backend: MockBackend, options: BaseRequestOptions) => new Http(backend, options), + deps: [MockBackend, BaseRequestOptions] + } + ] + }); + }); beforeEach(inject([MockBackend, Phone], (_mockBackend_: MockBackend, _phone_: Phone) => { mockBackend = _mockBackend_; diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/dell-venue.0.jpg b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/dell-venue.0.jpg new file mode 100644 index 0000000000..b4cb4eb25f Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/dell-venue.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/droid-2-global-by-motorola.0.jpg b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/droid-2-global-by-motorola.0.jpg new file mode 100644 index 0000000000..60700a2ab3 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/droid-2-global-by-motorola.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/droid-pro-by-motorola.0.jpg b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/droid-pro-by-motorola.0.jpg new file mode 100644 index 0000000000..c7710de986 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/droid-pro-by-motorola.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/lg-axis.0.jpg b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/lg-axis.0.jpg new file mode 100644 index 0000000000..55e5a23bb2 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/lg-axis.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/motorola-bravo-with-motoblur.0.jpg b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/motorola-bravo-with-motoblur.0.jpg new file mode 100644 index 0000000000..e452ae7e7c Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/motorola-bravo-with-motoblur.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/motorola-charm-with-motoblur.0.jpg b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/motorola-charm-with-motoblur.0.jpg new file mode 100644 index 0000000000..21e4b8d741 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/motorola-charm-with-motoblur.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/motorola-defy-with-motoblur.0.jpg b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/motorola-defy-with-motoblur.0.jpg new file mode 100644 index 0000000000..c7c5e3ba0c Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/motorola-defy-with-motoblur.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/samsung-galaxy-tab.0.jpg b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/samsung-galaxy-tab.0.jpg new file mode 100644 index 0000000000..3750377ad9 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/samsung-galaxy-tab.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/samsung-gem.0.jpg b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/samsung-gem.0.jpg new file mode 100644 index 0000000000..0d5024a026 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/samsung-gem.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg new file mode 100644 index 0000000000..11b8f860cb Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg new file mode 100644 index 0000000000..11b8f860cb Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/samsung-transform.0.jpg b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/samsung-transform.0.jpg new file mode 100644 index 0000000000..0e3107caf5 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/samsung-transform.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/sanyo-zio.0.jpg b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/sanyo-zio.0.jpg new file mode 100644 index 0000000000..9eeb9b96ed Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/sanyo-zio.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/t-mobile-g2.0.jpg b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/t-mobile-g2.0.jpg new file mode 100644 index 0000000000..6b6c09e058 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/t-mobile-g2.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/t-mobile-mytouch-4g.0.jpg b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/t-mobile-mytouch-4g.0.jpg new file mode 100644 index 0000000000..beba1f6827 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/img/phones/t-mobile-mytouch-4g.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/main.ts b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/main.ts index 4db648092b..08be7a99ba 100644 --- a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/main.ts +++ b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/main.ts @@ -1,27 +1,10 @@ // #docregion // #docregion imports -import { - LocationStrategy, - HashLocationStrategy, - APP_BASE_HREF -} from '@angular/common'; -import { bootstrap } from '@angular/platform-browser-dynamic'; -import { FormsModule } from '@angular/forms'; -import { HTTP_PROVIDERS } from '@angular/http'; -import { ROUTER_PROVIDERS } from '@angular/router-deprecated'; -import { Phone } from './core/phone/phone.service'; -import { AppComponent } from './app.component'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app.module'; // #enddocregion imports // #docregion bootstrap -bootstrap(AppComponent, { - imports: [FormsModule], - providers: [ - HTTP_PROVIDERS, - ROUTER_PROVIDERS, - { provide: APP_BASE_HREF, useValue: '!' }, - { provide: LocationStrategy, useClass: HashLocationStrategy }, - Phone - ] -}); +platformBrowserDynamic().bootstrapModule(AppModule); // #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-detail/phone-detail.component.spec.ts b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-detail/phone-detail.component.spec.ts index 79b3cddcfb..e3b9143a94 100644 --- a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-detail/phone-detail.component.spec.ts +++ b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-detail/phone-detail.component.spec.ts @@ -1,25 +1,15 @@ // #docregion -import { HTTP_PROVIDERS } from '@angular/http'; -// #docregion routeparams -import { RouteParams } from '@angular/router-deprecated'; +// #docregion activatedroute +import { ActivatedRoute } from '@angular/router'; -// #enddocregion routeparams +// #enddocregion activatedroute import { Observable } from 'rxjs/Rx'; -import { - describe, - beforeEachProviders, - inject, - it, - expect -} from '@angular/core/testing'; -import { - TestComponentBuilder, - ComponentFixture -} from '@angular/compiler/testing'; +import { async, TestBed } from '@angular/core/testing'; import { PhoneDetailComponent } from './phone-detail.component'; import { Phone, PhoneData } from '../core/phone/phone.service'; +import { CheckmarkPipe } from '../core/checkmark/checkmark.pipe'; function xyzPhoneData(): PhoneData { return { @@ -29,31 +19,41 @@ function xyzPhoneData(): PhoneData { }; } -class MockPhone extends Phone { +class MockPhone { get(id: string): Observable { return Observable.of(xyzPhoneData()); } } +// #docregion activatedroute + +class ActivatedRouteMock { + constructor(public snapshot: any) {} +} + +// #enddocregion activatedroute + describe('PhoneDetailComponent', () => { - // #docregion routeparams + // #docregion activatedroute - beforeEachProviders(() => [ - { provide: Phone, useClass: MockPhone }, - { provide: RouteParams, useValue: new RouteParams({phoneId: 'xyz'})}, - HTTP_PROVIDERS - ]); - // #enddocregion routeparams - - it('should fetch phone detail', - inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { - return tcb.createAsync(PhoneDetailComponent) - .then((fixture: ComponentFixture) => { - fixture.detectChanges(); - let compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1')).toHaveText(xyzPhoneData().name); - }); + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CheckmarkPipe, PhoneDetailComponent ], + providers: [ + { provide: Phone, useClass: MockPhone }, + { provide: ActivatedRoute, useValue: new ActivatedRouteMock({ params: { 'phoneId': 1 } }) } + ] + }) + .compileComponents(); })); + // #enddocregion activatedroute + + it('should fetch phone detail', () => { + const fixture = TestBed.createComponent(PhoneDetailComponent); + fixture.detectChanges(); + let compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain(xyzPhoneData().name); + }); }); diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-detail/phone-detail.component.ts b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-detail/phone-detail.component.ts index 7d42e20dee..ceba9a6f70 100644 --- a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-detail/phone-detail.component.ts +++ b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-detail/phone-detail.component.ts @@ -1,25 +1,25 @@ // #docplaster // #docregion -import { Component } from '@angular/core'; -import { RouteParams } from '@angular/router-deprecated'; +import { Component } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + import { Phone, PhoneData } from '../core/phone/phone.service'; -import { CheckmarkPipe } from '../core/checkmark/checkmark.pipe'; @Component({ moduleId: module.id, selector: 'phone-detail', - templateUrl: 'phone-detail.template.html', - pipes: [ CheckmarkPipe ] + templateUrl: 'phone-detail.template.html' }) export class PhoneDetailComponent { phone: PhoneData; mainImageUrl: string; - constructor(routeParams: RouteParams, phone: Phone) { - phone.get(routeParams.get('phoneId')).subscribe(phone => { - this.phone = phone; - this.setImage(phone.images[0]); - }); + constructor(activatedRoute: ActivatedRoute, phone: Phone) { + phone.get(activatedRoute.snapshot.params['phoneId']) + .subscribe((p: PhoneData) => { + this.phone = p; + this.setImage(p.images[0]); + }); } setImage(imageUrl: string) { diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-list/phone-list.component.spec.ts b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-list/phone-list.component.spec.ts index 3d6cd93b15..834c93df8f 100644 --- a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-list/phone-list.component.spec.ts +++ b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-list/phone-list.component.spec.ts @@ -1,42 +1,21 @@ /* tslint:disable */ // #docregion routestuff -import { Directive } from '@angular/core'; -import { HTTP_PROVIDERS } from '@angular/http'; -import { - Router, - RouterLink, - RootRouter, - RouteRegistry, - ROUTER_PRIMARY_COMPONENT -} from '@angular/router-deprecated'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; import { Observable } from 'rxjs/Rx'; -import { - describe, - addProviders, - inject, - it, - expect, - // MockApplicationRef -} from '@angular/core/testing'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { SpyLocation } from '@angular/common/testing'; -import { - TestComponentBuilder, - ComponentFixture -} from '@angular/core/testing'; -import { AppComponent } from '../app.component'; import { PhoneListComponent } from './phone-list.component'; import { Phone, PhoneData } from '../core/phone/phone.service'; // #enddocregion routestuff -@Directive({ - selector: '[routerLink]', - inputs: ['routeParams: routerLink', 'target: target'] -}) -class RouterLinkMock {} +class ActivatedRouteMock { + constructor(public snapshot: any) {} +} -class MockPhone extends Phone { +class MockPhone { query(): Observable { return Observable.of([ {name: 'Nexus S', snippet: '', images: []}, @@ -45,52 +24,48 @@ class MockPhone extends Phone { } } +let fixture: ComponentFixture; + describe('PhoneList', () => { // #docregion routestuff - addProviders([ - RouteRegistry, - { provide: Router, useClass: RootRouter }, - { provide: ROUTER_PRIMARY_COMPONENT, useValue: AppComponent }, - { provide: Location, useClass: SpyLocation}, - { provide: Phone, useClass: MockPhone}, - HTTP_PROVIDERS - ]); + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ PhoneListComponent ], + providers: [ + { provide: ActivatedRoute, useValue: new ActivatedRouteMock({ params: { 'phoneId': 1 } }) }, + { provide: Location, useClass: SpyLocation }, + { provide: Phone, useClass: MockPhone }, + ], + schemas: [ NO_ERRORS_SCHEMA ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PhoneListComponent); + }); // #enddocregion routestuff - it('should create "phones" model with 2 phones fetched from xhr', - inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { - return tcb - .overrideDirective(AppComponent, RouterLink, RouterLinkMock) - .overrideDirective(PhoneListComponent, RouterLink, RouterLinkMock) - .createAsync(PhoneListComponent) - .then((fixture: ComponentFixture) => { - fixture.detectChanges(); - let compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelectorAll('.phone-list-item').length).toBe(2); - expect( - compiled.querySelector('.phone-list-item:nth-child(1)').textContent - ).toContain('Motorola DROID'); - expect( - compiled.querySelector('.phone-list-item:nth-child(2)').textContent - ).toContain('Nexus S'); - }); - })); + it('should create "phones" model with 2 phones fetched from xhr', () => { + fixture.detectChanges(); + let compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelectorAll('.phone-list-item').length).toBe(2); + expect( + compiled.querySelector('.phone-list-item:nth-child(1)').textContent + ).toContain('Motorola DROID'); + expect( + compiled.querySelector('.phone-list-item:nth-child(2)').textContent + ).toContain('Nexus S'); + }); - it('should set the default value of orderProp model', - inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { - return tcb - .overrideDirective(AppComponent, RouterLink, RouterLinkMock) - .overrideDirective(PhoneListComponent, RouterLink, RouterLinkMock) - .createAsync(PhoneListComponent) - .then((fixture: ComponentFixture) => { - fixture.detectChanges(); - let compiled = fixture.debugElement.nativeElement; - expect( - compiled.querySelector('select option:last-child').selected - ).toBe(true); - }); - })); + xit('should set the default value of orderProp model', () => { + fixture.detectChanges(); + let compiled = fixture.debugElement.nativeElement; + expect( + compiled.querySelector('select option:last-child').selected + ).toBe(true); + }); }); diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-list/phone-list.component.ts b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-list/phone-list.component.ts index e97e740415..abbe27c5f2 100644 --- a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-list/phone-list.component.ts +++ b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-list/phone-list.component.ts @@ -1,14 +1,13 @@ // #docplaster // #docregion top import { Component } from '@angular/core'; -import { RouterLink } from '@angular/router-deprecated'; + import { Phone, PhoneData } from '../core/phone/phone.service'; @Component({ moduleId: module.id, selector: 'phone-list', templateUrl: 'phone-list.template.html', - directives: [ RouterLink ] }) // #enddocregion top export class PhoneListComponent { @@ -41,20 +40,20 @@ export class PhoneListComponent { } private sortPhones(phones: PhoneData[]) { - if (phones && this.orderProp) { - return phones - .slice(0) // Make a copy - .sort((a, b) => { - if (a[this.orderProp] < b[this.orderProp]) { - return -1; - } else if ([b[this.orderProp] < a[this.orderProp]]) { - return 1; - } else { - return 0; - } - }); - } - return phones; + if (phones && this.orderProp) { + return phones + .slice(0) // Make a copy + .sort((a, b) => { + if (a[this.orderProp] < b[this.orderProp]) { + return -1; + } else if ([b[this.orderProp] < a[this.orderProp]]) { + return 1; + } else { + return 0; + } + }); + } + return phones; } // #enddocregion getphones // #docregion initialclass diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-list/phone-list.template.html b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-list/phone-list.template.html index 9846664768..b4a994b297 100644 --- a/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-list/phone-list.template.html +++ b/public/docs/_examples/upgrade-phonecat-3-final/ts/app/phone-list/phone-list.template.html @@ -26,10 +26,10 @@ diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/karma.conf.ng1.js b/public/docs/_examples/upgrade-phonecat-3-final/ts/karma.conf.ng1.js index 48cc490f89..3decfbdd3e 100644 --- a/public/docs/_examples/upgrade-phonecat-3-final/ts/karma.conf.ng1.js +++ b/public/docs/_examples/upgrade-phonecat-3-final/ts/karma.conf.ng1.js @@ -63,11 +63,10 @@ module.exports = function(config) { frameworks: ['jasmine'], - browsers: ['Chrome', 'Firefox'], + browsers: ['Chrome'], plugins: [ 'karma-chrome-launcher', - 'karma-firefox-launcher', 'karma-jasmine' ] diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/systemjs.config.1.js b/public/docs/_examples/upgrade-phonecat-3-final/ts/systemjs.config.1.js index a54f8bb20c..592029cd65 100644 --- a/public/docs/_examples/upgrade-phonecat-3-final/ts/systemjs.config.1.js +++ b/public/docs/_examples/upgrade-phonecat-3-final/ts/systemjs.config.1.js @@ -1,59 +1,47 @@ /** - * System configuration for Angular 2 samples + * System configuration for Angular samples * Adjust as necessary for your application needs. */ -(function(global) { - - // map tells the System loader where to look for things +(function (global) { // #docregion paths - var map = { - 'app': '/app', // 'dist', - - '@angular': '/node_modules/@angular', - 'angular-in-memory-web-api': '/node_modules/angular-in-memory-web-api', - 'rxjs': '/node_modules/rxjs' - }; - - var packages = { - '/app': { main: 'main.js', defaultExtension: 'js' }, - 'rxjs': { defaultExtension: 'js' }, - 'angular-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' }, - }; - // #enddocregion paths - - var ngPackageNames = [ - 'common', - 'compiler', - 'core', - 'forms', - 'http', - 'platform-browser', - 'platform-browser-dynamic', - 'router', - 'router-deprecated', - 'upgrade', - ]; - - // Individual files (~300 requests): - function packIndex(pkgName) { - packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' }; - } - - // Bundled (~40 requests): - function packUmd(pkgName) { - packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' }; - } - - var setPackageConfig = System.packageWithIndex ? packIndex : packUmd; - - // Add package entries for angular packages - ngPackageNames.forEach(setPackageConfig); - - var config = { - map: map, - packages: packages - } - - System.config(config); + System.config({ + paths: { + // paths serve as alias + 'npm:': '/node_modules/' + }, + map: { + app: '/app', + // #enddocregion paths + // angular bundles + '@angular/core': 'npm:@angular/core/bundles/core.umd.js', + '@angular/common': 'npm:@angular/common/bundles/common.umd.js', + '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', + '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', + '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', + '@angular/http': 'npm:@angular/http/bundles/http.umd.js', + '@angular/router': 'npm:@angular/router/bundles/router.umd.js', + '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', + '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js', + // other libraries + 'rxjs': 'npm:rxjs', + 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api', + // #docregion paths + }, + // #enddocregion paths + // packages tells the System loader how to load when no filename and/or no extension + packages: { + 'app': { + main: './main.js', + defaultExtension: 'js' + }, + rxjs: { + defaultExtension: 'js' + }, + 'angular-in-memory-web-api': { + main: './index.js', + defaultExtension: 'js' + } + } + }); })(this); diff --git a/public/docs/ts/latest/guide/upgrade.jade b/public/docs/ts/latest/guide/upgrade.jade index 438ede147e..c5ce0ef1be 100644 --- a/public/docs/ts/latest/guide/upgrade.jade +++ b/public/docs/ts/latest/guide/upgrade.jade @@ -1,10 +1,5 @@ include ../_util-fns -.alert.is-important - :marked - This guide is still in the process of being updated to RC5 and it's samples - may not work correctly. - :marked Having an existing Angular 1 application doesn't mean that we can't begin enjoying everything Angular 2 has to offer. That's because Angular 2 @@ -28,13 +23,13 @@ include ../_util-fns make incremental upgrading seamless. 1. [Preparation](#preparation) - 1. [Following The Angular Style Guide](#following-the-angular-style-guide) + 1. [Follow the Angular Style Guide](#follow-the-angular-style-guide) 2. [Using a Module Loader](#using-a-module-loader) 3. [Migrating to TypeScript](#migrating-to-typescript) 4. [Using Component Directives](#using-component-directives) 2. [Upgrading with The Upgrade Adapter](#upgrading-with-the-upgrade-adapter) 1. [How The Upgrade Adapter Works](#how-the-upgrade-adapter-works) - 2. [Bootstrapping Hybrid Angular 1+2 Applications](#bootstrapping-hybrid-angular-1-2-applications) + 2. [Bootstrapping hybrid Angular 1+2 Applications](#bootstrapping-hybrid-angular-1-2-applications) 3. [Using Angular 2 Components from Angular 1 Code](#using-angular-2-components-from-angular-1-code) 4. [Using Angular 1 Component Directives from Angular 2 Code](#using-angular-1-component-directives-from-angular-2-code) 5. [Projecting Angular 1 Content into Angular 2 Components](#projecting-angular-1-content-into-angular-2-components) @@ -44,7 +39,7 @@ include ../_util-fns 3. [PhoneCat Upgrade Tutorial](#phonecat-upgrade-tutorial) 1. [Switching to TypeScript](#switching-to-typescript) 2. [Installing Angular 2](#installing-angular-2) - 3. [Bootstrapping A Hybrid 1+2 PhoneCat](#bootstrapping-a-hybrid-1-2-phonecat) + 3. [Bootstrapping a hybrid 1+2 PhoneCat](#bootstrapping-a-hybrid-1-2-phonecat) 4. [Upgrading the Phone service](#upgrading-the-phone-service) 5. [Upgrading Components](#upgrading-components) 6. [Switching To The Angular 2 Router And Bootstrap](#switching-to-the-angular-2-router-and-bootstrap) @@ -61,7 +56,7 @@ include ../_util-fns and patterns that we can apply to future proof our apps even before we begin the migration. - ## Following The Angular Style Guide + ## Follow the Angular Style Guide The [Angular 1 Style Guide](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#single-responsibility) collects patterns and practices that have been proven to result in @@ -84,6 +79,7 @@ include ../_util-fns components easy to navigate and find, but will also allow us to migrate them between languages and frameworks one at a time. In this example application, each controller, component, service, and filter is in its own source file. + * The [Folders-by-Feature Structure](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#folders-by-feature-structure) and [Modularity](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#modularity) rules define similar principles on a higher level of abstraction: Different parts of the @@ -390,6 +386,26 @@ figure.image-display as regular Angular 2 inputs and set onto the scope (or controller) when they change. + ## Using the Upgrade Adapter with Angular 2 _NgModules_ + + Both Angular 1 and Angular 2 have their own concept of modules + to help organize an application into cohesive blocks of funcionality. + + Their details are quite different in architecture and implementation. + In Angular 1, you add Angular assets to the `angular.module` property. + In Angular 2, you create one or more classes adorned with an `NgModule` decorator + that describes Angular assets in metadata. The differences blossom from there. + + In a hybrid application we run both versions of Angular at the same time. + That means that we need at least one module each from both Angular 1 and Angular 2. + We will give the Angular 2 module to the `UpgradeAdapter` while we use the + Angular 1 module for bootstrapping. Let's see how. + +.l-sub-section + :marked + Learn more about Angular 2 modules at the [NgModule guide](ngmodule.html). + +:marked ## Bootstrapping Hybrid Angular 1+2 Applications The first step to upgrading an application using the `UpgradeAdapter` is @@ -416,28 +432,30 @@ figure.image-display +makeExample('upgrade-adapter/ts/app/1-bootstrap/app.module.ts', 'bootstrap') :marked - To then switch the application into hybrid mode, we must first - install Angular 2 to the project. Follow the instructions in - [the QuickStart](../quickstart.html) for some pointers on this. - When we have Angular 2 installed, we can import and instantiate - the `UpgradeAdapter`, and then call its `bootstrap` method. It - is designed to take the exact same arguments as - [angular.bootstrap](https://docs.angularjs.org/api/ng/function/angular.bootstrap) - so that it is easy to make the switch: + Now introduce Angular 2 to the project. Inspired by instructions in + [the QuickStart](../quickstart.html), you can selectively copy in material from the + QuickStart github repository. + + Next, create an `app.module.ts` file and add the following `NgModule` class: + ++makeExample('upgrade-adapter/ts/app/1-2-hybrid-bootstrap/app.module.ts', 'ngmodule') + +:marked + This bare minimum `NgModule` imports `BrowserModule`, the module every Angular browser-based app must have. + + Import and instantiate the `UpgradeAdapter` with the new `AppModule` and call its `bootstrap` method. + That method takes the exact same arguments as [angular.bootstrap](https://docs.angularjs.org/api/ng/function/angular.bootstrap): +makeExample('upgrade-adapter/ts/app/1-2-hybrid-bootstrap/app.module.ts', 'bootstrap') :marked - At this point we'll be running a hybrid Angular 1+2 application! All the - existing Angular 1 code will work as it always did, but we are now ready - to run Angular 2 code as well. + Congratulations! You're running a hybrid Angular 1+2 application! The + existing Angular 1 code works as before _and_ you're ready to run Angular 2 code. .alert.is-helpful :marked - One notable difference between `angular.bootstrap` and - `upgradeAdapter.bootstrap` is that the latter works *asynchronously*. - This means that we cannot assume that the application has been instantiated - immediately after the bootstrap call returns. + Note that, unlike `angular.bootstrap`, the `upgradeAdapter.bootstrap` runs *asynchronously*. + The application is not launched immediately. Some time must pass after the bootstrap call returns. :marked As we begin to migrate components to Angular 2, we'll be using the @@ -476,16 +494,25 @@ figure +makeExample('upgrade-adapter/ts/app/downgrade-static/app.module.ts', 'downgradecomponent') :marked - What we have here is an Angular 1 directive called `heroDetail`, which we can + Because `HeroDetailComponent` is an Angular 2 component, we must also add it to the `declarations` in the `AppModule`. + ++makeExample('upgrade-adapter/ts/app/downgrade-static/app.module.ts', 'ngmodule') +.l-sub-section + :marked + All Angular 2 components, directives and pipes must be declared in an NgModule. + +:marked + The net resulit is an Angular 1 directive called `heroDetail`, that we can use like any other directive in our Angular 1 templates. +makeExample('upgrade-adapter/ts/index-downgrade-static.html', 'usecomponent') .alert.is-helpful :marked - Note that since Angular 1 directives are matched based on their name, - *the selector metadata of the Angular 2 component is not used in Angular 1*. - It is matched as an element directive (`restrict: 'E'`) called `heroDetail`. + Note that this Angular 1 is an element directive (`restrict: 'E'`) called `heroDetail`. + An Angular 1 element directive is matched based on its _name_. + *The `selector` metadata of the downgraded Angular 2 component is ignored.* + :marked Most components are not quite this simple, of course. Many of them @@ -558,11 +585,10 @@ figure :marked We can *upgrade* this component to Angular 2 using the `UpgradeAdapter`'s `upgradeNg1Component` method. It takes the name of an Angular 1 component - directive and returns an Angular 2 **component class**. When we then - want to use it from an Angular 2 component, we list it the in the `directives` - metadata of the component and then just use it in the Angular 2 template: + directive and returns an Angular 2 **component class**. + Declare it in an `NgModule` as with other Angular 2 components: -+makeExample('upgrade-adapter/ts/app/upgrade-static/container.component.ts', null, 'container.component.ts') ++makeExample('upgrade-adapter/ts/app/upgrade-static/upgrade_adapter.ts', 'heroupgrade', 'app.module.ts') .alert.is-helpful :marked @@ -731,17 +757,14 @@ figure +makeExample('upgrade-adapter/ts/app/2-to-1-providers/heroes.ts', null, 'heroes.ts') :marked - We can again use the `UpgradeAdapter` for this, but first we need to register `Heroes` - to the Angular 2 injector itself. In a pure Angular 2 application we would do this - when we bootstrap the app, as described in the [dependency injection guide](dependency-injection.html#!#providers). - But since hybrid applications are bootstrapped using the `UpgradeAdapter`, we also - need to register our Angular 2 providers using `UpgradeAdapter`. It has a method - called `addProvider` for this purpose. + Again, as with Angular 2 components, register the provider with the `NgModule` by adding it to the module's `providers` list. - Once we've registered the Angular 2 provider, we can turn `Heroes` into an *Angular 1 - factory function* using `upgradeAdapter.downgradeNg2Provider()`. We can - then plug the factory into an Angular 1 module, at which point we also choose what the - name of the dependency will be in Angular 1: ++makeExample('upgrade-adapter/ts/app/2-to-1-providers/upgrade_adapter.ts', 'ngmodule', 'app.module.ts') + +:marked + Now wrap the Angular 2 `Heroes` in an *Angular 1 factory function* using `upgradeAdapter.downgradeNg2Provider()`. + and plug the factory into an Angular 1 module. + The name of the Angular 1 dependency is up to you: +makeExample('upgrade-adapter/ts/app/2-to-1-providers/app.module.ts', 'register', 'app.module.ts') @@ -1033,7 +1056,7 @@ code-example(format=""). development server root path in `package.json` to also point to the project root instead of `app`: -+makeJson('upgrade-phonecat-2-hybrid/ts/package.ng1.json', {paths: 'scripts.start'}, 'package.json') ++makeJson('upgrade-phonecat-2-hybrid/ts/package.ng1.json', {paths: 'scripts.start'}, 'package.json (start script)') :marked Now we're able to serve everything from the project root to the web browser. But we do *not* @@ -1058,7 +1081,22 @@ code-example(format=""). +makeExample('upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js', 'paths', 'systemjs.config.js') :marked - ## Bootstrapping A Hybrid 1+2 PhoneCat + ## Creating the _AppModule_ + + Now create the root `NgModule` class called `AppModule`. + There is already a file named `app.module.ts` that holds the Angular 1 module. + Rename it to `app.module.ng1.ts` and update the corresponding script name in the `index.html` as well. + The file contents remain: + ++makeExample('upgrade-phonecat-2-hybrid/ts/app/app.module.ng1.ts', null, 'app.module.ng1.ts') + +:marked + Now create a new `app.module.ts` with the minimum `NgModule` class: + ++makeExample('upgrade-phonecat-2-hybrid/ts/app/app.module.ts', 'bare', 'app.module.ts') + +:marked + ## Bootstrapping a hybrid 1+2 PhoneCat What we'll do next is bootstrap the application as a *hybrid application* that supports both Angular 1 and Angular 2 components. Once we've done that @@ -1109,32 +1147,19 @@ code-example(format=""). * For loading the details of a single phone into the phone detail component. We can replace this implementation with an Angular 2 service class, while - keeping our controllers in Angular 1 land. In the new version we'll just use - the `Http` service from Angular 2 instead of ngResource. + keeping our controllers in Angular 1 land. + + In the new version, we import the Angular 2 HTTP module and call its `Http` service instead of `ngResource`. - Before the `Http` service is available for injection, we need to register - it into our application's dependency injector. We should import the `HTTP_PROVIDERS` - constant in `main.ts`: + Re-open the `app.module.ts` file, import and add `HttpModule` to the `imports` array of the `AppModule`: -+makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'import-http') - -:marked - In a regular Angular 2 application we would now pass `HTTP_PROVIDERS` into - the application bootstrap function. But we can't do that in a hybrid - application such as the one we're working on. That's because the `bootstrap` - method of `UpgradeAdapter` expects Angular 1 modules as dependencies, - not Angular 2 providers. - - What we must do instead is register `HTTP_PROVIDERS` into the `UpgradeAdapter` - separately. It has a method called `addProvider` for that purpose: - -+makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'add-http') ++makeExample('upgrade-phonecat-2-hybrid/ts/app/app.module.ts', 'httpmodule', 'app.module.ts') :marked Now we're ready to upgrade the Phone service itself. We replace the ngResource-based service in `phone.service.ts` with a TypeScript class decorated as `@Injectable`: -+makeExample('upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts', 'classdef', 'app/core/phone/phone.service.ts') ++makeExample('upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts', 'classdef', 'app/core/phone/phone.service.ts (skeleton)')(format='.') :marked The `@Injectable` decorator will attach some dependency injection metadata @@ -1154,7 +1179,7 @@ code-example(format=""). The methods now return Observables of type `PhoneData` and `PhoneData[]`. This is a type we don't have yet, so let's add a simple interface for it: -+makeExample('upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts', 'phonedata-interface', 'app/core/phone/phone.service.ts') ++makeExample('upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts', 'phonedata-interface', 'app/core/phone/phone.service.ts (interface)')(format='.') :marked Here's the full, final code for the service: @@ -1166,24 +1191,17 @@ code-example(format=""). We need to do this for all RxJS operators that we want to use, since Angular 2 does not load all of them by default. - The new `Phone` service now has the same features that the original, ngResource based - service did. Now we just need to register the new service into the application, so that - our Angular 1 components will be able to use it. + The new `Phone` service has the same features as the original, `ngResource`-based service. + Because it's an Angular 2 service, we register it with the `NgModule` providers: ++makeExample('upgrade-phonecat-2-hybrid/ts/app/app.module.ts', 'phone', 'app.module.ts') +:marked `UpgradeAdapter` has a `downgradeNg2Provider` method for the purpose of making - Angular 2 services available to Angular 1 code. We can use it to plug in our - `Phone` service: + Angular 2 services available to Angular 1 code. Use it to plug in the `Phone` service: -+makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'phone-service', 'app/main.ts') ++makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'phone-service', 'app/main.ts (excerpt)')(format='.') :marked - Note that we actually needed to do two registrations here: - - 1. Register `Phone` as an **Angular 2 provider** with the `addProvider` - method. That's the same method that we used earlier for `HTTP_PROVIDERS`. - 2. Register an **Angular 1 factory** called `phone`, which will be a *downgraded* - version of the `Phone` Angular 2 service. - Now that we are loading `phone.service.ts` through an import that is resolved by SystemJS, we should **remove the <script> tag** for the service from `index.html`. This is something we'll do to all our components as we upgrade them. Simultaneously @@ -1234,69 +1252,72 @@ code-example(format=""). just like the Angular 1 version did. We now also need to convert the template of this component into Angular 2 syntax. - In the search controls we need to use Angular 2 syntax for the two `ngModel`s. - We should also no longer use the `$ctrl` prefix in expressions: + The search controls replace the Angular 1 `$ctrl` expressions + with Angular 2's two-way `[(ngModel)]` binding syntax: -+makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.template.html', 'controls', 'app/phone-list/phone-list.template.html') ++makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.template.html', 'controls', 'app/phone-list/phone-list.template.html (search controls)')(format='.') :marked - In the list we need to replace the `ng-repeat` with an `*ngFor` and the - `let var of iterable` syntax, which is [described in our - Template Syntax guide](../guide/template-syntax.html#directives). - For the images, we can replace `ng-src` with a binding to the standard `src` property. + Replace the list's `ng-repeat` with an `*ngFor` as + [described in the Template Syntax page](../guide/template-syntax.html#directives). + Replace the image tag's `ng-src` with a binding to the native `src` property. -+makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.template.html', 'list', 'app/phone-list/phone-list.template.html') ++makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.template.html', 'list', 'app/phone-list/phone-list.template.html (phones)')(format='.') :marked - Another thing that we've done here is that we've removed the use of `filter` and `orderBy` filters, - and replaced them with a call to the `getPhones()` controller method. - The built-in Angular filters `filter` and `orderBy` do not exist in Angular 2, - so we need to do the filtering and sorting ourselves. We could define our own Angular 2 - pipes for this purpose, but in this case it is more convenient to just implement the filtering - and ordering logic in the component itself. We expect the `getPhones()` method to return a collection - where the current filtering and ordering has been applied. + ### No Angular 2 _filter_ or _orderBy_ filters + The built-in Angular 1 `filter` and `orderBy` filters do not exist in Angular 2, + so we need to do the filtering and sorting ourselves. + + We replaced the `filter` and `orderBy` filters with bindings to the `getPhones()` controller method, + which implements the filtering and ordering logic inside the component itself. +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ts', 'getphones', 'app/phone-list/phone-list.component.ts') :marked - In the entrypoint file `main.ts` we're going to plug this component into our application. Instead - of registering a component, we register a `phoneList` *directive*. - The directive is a downgraded version of our Angular 2 component, and the `UpgradeAdapter` - handles the bridging between the two: + The new `PhoneListComponent` uses the Angular 2 `ngModel` directive, located in the `FormsModule`. + Add the `FormsModule` to `NgModule` imports and declare the new `PhoneListComponent` : -+makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'phone-list', 'app/main.ts') ++makeExample('upgrade-phonecat-2-hybrid/ts/app/app.module.ts', 'phonelist', 'app.module.ts') :marked - The `` type annotation here is to let the TypeScript compiler - know that the return value of the downgrade method call will be something that can be - used as a directive factory. + In the entrypoint file `main.ts` we'll plug this component into the Angular 1 module. + + Instead of registering a component, we register a `phoneList` *directive*, a downgraded version of the Angular 2 component. + The `UpgradeAdapter` creates the bridge between the two: - At this point, also remove the <script> tag for the phone list component from `index.html`. ++makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'phone-list', 'app/main.ts (excerpt)')(format='.') - Now we can start looking at our other component, which is the one for - the phone details. Set the contents of `phone-detail.component.ts` as follows: +:marked + The `as angular.IDirectiveFactory` cast tells the TypeScript compiler + that the return value of the downgrade method is a directive factory. + + Remove the <script> tag for the phone list component from `index.html`. + + Now set the remaining `phone-detail.component.ts` as follows: +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ts', 'initialclass', 'app/phone-detail/phone-detail.component.ts') :marked - This is pretty similar to what we did with the phone list. The one new change - here is the use of `@Inject` for the `$routeParams` dependency. It tells the - Angular 2 injector what this dependency should map to. We have a dependency called - `$routeParams` in the Angular 1 injector, where it is provided by the Angular 1 router. - That is what we were already using when `PhoneDetails` was still an Angular 1 controller. + This is similar to the phone list component. + The new wrinkle is the `@Inject` decorator that identifies the `$routeParams` dependency. - The things is though, Angular 1 dependencies are not made automatically available to - Angular 2 components, so if we were to run this now, it would not work. We need to explicitly - tell the `UpgradeAdapter` to upgrade `$routeParams` so that it is available for injection in - Angular 2. We can do it in `main.ts`: - -+makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'routeparams', 'app/main.ts') + The Angular 1 injector has an Angular 1 router dependency called `$routeParams`. + which was injected into `PhoneDetails` when it was still an Angular 1 controller. + We intend to inject it into the new `PhoneDetailsComponent`. + + Unfortunately, Angular 1 dependencies are not automatically available to Angular 2 components. + We must use the `UpgradeAdapter` to make the `$routeParams` an Angular 2 provider. + Do that in `main.ts`: ++makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'routeparams', 'app/main.ts ($routeParms)')(format='.') +.l-sub-section + :marked + Do not register an upgraded Angular 1 provider in the `NgModule`. :marked - We now also need to convert the template of this component into Angular 2 syntax. - Here is the new template in its entirety: + Convert the phone detail component template into Angular 2 syntax as follows: +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.template.html', null, 'app/phone-detail/phone-detail.template.html') @@ -1320,118 +1341,135 @@ code-example(format=""). when we try to refer to properties on undefined objects. We need to be explicit about cases where this is expected. + Add this component to the `NgModule` _declarations_: + ++makeExample('upgrade-phonecat-2-hybrid/ts/app/app.module.ts', 'phonedetail', 'app.module.ts') + :marked In `main.ts` we'll now register a `phoneDetail` directive instead of a component. The directive is a downgraded version of the `PhoneDetail` Angular 2 component. -+makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'phone-detail', 'app/main.ts') ++makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'phone-detail', 'app/main.ts (excerpt)')(format='.') :marked We should now also remove the phone detail component <script> tag from `index.html`. - There's one additional step we need to take, which is to upgrade the - `checkmark` filter that the template is using. We need an Angular 2 - pipe instead of an Angular 1 filter. + ### Add the _CheckmarkPipe_ - While there is no upgrade method in the upgrade adapter for filters, we - can just turn the filter function into a class that fulfills - the contract for Angular 2 Pipes. The implementation is the same as before. - It just comes in a different kind of packaging. While changing it, also - rename the file to `checkmark.pipe.ts`: + The Angular 1 directive had a `checkmark` _filter_. + Turn that into an Angular 2 **pipe**. -+makeExample('upgrade-phonecat-2-hybrid/ts/app/core/checkmark/checkmark.pipe.ts', null, 'app/core/checkmark/checkmark.pipe.ts') + There is no upgrade adapter method to convert filters into pipes. + You won't miss it. + It's easy to turn the filter function into an equivalent Pipe class. + The implementation is the same as before, repackaged in the `transform` method. + Rename the file to `checkmark.pipe.ts` to conform with Angular 2 conventions: + ++makeExample('upgrade-phonecat-2-hybrid/ts/app/core/checkmark/checkmark.pipe.ts', null, 'app/core/checkmark/checkmark.pipe.ts')(format='.') :marked - In the component we should now import and declare our newly created pipe (as well as - remove the filter <script> tag from `index.html`): + Now import and declare the newly created pipe and + remove the filter <script> tag from `index.html`: -+makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ts', 'checkmark-pipe', 'app/phone-detail/phone-detail.component.ts') ++makeExample('upgrade-phonecat-2-hybrid/ts/app/app.module.ts', 'checkmarkpipe', 'app.module.ts') :marked ## Switching To The Angular 2 Router And Bootstrap - At this point we've replaced all our Angular 1 application components with - their Angular 2 counterparts. The application is still bootstrapped as a hybrid, - but there isn't really any need for that anymore, and we can begin to - pull out the last remnants of Angular 1. + At this point we've replaced all Angular 1 application components with + their Angular 2 counterparts. + + The application is still bootstrapped as a hybrid app. + There's no need for that anymore. + It's time to remove the last remnants of Angular 1 in two final steps: + 1. Switch to the Angular 2 router. + 1. Bootstrap as a pure Angular 2 app. - There are just two more things to do: We need to switch the router to - the Angular 2 one, and then bootstrap the app as a pure Angular 2 app. + ### Switch to the Angular 2 router + Angular 2 has an [all-new router](router.html). - Let's do the routing part first. Angular 2 comes with an [all-new router](router.html) - that we can use for this. + Like all routers, it needs a place in the UI to display routed views. + The Angular 2 that's the `` and it belongs in a *root component* + at the top of the applications component tree. + + We don't yet have such a root component, because the app is still managed as an Angular 1 app. + Create a new `app.component.ts` file with the following `AppComponent` class: - Angular 2 applications all have a *root component*, which, among other - things, is where we should plug in the router. We don't yet have such a root - component, because our app is still managed as an Angular 1 app. - Let's change this now and add an `AppComponent` class into a new file - `app.component.ts`: - -+makeExample('upgrade-phonecat-3-final/ts/app/app.component.ts', null, 'app/app.component.ts') ++makeExample('upgrade-phonecat-3-final/ts/app/app.component.ts', null, 'app/app.component.ts')(format='.') :marked - This is a component that plugs in to an `` element on the page, - and has a simple template that only includes the router outlet component - of the Angular router. This means that the component just renders the contents - of the current route and nothing else. The `@RouteConfig` decorator defines - the Angular 2 counterparts of our two routes. They refer directly to the - two components. + It has a simple template that only includes the ``. + This component just renders the contents of the active route and nothing else. + + The selector tells Angular 2 to plug this root component into the `` + element on the host web page when the application launches. - We should put this `` element in the HTML so that the root component - has something to attach to. It replaces the old Angular 1 `ng-view` directive: + Add this `` element to the `index.html`. + It replaces the old Angular 1 `ng-view` directive: -+makeExample('upgrade-phonecat-3-final/ts/index.html', 'appcomponent', 'index.html') ++makeExample('upgrade-phonecat-3-final/ts/index.html', 'appcomponent', 'index.html (body)')(format='.') :marked - In the `PhoneDetail` component we now need to change how the phone id parameter - is received. There will be no more `$routeParams` injection available, because - that comes from the Angular 1 router. Instead, what we have is a `RouteParams` - object provided by the Angular 2 router. We use it to obtain the `phoneId` from - the params: + ### Create the _Routing Module_ + A router needs configuration whether it's the Angular 1 or Angular 2 or any other router. + + The details of Angular 2 router configuration are best left to the [Routing](../router.html) documentation + which recommends that you create a `NgModule` dedicated to router configuration + (called a _Routing Module_): + ++makeExample('upgrade-phonecat-3-final/ts/app/app-routing.module.ts', null, 'app/app-routing.module.ts') + +:marked + This module defines a `routes` object with two routes to the two phone components + and a default route for the empty path. + It passes the `routes` to the `RouterModule.forRoot` method which does the rest. + + A couple of extra providers enable routing with "hash" URLs such as `#!/phones` instead of the default "push state" strategy. + + Now update the `AppModule` to import this `AppRoutingModule` and also the + declare the root `AppComponent`: + ++makeExample('upgrade-phonecat-3-final/ts/app/app.module.ts', null, 'app/app.module.ts') + +:marked + The Angular 2 router passes route parameters differently. + Correct the `PhoneDetail` component constructor to expect an injected `ActivatedRoute` object. + Extract the `phoneId` from the `ActivatedRoute.snapshot.params` and fetch the phone data as before: +makeExample('upgrade-phonecat-3-final/ts/app/phone-detail/phone-detail.component.ts', null, 'app/phone-detail/phone-detail.component.ts') +:marked + ### Generate links for each phone + + We no longer have to hardcode the links to phone details in the phone list. + We can generate them data binding each phone's `id` to the `routerLink` directive + and let that directive construct the appropriate URL to the `PhoneDetailComponent`: + ++makeExample('upgrade-phonecat-3-final/ts/app/phone-list/phone-list.template.html', 'list', 'app/phone-list/phone-list.template.html (list with links)')(format='.') +.l-sub-section + :marked + See the [Routing](../router.html) page for details. :marked - With that, we're ready to switch the bootstrap method of the application from that - of the `UpgradeAdapter` to the main Angular 2 `bootstrap`. Let's import it together - with the router, the new app component, and everything else in `main.ts` + ### Bootstrap as an Angular 2 app -+makeExample('upgrade-phonecat-3-final/ts/app/main.ts', 'imports') + You may have noticed one extra `bootstrap` metadata property added to the `AppModule` ++makeExample('upgrade-phonecat-3-final/ts/app/app.module.ts', 'bootstrap', 'app/app.module.ts (bootstrap)')(format='.') +:marked + That tells Angular 2 that it should bootstrap the app with the _root_ `AppComponent` and + insert it's view into the host web page. + + Now switch the bootstrap method of the application from the `UpgradeAdapter` + to the Angular 2 way. + Because this is a browser application, compiled with the Just-in-Time (JiT) compiler, + use the `platformBrowserDynamic` function to bootstrap the `AppModule`: + ++makeExample('upgrade-phonecat-3-final/ts/app/main.ts', null, 'main.ts') :marked - We'll now use the regular Angular 2 `bootstrap` function to bootstrap the app - instead of using `UpgradeAdapter`. The first argument to `bootstrap` is the - application's root component `AppComponent`, and the second - is an array of the Angular 2 providers that we want to make available for - injection. In that array we include all the things we have been registering - with `upgradeAdapter.addProvider` until now, as well as the providers and - directives of the router: + You are now running a pure Angular 2 application! -+makeExample('upgrade-phonecat-3-final/ts/app/main.ts', 'bootstrap') - -:marked - We also configure a couple of things for the router here so that the application - URL paths match exactly those we had in the Angular 1 app: We want the - hash location strategy with the `!` prefix: `#!/phones`. - - At this point we are running a pure Angular 2 application! - - But there's actually one more cool thing we can do with the new router. - We no longer have to hardcode the links to phone details from the phone - list, because the Angular 2 router is able to generate them for us with - its `routerLink` directive. We just need to refer to the route names we - used in the `@RouteConfig`: - -+makeExample('upgrade-phonecat-3-final/ts/app/phone-list/phone-list.template.html', 'list', 'app/phone-list/phone-list.template.html') - -:marked - For this to work the directive just needs to be declared in the component: - -+makeExample('upgrade-phonecat-3-final/ts/app/phone-list/phone-list.component.ts', 'top') - -:marked - ## Saying Goodbye to Angular 1 + ## Say Goodbye to Angular 1 It is time to take off the training wheels and let our application begin its new life as a pure, shiny Angular 2 app. The remaining tasks all have to @@ -1578,24 +1616,12 @@ code-example(format=""). that use WebDriver's generic URL APIs instead. The first of these is the redirection spec: -.alert.is-important - :marked - This guide is still in the process of being updated to RC5 and it's samples - may not work correctly. - -//- +makeExample('upgrade-phonecat-3-final/e2e-spec.ts', 'redirect', 'e2e-tests/scenarios.ts') ++makeExample('upgrade-phonecat-3-final/e2e-spec.ts', 'redirect', 'e2e-tests/scenarios.ts') :marked And the second is the phone links spec: - -.alert.is-important - :marked - This guide is still in the process of being updated to RC5 and it's samples - may not work correctly. - -//- +makeExample('upgrade-phonecat-3-final/e2e-spec.ts', 'links', 'e2e-tests/scenarios.ts') - ++makeExample('upgrade-phonecat-3-final/e2e-spec.ts', 'links', 'e2e-tests/scenarios.ts') :marked ## Unit Tests @@ -1666,10 +1692,10 @@ code-example(format=""). :marked Finally, we need to revisit both of the component tests when we switch to the Angular 2 - router. For the details component we need to provide an Angular 2 `RouteParams` object + router. For the details component we need to provide a mock of Angular 2 `ActivatedRoute` object instead of using the Angular 1 `$routeParams`. -+makeExample('upgrade-phonecat-3-final/ts/app/phone-detail/phone-detail.component.spec.ts', 'routeparams', 'app/phone-detail/phone-detail.component.spec.ts') ++makeExample('upgrade-phonecat-3-final/ts/app/phone-detail/phone-detail.component.spec.ts', 'activatedroute', 'app/phone-detail/phone-detail.component.spec.ts') :marked And for the phone list component we need to set up a few things for the router itself so that