diff --git a/aio/content/examples/.gitignore b/aio/content/examples/.gitignore index 0aba7ad419..4352bbcdf1 100644 --- a/aio/content/examples/.gitignore +++ b/aio/content/examples/.gitignore @@ -56,6 +56,7 @@ dist/ # TS to JS !cb-ts-to-js/js*/**/*.js +cb-ts-to-js/js*/**/system*.js # webpack !webpack/**/config/*.js diff --git a/aio/content/examples/cb-ts-to-js/js-es6-decorators/src/systemjs-angular-loader.js b/aio/content/examples/cb-ts-to-js/js-es6-decorators/src/systemjs-angular-loader.js deleted file mode 100644 index a0f7c54538..0000000000 --- a/aio/content/examples/cb-ts-to-js/js-es6-decorators/src/systemjs-angular-loader.js +++ /dev/null @@ -1,45 +0,0 @@ -var templateUrlRegex = /templateUrl\s*:(\s*['"`](.*?)['"`]\s*)/gm; -var stylesRegex = /styleUrls *:(\s*\[[^\]]*?\])/g; -var stringRegex = /(['`"])((?:[^\\]\\\1|.)*?)\1/g; - -module.exports.translate = function(load){ - var url = document.createElement('a'); - url.href = load.address; - - var basePathParts = url.pathname.split('/'); - - basePathParts.pop(); - var basePath = basePathParts.join('/'); - - var baseHref = document.createElement('a'); - baseHref.href = this.baseURL; - baseHref = baseHref.pathname; - - basePath = basePath.replace(baseHref, ''); - - load.source = load.source - .replace(templateUrlRegex, function(match, quote, url){ - let resolvedUrl = url; - - if (url.startsWith('.')) { - resolvedUrl = basePath + url.substr(1); - } - - return 'templateUrl: "' + resolvedUrl + '"'; - }) - .replace(stylesRegex, function(match, relativeUrls) { - var urls = []; - - while ((match = stringRegex.exec(relativeUrls)) !== null) { - if (match[2].startsWith('.')) { - urls.push('"' + basePath + match[2].substr(1) + '"'); - } else { - urls.push('"' + match[2] + '"'); - } - } - - return "styleUrls: [" + urls.join(', ') + "]"; - }); - - return load; -}; diff --git a/aio/content/examples/cb-ts-to-js/js-es6-decorators/src/systemjs.config.js b/aio/content/examples/cb-ts-to-js/js-es6-decorators/src/systemjs.config.js deleted file mode 100644 index ea7a3879ac..0000000000 --- a/aio/content/examples/cb-ts-to-js/js-es6-decorators/src/systemjs.config.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * System configuration for Angular samples - * Adjust as necessary for your application needs. - */ -(function (global) { - System.config({ - paths: { - // paths serve as alias - 'npm:': 'node_modules/' - }, - // map tells the System loader where to look for things - map: { - // our app is within the app folder - 'app': 'app', - - // angular bundles - '@angular/animations': 'npm:@angular/animations/bundles/animations.umd.js', - '@angular/animations/browser': 'npm:@angular/animations/bundles/animations-browser.umd.js', - '@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/animations': 'npm:@angular/platform-browser/bundles/platform-browser-animations.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/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js', - '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', - '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js', - '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js', - - // other libraries - 'rxjs': 'npm:rxjs', - 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js' - }, - // packages tells the System loader how to load when no filename and/or no extension - packages: { - app: { - main: './main.js', - defaultExtension: 'js', - meta: { - './*.js': { - loader: 'systemjs-angular-loader.js' - } - } - }, - rxjs: { - defaultExtension: 'js' - } - } - }); -})(this); diff --git a/aio/content/examples/cb-ts-to-js/js-es6/src/systemjs-angular-loader.js b/aio/content/examples/cb-ts-to-js/js-es6/src/systemjs-angular-loader.js deleted file mode 100644 index a0f7c54538..0000000000 --- a/aio/content/examples/cb-ts-to-js/js-es6/src/systemjs-angular-loader.js +++ /dev/null @@ -1,45 +0,0 @@ -var templateUrlRegex = /templateUrl\s*:(\s*['"`](.*?)['"`]\s*)/gm; -var stylesRegex = /styleUrls *:(\s*\[[^\]]*?\])/g; -var stringRegex = /(['`"])((?:[^\\]\\\1|.)*?)\1/g; - -module.exports.translate = function(load){ - var url = document.createElement('a'); - url.href = load.address; - - var basePathParts = url.pathname.split('/'); - - basePathParts.pop(); - var basePath = basePathParts.join('/'); - - var baseHref = document.createElement('a'); - baseHref.href = this.baseURL; - baseHref = baseHref.pathname; - - basePath = basePath.replace(baseHref, ''); - - load.source = load.source - .replace(templateUrlRegex, function(match, quote, url){ - let resolvedUrl = url; - - if (url.startsWith('.')) { - resolvedUrl = basePath + url.substr(1); - } - - return 'templateUrl: "' + resolvedUrl + '"'; - }) - .replace(stylesRegex, function(match, relativeUrls) { - var urls = []; - - while ((match = stringRegex.exec(relativeUrls)) !== null) { - if (match[2].startsWith('.')) { - urls.push('"' + basePath + match[2].substr(1) + '"'); - } else { - urls.push('"' + match[2] + '"'); - } - } - - return "styleUrls: [" + urls.join(', ') + "]"; - }); - - return load; -}; diff --git a/aio/content/examples/cb-ts-to-js/js-es6/src/systemjs.config.js b/aio/content/examples/cb-ts-to-js/js-es6/src/systemjs.config.js deleted file mode 100644 index ea7a3879ac..0000000000 --- a/aio/content/examples/cb-ts-to-js/js-es6/src/systemjs.config.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * System configuration for Angular samples - * Adjust as necessary for your application needs. - */ -(function (global) { - System.config({ - paths: { - // paths serve as alias - 'npm:': 'node_modules/' - }, - // map tells the System loader where to look for things - map: { - // our app is within the app folder - 'app': 'app', - - // angular bundles - '@angular/animations': 'npm:@angular/animations/bundles/animations.umd.js', - '@angular/animations/browser': 'npm:@angular/animations/bundles/animations-browser.umd.js', - '@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/animations': 'npm:@angular/platform-browser/bundles/platform-browser-animations.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/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js', - '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', - '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js', - '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js', - - // other libraries - 'rxjs': 'npm:rxjs', - 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js' - }, - // packages tells the System loader how to load when no filename and/or no extension - packages: { - app: { - main: './main.js', - defaultExtension: 'js', - meta: { - './*.js': { - loader: 'systemjs-angular-loader.js' - } - } - }, - rxjs: { - defaultExtension: 'js' - } - } - }); -})(this); diff --git a/aio/content/examples/cb-ts-to-js/js/src/systemjs-angular-loader.js b/aio/content/examples/cb-ts-to-js/js/src/systemjs-angular-loader.js deleted file mode 100644 index a0f7c54538..0000000000 --- a/aio/content/examples/cb-ts-to-js/js/src/systemjs-angular-loader.js +++ /dev/null @@ -1,45 +0,0 @@ -var templateUrlRegex = /templateUrl\s*:(\s*['"`](.*?)['"`]\s*)/gm; -var stylesRegex = /styleUrls *:(\s*\[[^\]]*?\])/g; -var stringRegex = /(['`"])((?:[^\\]\\\1|.)*?)\1/g; - -module.exports.translate = function(load){ - var url = document.createElement('a'); - url.href = load.address; - - var basePathParts = url.pathname.split('/'); - - basePathParts.pop(); - var basePath = basePathParts.join('/'); - - var baseHref = document.createElement('a'); - baseHref.href = this.baseURL; - baseHref = baseHref.pathname; - - basePath = basePath.replace(baseHref, ''); - - load.source = load.source - .replace(templateUrlRegex, function(match, quote, url){ - let resolvedUrl = url; - - if (url.startsWith('.')) { - resolvedUrl = basePath + url.substr(1); - } - - return 'templateUrl: "' + resolvedUrl + '"'; - }) - .replace(stylesRegex, function(match, relativeUrls) { - var urls = []; - - while ((match = stringRegex.exec(relativeUrls)) !== null) { - if (match[2].startsWith('.')) { - urls.push('"' + basePath + match[2].substr(1) + '"'); - } else { - urls.push('"' + match[2] + '"'); - } - } - - return "styleUrls: [" + urls.join(', ') + "]"; - }); - - return load; -}; diff --git a/aio/content/examples/cb-ts-to-js/js/src/systemjs.config.js b/aio/content/examples/cb-ts-to-js/js/src/systemjs.config.js deleted file mode 100644 index ea7a3879ac..0000000000 --- a/aio/content/examples/cb-ts-to-js/js/src/systemjs.config.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * System configuration for Angular samples - * Adjust as necessary for your application needs. - */ -(function (global) { - System.config({ - paths: { - // paths serve as alias - 'npm:': 'node_modules/' - }, - // map tells the System loader where to look for things - map: { - // our app is within the app folder - 'app': 'app', - - // angular bundles - '@angular/animations': 'npm:@angular/animations/bundles/animations.umd.js', - '@angular/animations/browser': 'npm:@angular/animations/bundles/animations-browser.umd.js', - '@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/animations': 'npm:@angular/platform-browser/bundles/platform-browser-animations.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/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js', - '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', - '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js', - '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js', - - // other libraries - 'rxjs': 'npm:rxjs', - 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js' - }, - // packages tells the System loader how to load when no filename and/or no extension - packages: { - app: { - main: './main.js', - defaultExtension: 'js', - meta: { - './*.js': { - loader: 'systemjs-angular-loader.js' - } - } - }, - rxjs: { - defaultExtension: 'js' - } - } - }); -})(this); diff --git a/aio/content/examples/cli-quickstart/src/styles.css b/aio/content/examples/cli-quickstart/src/styles.css new file mode 100644 index 0000000000..d81835d0cd --- /dev/null +++ b/aio/content/examples/cli-quickstart/src/styles.css @@ -0,0 +1,116 @@ +/* #docregion , quickstart, toh */ +/* Master Styles */ +h1 { + color: #369; + font-family: Arial, Helvetica, sans-serif; + font-size: 250%; +} +h2, h3 { + color: #444; + font-family: Arial, Helvetica, sans-serif; + font-weight: lighter; +} +body { + margin: 2em; +} +/* #enddocregion quickstart */ +body, input[text], button { + color: #888; + font-family: Cambria, Georgia; +} +/* #enddocregion toh */ +a { + cursor: pointer; + cursor: hand; +} +button { + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; + cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +button:disabled { + background-color: #eee; + color: #aaa; + cursor: auto; +} + +/* Navigation link styles */ +nav a { + padding: 5px 10px; + text-decoration: none; + margin-right: 10px; + margin-top: 10px; + display: inline-block; + background-color: #eee; + border-radius: 4px; +} +nav a:visited, a:link { + color: #607D8B; +} +nav a:hover { + color: #039be5; + background-color: #CFD8DC; +} +nav a.active { + color: #039be5; +} + +/* items class */ +.items { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 24em; +} +.items li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; +} +.items li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; +} +.items li.selected { + background-color: #CFD8DC; + color: white; +} +.items li.selected:hover { + background-color: #BBD8DC; +} +.items .text { + position: relative; + top: -3px; +} +.items .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; +} +/* #docregion toh */ +/* everywhere else */ +* { + font-family: Arial, Helvetica, sans-serif; +} diff --git a/aio/content/examples/forms/src/app/hero-form.component.html b/aio/content/examples/forms/src/app/hero-form.component.html index 2efb9bc7dd..73b703f789 100644 --- a/aio/content/examples/forms/src/app/hero-form.component.html +++ b/aio/content/examples/forms/src/app/hero-form.component.html @@ -150,7 +150,9 @@

Hero Form

-
+ + + {{diagnostic}}
diff --git a/aio/content/examples/pipes/e2e-spec.ts b/aio/content/examples/pipes/e2e-spec.ts index a2c4062dfd..00277e3657 100644 --- a/aio/content/examples/pipes/e2e-spec.ts +++ b/aio/content/examples/pipes/e2e-spec.ts @@ -1,4 +1,4 @@ -'use strict'; // necessary for es6 output in node +'use strict'; // necessary for es6 output in node import { browser, element, by } from 'protractor'; @@ -64,7 +64,7 @@ describe('Pipes', function () { }); - xit('should support flying heroes (pure) ', function () { + it('should support flying heroes (pure) ', function () { let nameEle = element(by.css('flying-heroes input[type="text"]')); let canFlyCheckEle = element(by.css('flying-heroes #can-fly')); let mutateCheckEle = element(by.css('flying-heroes #mutate')); @@ -90,7 +90,7 @@ describe('Pipes', function () { }); - xit('should support flying heroes (impure) ', function () { + it('should support flying heroes (impure) ', function () { let nameEle = element(by.css('flying-heroes-impure input[type="text"]')); let canFlyCheckEle = element(by.css('flying-heroes-impure #can-fly')); let mutateCheckEle = element(by.css('flying-heroes-impure #mutate')); diff --git a/aio/content/examples/structural-directives/src/app/app.component.html b/aio/content/examples/structural-directives/src/app/app.component.html index 309d2bb5f7..49c4928aad 100644 --- a/aio/content/examples/structural-directives/src/app/app.component.html +++ b/aio/content/examples/structural-directives/src/app/app.component.html @@ -48,11 +48,11 @@

NgIf with template

-

<template> element

+

<ng-template> element

- +

template attribute

@@ -140,9 +140,9 @@

<template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById">

- +
@@ -179,21 +179,21 @@
-

NgSwitch with <template>

+

NgSwitch with <ng-template>

- - - - +
@@ -202,9 +202,9 @@

<template>

Hip!

- +

Hooray!

@@ -242,9 +242,9 @@ (A) <p template="myUnless condition" class="code unless">

- + diff --git a/aio/content/examples/template-syntax/src/app/app.component.html b/aio/content/examples/template-syntax/src/app/app.component.html index e58460bf89..760fa3a367 100644 --- a/aio/content/examples/template-syntax/src/app/app.component.html +++ b/aio/content/examples/template-syntax/src/app/app.component.html @@ -544,13 +544,13 @@ bindon-ngModel - +Add {{currentHero.name}} with template
Hero Detail removed from DOM (via template) because isActive is false
- + diff --git a/aio/content/examples/testing/src/app/app.component.router.spec.ts b/aio/content/examples/testing/src/app/app.component.router.spec.ts index de22db8ceb..226d6d1ff3 100644 --- a/aio/content/examples/testing/src/app/app.component.router.spec.ts +++ b/aio/content/examples/testing/src/app/app.component.router.spec.ts @@ -141,7 +141,7 @@ function createComponent() { comp = fixture.componentInstance; const injector = fixture.debugElement.injector; - location = injector.get(Location); + location = injector.get(Location) as SpyLocation; router = injector.get(Router); router.initialNavigation(); spyOn(injector.get(TwainService), 'getQuote') diff --git a/aio/content/examples/testing/src/app/bag/async-helper.spec.ts b/aio/content/examples/testing/src/app/bag/async-helper.spec.ts index 5106361a58..12c8a4fbbd 100644 --- a/aio/content/examples/testing/src/app/bag/async-helper.spec.ts +++ b/aio/content/examples/testing/src/app/bag/async-helper.spec.ts @@ -34,7 +34,7 @@ describe('Angular async helper', () => { // Use done. Cannot use setInterval with async or fakeAsync // See https://github.com/angular/angular/issues/10127 - it('should run async test with successful delayed Observable', done => { + it('should run async test with successful delayed Observable', (done: any) => { const source = Observable.of(true).delay(10); source.subscribe( val => actuallyDone = true, diff --git a/aio/content/examples/testing/src/app/bag/bag.no-testbed.spec.ts b/aio/content/examples/testing/src/app/bag/bag.no-testbed.spec.ts index 6bdbe86cd0..f29672ecf6 100644 --- a/aio/content/examples/testing/src/app/bag/bag.no-testbed.spec.ts +++ b/aio/content/examples/testing/src/app/bag/bag.no-testbed.spec.ts @@ -18,7 +18,7 @@ describe('FancyService without the TestBed', () => { expect(service.getValue()).toBe('real value'); }); - it('#getAsyncValue should return async value', done => { + it('#getAsyncValue should return async value', (done: DoneFn) => { service.getAsyncValue().then(value => { expect(value).toBe('async value'); done(); @@ -26,7 +26,7 @@ describe('FancyService without the TestBed', () => { }); // #docregion getTimeoutValue - it('#getTimeoutValue should return timeout value', done => { + it('#getTimeoutValue should return timeout value', (done: DoneFn) => { service = new FancyService(); service.getTimeoutValue().then(value => { expect(value).toBe('timeout value'); @@ -35,7 +35,7 @@ describe('FancyService without the TestBed', () => { }); // #enddocregion getTimeoutValue - it('#getObservableValue should return observable value', done => { + it('#getObservableValue should return observable value', (done: DoneFn) => { service.getObservableValue().subscribe(value => { expect(value).toBe('observable value'); done(); diff --git a/aio/content/examples/testing/src/app/bag/bag.spec.ts b/aio/content/examples/testing/src/app/bag/bag.spec.ts index 3890d8844d..d6fea7ca94 100644 --- a/aio/content/examples/testing/src/app/bag/bag.spec.ts +++ b/aio/content/examples/testing/src/app/bag/bag.spec.ts @@ -73,7 +73,7 @@ describe('use inject helper in beforeEach', () => { })); // Must use done. See https://github.com/angular/angular/issues/10127 - it('test should wait for FancyService.getObservableDelayValue', done => { + it('test should wait for FancyService.getObservableDelayValue', (done: DoneFn) => { service.getObservableDelayValue().subscribe(value => { expect(value).toBe('observable delay value'); done(); @@ -187,20 +187,21 @@ describe('TestBed Component Tests', () => { expect(selected).toHaveText(hero.name); }); - it('can access the instance variable of an `*ngFor` row', () => { + it('can access the instance variable of an `*ngFor` row component', () => { const fixture = TestBed.createComponent(IoParentComponent); const comp = fixture.componentInstance; + const heroName = comp.heroes[0].name; // first hero's name fixture.detectChanges(); - const heroEl = fixture.debugElement.query(By.css('.hero')); // first hero + const ngForRow = fixture.debugElement.query(By.directive(IoComponent)); // first hero ngForRow - const ngForRow = heroEl.parent; // Angular's NgForRow wrapper element + const hero = ngForRow.context['hero']; // the hero object passed into the row + expect(hero.name).toBe(heroName, 'ngRow.context.hero'); - // jasmine.any is instance-of-type test. - expect(ngForRow.componentInstance).toEqual(jasmine.any(IoComponent), 'component is IoComp'); - - const hero = ngForRow.context['$implicit']; // the hero object - expect(hero.name).toBe(comp.heroes[0].name, '1st hero\'s name'); + const rowComp = ngForRow.componentInstance; + // jasmine.any is an "instance-of-type" test. + expect(rowComp).toEqual(jasmine.any(IoComponent), 'component is IoComp'); + expect(rowComp.hero.name).toBe(heroName, 'component.hero'); }); @@ -343,7 +344,7 @@ describe('TestBed Component Tests', () => { const childComp = el.componentInstance as BankAccountComponent; expect(childComp).toEqual(jasmine.any(BankAccountComponent)); - expect(el.context).toBe(comp, 'context is the parent component'); + expect(el.context).toBe(childComp, 'context is the child component'); expect(el.attributes['account']).toBe(childComp.id, 'account attribute'); expect(el.attributes['bank']).toBe(childComp.bank, 'bank attribute'); @@ -447,7 +448,7 @@ describe('TestBed Component Overrides:', () => { // `inject` uses TestBed's injector inject([FancyService], (s: FancyService) => testBedProvider = s)(); tcProvider = fixture.debugElement.injector.get(FancyService); - tpcProvider = fixture.debugElement.children[0].injector.get(FancyService); + tpcProvider = fixture.debugElement.children[0].injector.get(FancyService) as FakeFancyService; expect(testBedProvider).not.toBe(tcProvider, 'testBed/tc not same providers'); expect(testBedProvider).not.toBe(tpcProvider, 'testBed/tpc not same providers'); diff --git a/aio/content/examples/testing/src/app/hero/hero-detail.component.no-testbed.spec.ts b/aio/content/examples/testing/src/app/hero/hero-detail.component.no-testbed.spec.ts index a6c1af98d7..422dae6f77 100644 --- a/aio/content/examples/testing/src/app/hero/hero-detail.component.no-testbed.spec.ts +++ b/aio/content/examples/testing/src/app/hero/hero-detail.component.no-testbed.spec.ts @@ -12,7 +12,7 @@ describe('HeroDetailComponent - no TestBed', () => { let hds: any; let router: any; - beforeEach( done => { + beforeEach((done: any) => { expectedHero = new Hero(42, 'Bubba'); activatedRoute = new ActivatedRouteStub(); activatedRoute.testParams = { id: expectedHero.id }; @@ -45,7 +45,7 @@ describe('HeroDetailComponent - no TestBed', () => { expect(router.navigate.calls.any()).toBe(false, 'router.navigate not called yet'); }); - it('should navigate when click save resolves', done => { + it('should navigate when click save resolves', (done: any) => { comp.save(); // waits for async save to complete before navigating hds.saveHero.calls.first().returnValue diff --git a/aio/content/examples/testing/src/app/hero/hero-detail.component.spec.ts b/aio/content/examples/testing/src/app/hero/hero-detail.component.spec.ts index 4e1ee034d7..80b6450ac5 100644 --- a/aio/content/examples/testing/src/app/hero/hero-detail.component.spec.ts +++ b/aio/content/examples/testing/src/app/hero/hero-detail.component.spec.ts @@ -90,7 +90,7 @@ function overrideSetup() { beforeEach( async(() => { createComponent(); // get the component's injected HeroDetailServiceSpy - hdsSpy = fixture.debugElement.injector.get(HeroDetailService); + hdsSpy = fixture.debugElement.injector.get(HeroDetailService) as any; })); it('should have called `getHero`', () => { diff --git a/aio/content/examples/testing/src/app/shared/twain.component.spec.ts b/aio/content/examples/testing/src/app/shared/twain.component.spec.ts index b80993cc0b..b177c0bfc3 100644 --- a/aio/content/examples/testing/src/app/shared/twain.component.spec.ts +++ b/aio/content/examples/testing/src/app/shared/twain.component.spec.ts @@ -78,7 +78,7 @@ describe('TwainComponent', () => { // #enddocregion tests // #docregion done-test - it('should show quote after getQuote promise (done)', done => { + it('should show quote after getQuote promise (done)', (done: any) => { fixture.detectChanges(); // get the spy promise and wait for it to resolve diff --git a/aio/content/examples/user-input/e2e-spec.ts b/aio/content/examples/user-input/e2e-spec.ts index c0bb770848..3f178382c7 100644 --- a/aio/content/examples/user-input/e2e-spec.ts +++ b/aio/content/examples/user-input/e2e-spec.ts @@ -1,4 +1,4 @@ -'use strict'; // necessary for es6 output in node +'use strict'; // necessary for es6 output in node import { browser, element, by, protractor } from 'protractor'; @@ -53,7 +53,7 @@ describe('User Input Tests', function () { expect(outputTextEle.getText()).toEqual('a | ab | abc |'); }); - xit('should be able to filter key events', () => { + it('should be able to filter key events', () => { let mainEle = element(by.css('key-up3')); let inputEle = mainEle.element(by.css('input')); let outputTextEle = mainEle.element(by.css('p')); diff --git a/aio/content/examples/webpack/config/webpack.common.js b/aio/content/examples/webpack/config/webpack.common.js index be01ad5603..28be240e04 100644 --- a/aio/content/examples/webpack/config/webpack.common.js +++ b/aio/content/examples/webpack/config/webpack.common.js @@ -62,7 +62,7 @@ module.exports = { // Workaround for angular/angular#11580 new webpack.ContextReplacementPlugin( // The (\\|\/) piece accounts for path separators in *nix and Windows - /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/, + /angular(\\|\/)core(\\|\/)@angular/, helpers.root('./src'), // location of your src {} // a map of your routes ), diff --git a/aio/content/examples/webpack/config/webpack.dev.js b/aio/content/examples/webpack/config/webpack.dev.js index c1484a0caa..57d29560a0 100644 --- a/aio/content/examples/webpack/config/webpack.dev.js +++ b/aio/content/examples/webpack/config/webpack.dev.js @@ -6,21 +6,21 @@ var helpers = require('./helpers'); module.exports = webpackMerge(commonConfig, { devtool: 'cheap-module-eval-source-map', - + output: { path: helpers.root('dist'), - publicPath: 'http://localhost:8080/', + publicPath: '/', filename: '[name].js', chunkFilename: '[id].chunk.js' }, - + plugins: [ new ExtractTextPlugin('[name].css') ], - + devServer: { historyApiFallback: true, stats: 'minimal' } }); -// #enddocregion \ No newline at end of file +// #enddocregion diff --git a/aio/content/guide/dependency-injection.md b/aio/content/guide/dependency-injection.md index 1a9e59d95b..3fb0efafb8 100644 --- a/aio/content/guide/dependency-injection.md +++ b/aio/content/guide/dependency-injection.md @@ -1079,7 +1079,7 @@ This is especially convenient when you consider that most dependency values are

What if the dependency value isn't a class? Sometimes the thing you want to inject is a - span string, function, or object. + string, function, or object.

diff --git a/aio/content/guide/deployment.md b/aio/content/guide/deployment.md index 18914f7061..ba52f85129 100644 --- a/aio/content/guide/deployment.md +++ b/aio/content/guide/deployment.md @@ -408,7 +408,7 @@ console: - Angular 2 is running in the development mode. Call enableProdMode() to enable the production mode. + Angular is running in the development mode. Call enableProdMode() to enable the production mode. diff --git a/aio/content/guide/dynamic-form.md b/aio/content/guide/dynamic-form.md index 8da4890895..3f5e7bc0a2 100644 --- a/aio/content/guide/dynamic-form.md +++ b/aio/content/guide/dynamic-form.md @@ -7,48 +7,48 @@ Render dynamic forms with FormGroup. @description -We can't always justify the cost and time to build handcrafted forms, -especially if we'll need a great number of them, they're similar to each other, and they change frequently +Building handcrafted forms can be costly and time-consuming, +especially if you need a great number of them, they're similar to each other, and they change frequently to meet rapidly changing business and regulatory requirements. -It may be more economical to create the forms dynamically, based on metadata that describe the business object model. +It may be more economical to create the forms dynamically, based on +metadata that describes the business object model. -In this cookbook we show how to use `formGroup` to dynamically render a simple form with different control types and validation. -It's a primitive start. +This cookbook shows you how to use `formGroup` to dynamically +render a simple form with different control types and validation. +It's a primitive start. It might evolve to support a much richer variety of questions, more graceful rendering, and superior user experience. All such greatness has humble beginnings. -In our example we use a dynamic form to build an online application experience for heroes seeking employment. +The example in this cookbook is a dynamic form to build an +online application experience for heroes seeking employment. The agency is constantly tinkering with the application process. -We can create the forms on the fly *without changing our application code*. +You can create the forms on the fly *without changing the application code*. {@a toc} -## Table of contents - - [Bootstrap](guide/dynamic-form#bootstrap) - - [Question Model](guide/dynamic-form#object-model) - - [Form Component](guide/dynamic-form#form-component) - - [Questionnaire Metadata](guide/dynamic-form#questionnaire-metadata) - - [Dynamic Template](guide/dynamic-form#dynamic-template) +# Contents + * [Bootstrap](guide/dynamic-form#bootstrap) + * [Question model](guide/dynamic-form#object-model) + * [Question form components](guide/dynamic-form#form-component) + * [Questionnaire data](guide/dynamic-form#questionnaire-data) + * [Dynamic template](guide/dynamic-form#dynamic-template) -**See the **. +See the . {@a bootstrap} ## Bootstrap -We start by creating an `NgModule` called `AppModule`. +Start by creating an `NgModule` called `AppModule`. -In our example we will be using Reactive Forms. +This cookbook uses [reactive forms](guide/reactive-forms). -Reactive Forms belongs to a different `NgModule` called `ReactiveFormsModule`, so in order to access any Reactive Forms directives, we have to import `ReactiveFormsModule` from the `@angular/forms` library. +Reactive forms belongs to a different `NgModule` called `ReactiveFormsModule`, +so in order to access any reactive forms directives, you have to import +`ReactiveFormsModule` from the `@angular/forms` library. -We bootstrap our `AppModule` in main.ts. +Bootstrap the `AppModule` in `main.ts`. @@ -66,13 +66,13 @@ We bootstrap our `AppModule` in main.ts. {@a object-model} -## Question Model +## Question model The next step is to define an object model that can describe all scenarios needed by the form functionality. -The hero application process involves a form with a lot of questions. -The "question" is the most fundamental object in the model. +The hero application process involves a form with a lot of questions. +The _question_ is the most fundamental object in the model. -We have created `QuestionBase` as the most fundamental question class. +The following `QuestionBase` is a fundamental question class. @@ -81,10 +81,13 @@ We have created `QuestionBase` as the most fundamental question class. -From this base we derived two new classes in `TextboxQuestion` and `DropdownQuestion` that represent Textbox and Dropdown questions. -The idea is that the form will be bound to specific question types and render the appropriate controls dynamically. +From this base you can derive two new classes in `TextboxQuestion` and `DropdownQuestion` +that represent textbox and dropdown questions. +The idea is that the form will be bound to specific question types and render the +appropriate controls dynamically. -`TextboxQuestion` supports multiple html5 types like text, email, url etc via the `type` property. +`TextboxQuestion` supports multiple HTML5 types such as text, email, and url +via the `type` property. @@ -102,8 +105,9 @@ The idea is that the form will be bound to specific question types and render th -Next we have defined `QuestionControlService`, a simple service for transforming our questions to a `FormGroup`. -In a nutshell, the form group consumes the metadata from the question model and allows us to specify default values and validation rules. +Next is `QuestionControlService`, a simple service for transforming the questions to a `FormGroup`. +In a nutshell, the form group consumes the metadata from the question model and +allows you to specify default values and validation rules. @@ -113,10 +117,11 @@ In a nutshell, the form group consumes the metadata from the question model and {@a form-component} ## Question form components -Now that we have defined the complete model we are ready to create components to represent the dynamic form. +Now that you have defined the complete model you are ready +to create components to represent the dynamic form. -`DynamicFormComponent` is the entry point and the main container for the form. +`DynamicFormComponent` is the entry point and the main container for the form. @@ -132,9 +137,10 @@ Now that we have defined the complete model we are ready to create components to -It presents a list of questions, each question bound to a `` component element. +It presents a list of questions, each bound to a `` component element. The `` tag matches the `DynamicFormQuestionComponent`, -the component responsible for rendering the details of each _individual_ question based on values in the data-bound question object. +the component responsible for rendering the details of each _individual_ +question based on values in the data-bound question object. @@ -151,26 +157,30 @@ the component responsible for rendering the details of each _individual_ questio -Notice this component can present any type of question in our model. -We only have two types of questions at this point but we can imagine many more. +Notice this component can present any type of question in your model. +You only have two types of questions at this point but you can imagine many more. The `ngSwitch` determines which type of question to display. -In both components we're relying on Angular's **formGroup** to connect the template HTML to the +In both components you're relying on Angular's **formGroup** to connect the template HTML to the underlying control objects, populated from the question model with display and validation rules. -`formControlName` and `formGroup` are directives defined in `ReactiveFormsModule`. Our templates can access these directives directly since we imported `ReactiveFormsModule` from `AppModule`. -{@a questionnaire-metadata} +`formControlName` and `formGroup` are directives defined in +`ReactiveFormsModule`. The templates can access these directives +directly since you imported `ReactiveFormsModule` from `AppModule`. +{@a questionnaire-data} ## Questionnaire data -`DynamicFormComponent` expects the list of questions in the form of an array bound to `@Input() questions`. +`DynamicFormComponent` expects the list of questions in the form of an array bound to `@Input() questions`. + + The set of questions you've defined for the job application is returned from the `QuestionService`. + In a real app you'd retrieve these questions from storage. + + The key point is that you control the hero job application questions + entirely through the objects returned from `QuestionService`. + Questionnaire maintenance is a simple matter of adding, updating, + and removing objects from the `questions` array. - The set of questions we have defined for the job application is returned from the `QuestionService`. - In a real app we'd retrieve these questions from storage. - - The key point is that we control the hero job application questions entirely through the objects returned from `QuestionService`. - Questionnaire maintenance is a simple matter of adding, updating, and removing objects from the `questions` array. - @@ -178,7 +188,7 @@ underlying control objects, populated from the question model with display and v -Finally, we display an instance of the form in the `AppComponent` shell. +Finally, display an instance of the form in the `AppComponent` shell. @@ -188,17 +198,18 @@ Finally, we display an instance of the form in the `AppComponent` shell. {@a dynamic-template} ## Dynamic Template -Although in this example we're modelling a job application for heroes, there are no references to any specific hero question -outside the objects returned by `QuestionService`. +Although in this example you're modelling a job application for heroes, there are +no references to any specific hero question +outside the objects returned by `QuestionService`. -This is very important since it allows us to repurpose the components for any type of survey -as long as it's compatible with our *question* object model. -The key is the dynamic data binding of metadata used to render the form -without making any hardcoded assumptions about specific questions. -In addition to control metadata, we are also adding validation dynamically. +This is very important since it allows you to repurpose the components for any type of survey +as long as it's compatible with the *question* object model. +The key is the dynamic data binding of metadata used to render the form +without making any hardcoded assumptions about specific questions. +In addition to control metadata, you are also adding validation dynamically. -The *Save* button is disabled until the form is in a valid state. -When the form is valid, we can click *Save* and the app renders the current form values as JSON. +The *Save* button is disabled until the form is in a valid state. +When the form is valid, you can click *Save* and the app renders the current form values as JSON. This proves that any user input is bound back to the data model. Saving and retrieving the data is an exercise for another time. diff --git a/aio/content/guide/forms.md b/aio/content/guide/forms.md index 12195b6ec1..ab2a702ac4 100644 --- a/aio/content/guide/forms.md +++ b/aio/content/guide/forms.md @@ -296,6 +296,19 @@ You added a *Submit* button at the bottom with some classes on it for styling. *You're not using Angular yet*. There are no bindings or extra directives, just layout. + +
+ + + +In template driven forms, if you've imported `FormsModule`, you don't have to do anything +to the `` tag in order to make use of `FormsModule`. Continue on to see how this works. + + +
+ + + The `container`, `form-group`, `form-control`, and `btn` classes come from [Twitter Bootstrap](http://getbootstrap.com/css/). These classes are purely cosmetic. Bootstrap gives the form a little style. @@ -400,6 +413,42 @@ You left yourself a note to throw it away when you're done. Focus on the binding syntax: `[(ngModel)]="..."`. +You need one more addition to display the data. Declare +a template variable for the form. Update the `` tag with +`#heroForm="ngForm"` as follows: + + + + + + + + +The variable `heroForm` is now a reference to the `NgForm` directive that governs the form as a whole. + + +
+ + + +### The _NgForm_ directive + +What `NgForm` directive? +You didn't add an [NgForm](api/forms/index/NgForm-directive) directive. + +Angular did. Angular automatically creates and attaches an `NgForm` directive to the `` tag. + +The `NgForm` directive supplements the `form` element with additional features. +It holds the controls you created for the elements with an `ngModel` directive +and `name` attribute, and monitors their properties, including their validity. +It also has its own `valid` property which is true only *if every contained +control* is valid. + + +
+ + + If you ran the app now and started typing in the *Name* input box, adding and deleting characters, you'd see them appear and disappear from the interpolated text. @@ -442,7 +491,7 @@ Defining a `name` attribute is a requirement when using `[(ngModel)]` in combina Internally, Angular creates `FormControl` instances and registers them with an `NgForm` directive that Angular attached to the `` tag. Each `FormControl` is registered under the name you assigned to the `name` attribute. -Read more in [The NgForm directive](guide/forms#ngForm), later in this page. +Read more in the previous section, [The NgForm directive](guide/forms#ngForm). @@ -784,32 +833,9 @@ to the hero form component's `onSubmit()` method: -You added something extra at the end. You defined a -template reference variable, `#heroForm`, and initialized it with the value "ngForm". - -The variable `heroForm` is now a reference to the `NgForm` directive that governs the form as a whole. - - -
- - - -### The _NgForm_ directive - -What `NgForm` directive? -You didn't add an [NgForm](api/forms/index/NgForm-directive) directive. - -Angular did. Angular automatically creates and attaches an `NgForm` directive to the `` tag. - -The `NgForm` directive supplements the `form` element with additional features. -It holds the controls you created for the elements with an `ngModel` directive -and `name` attribute, and monitors their properties, including their validity. -It also has its own `valid` property which is true only *if every contained -control* is valid. - - -
- +You'd already defined a template reference variable, +`#heroForm`, and initialized it with the value "ngForm". +Now, use that variable to access the form with the Submit button. You'll bind the form's overall validity via diff --git a/aio/content/guide/i18n.md b/aio/content/guide/i18n.md index ace7ea4233..fdca5b7fc8 100644 --- a/aio/content/guide/i18n.md +++ b/aio/content/guide/i18n.md @@ -12,24 +12,36 @@ Translate the app's template text into multiple languages. Angular's _internationalization_ (_i18n_) tools help make your app available in multiple languages. -## Table of contents +# Contents * [Angular and i18n template translation](guide/i18n#angular-i18n) * [Mark text with the _i18n_ attribute](guide/i18n#i18n-attribute) + * [Help the translator with a description and intent](guide/i18n#help-translator) + * [Translate text without creating an element](guide/i18n#no-element) * [Add _i18n-..._ translation attributes](guide/i18n#translate-attributes) * [Handle singular and plural](guide/i18n#cardinality) * [Select among alternative texts](guide/i18n#select) * [Create a translation source file with the **_ng-xi18n_ extraction tool**](guide/i18n#ng-xi18n) + * [Other translation formats](guide/i18n#other-formats) + * [Other options](guide/i18n#ng-xi18n-options) + * [Add an `npm` script for convenience](guide/i18n#npm-i18n-script) * [Translate text messages](guide/i18n#translate) + * [Create a localization folder](guide/i18n#localization-folder) + * [Translate text nodes](guide/i18n#translate-text-nodes) + * [Translate `plural` and `select`](guide/i18n#translate-plural-select) + * [Translate `plural`](guide/i18n#translate-plural) + * [Translate `select`](guide/i18n#translate-select) + * [The app before translation](guide/i18n#app-pre-translation) * [Merge the completed translation file into the app](guide/i18n#merge) - * [Merge with the JIT compiler](guide/i18n#jit) + * [SystemJS text plugin](guide/i18n#text-plugin) + * [Create translation providers](guide/i18n#create-translation-providers) + * [Bootstrap the app with translation providers](guide/i18n#bootstrap-the-app) * [Internationalization with the AOT compiler](guide/i18n#aot) - * [Translation file maintenance and _id_ changes](guide/i18n#maintenance) -**Try this** live example +Try this live example of a JIT-compiled app, translated into Spanish. @@ -40,7 +52,7 @@ of a JIT-compiled app, translated into Spanish. ## Angular and _i18n_ template translation -Application internationalization is a challenging, many-faceted effort that +Application internationalization is a challenging, many-faceted effort that takes dedication and enduring commitment. Angular's _i18n_ internationalization facilities can help. @@ -67,10 +79,10 @@ The _i18n_ template translation process has four phases: 1. An angular _i18n_ tool extracts the marked messages into an industry standard translation source file. -1. A translator edits that file, translating the extracted text messages into the target language, +1. A translator edits that file, translating the extracted text messages into the target language, and returns the file to you. -1. The Angular compiler imports the completed translation files, +1. The Angular compiler imports the completed translation files, replaces the original messages with translated text, and generates a new version of the application in the target language. @@ -91,7 +103,7 @@ Place it on every element tag whose fixed text should be translated. -`i18n` is not an Angular _directive_. +`i18n` is not an Angular _directive_. It's a custom _attribute_, recognized by Angular tools and compilers. After translation, the compiler removes it. @@ -100,7 +112,7 @@ After translation, the compiler removes it. -In the accompanying sample, an `

` tag displays a simple English language greeting +In the accompanying sample, an `

` tag displays a simple English language greeting that you translate into Spanish: @@ -118,9 +130,12 @@ Add the `i18n` attribute to the tag to mark it for translation. +{@a help-translator} + + ### Help the translator with a _description_ and _intent_ -In order to translate it accurately, the translator may +In order to translate it accurately, the translator may need a description of the message. Assign a description to the i18n attribute: @@ -131,8 +146,8 @@ Assign a description to the i18n attribute: -In order to deliver a correct translation, the translator may need to -know your _intent_—the true _meaning_ of the text +In order to deliver a correct translation, the translator may need to +know your _intent_—the true _meaning_ of the text within _this particular_ application context. In front of the description, add some contextual meaning to the assigned string, separating it from the description with the `|` character (`|`): @@ -144,11 +159,15 @@ separating it from the description with the `|` character (`|ICU Message Format -that derives from the -Common Locale Data Repository (CLDR), +that derives from the +Common Locale Data Repository (CLDR), which specifies the pluralization rules. @@ -274,12 +293,12 @@ which specifies the The application displays different text depending upon whether the hero is male or female. These text alternatives require translation too. -You can handle this with a `select` translation. +You can handle this with a `select` translation. A `select` also follows the -ICU message syntax. +ICU message syntax. You choose among alternative translation based on a string value instead of a number. -The following format message in the component template binds to the component's `gender` +The following format message in the component template binds to the component's `gender` property, which outputs either an "m" or an "f". The message maps those values to the appropriate translation: @@ -296,7 +315,7 @@ The message maps those values to the appropriate translation: ## Create a translation source file with the _ng-xi18n_ tool -Use the **_ng-xi18n_ extraction tool** to extract the `i18n`-marked texts +Use the **_ng-xi18n_ extraction tool** to extract the `i18n`-marked texts into a translation source file in an industry standard format. This is an Angular CLI tool in the `@angular/compiler-cli` npm package. @@ -340,7 +359,7 @@ By default, the tool generates a translation file named **`messages.xlf`** in th ### Other translation formats -You can generate a file named **`messages.xmb`** in the +You can generate a file named **`messages.xmb`** in the XML Message Bundle (XMB) format by adding the `--i18nFormat=xmb` flag. @@ -359,8 +378,8 @@ This sample sticks with the _XLIFF_ format. ### Other options -You may have to specify additional options. -For example, if the `tsconfig.json` TypeScript configuration +You may have to specify additional options. +For example, if the `tsconfig.json` TypeScript configuration file is located somewhere other than in the root folder, you must identify the path to it with the `-p` option: @@ -383,7 +402,7 @@ to make the command easier to remember and run: "scripts": { - "i18n": "ng-xi18n", + "i18n": "ng-xi18n", ... } @@ -400,7 +419,7 @@ Now you can issue command variations such as these: -Note the `--` flag before the options. +Note the `--` flag before the options. It tells _npm_ to pass every flag thereafter to `ng-xi18n`. @@ -410,9 +429,9 @@ It tells _npm_ to pass every flag thereafter to `ng-xi18n`. ## Translate text messages -The `ng-xi18n` command generates a translation source file +The `ng-xi18n` command generates a translation source file in the project root folder named `messages.xlf`. -The next step is to translate the English language template +The next step is to translate the English language template text into the specific language translation files. The cookbook sample creates a Spanish translation file. @@ -425,14 +444,14 @@ files. The cookbook sample creates a Spanish translation file. You will probably translate into more than one other language so it's a good idea for the project structure to reflect your entire internationalization effort. -One approach is to dedicate a folder to localization and store related assets -(for example, internationalization files) there. +One approach is to dedicate a folder to localization and store related assets, +such as internationalization files, there.
-Localization and internationalization are +Localization and internationalization are different but closely related terms.
@@ -443,10 +462,13 @@ This cookbook follows that suggestion. It has a `locale` folder under the `src/` Assets within the folder carry a filename extension that matches a language-culture code from a well-known codeset. -Make a copy of the `messages.xlf` file, put it in the `locale` folder and +Make a copy of the `messages.xlf` file, put it in the `locale` folder and rename it `messages.es.xlf`for the Spanish language translation. Do the same for each target language. +{@a translate-text-nodes} + + ### Translate text nodes In the real world, you send the `messages.es.xlf` file to a Spanish translator who fills in the translations using one of the @@ -462,7 +484,7 @@ Open `messages.es.xlf` and find the first `` section: -This XML element represents the translation of the `

` greeting tag you marked with the `i18n` attribute. +This XML element represents the translation of the `

` greeting tag you marked with the `i18n` attribute. Using the _source_, _description_, and _meaning_ elements to guide your translation, replace the `` tag with the Spanish greeting: @@ -502,16 +524,19 @@ Translate the other text nodes the same way: ## Translate _plural_ and _select_ Translating _plural_ and _select_ messages is a little tricky. -The `` tag is empty for `plural` and `select` translation +The `` tag is empty for `plural` and `select` translation units, which makes them hard to correlate with the original template. -The `XLIFF` format doesn't yet support the ICU rules; it soon will. +The `XLIFF` format doesn't yet support the ICU rules. However, the `XMB` format does support the ICU rules. You'll just have to look for them in relation to other translation units that you recognize from elsewhere in the source template. In this example, you know the translation unit for the `select` must be just below the translation unit for the logo. -### Translate _plural_ +{@a translate-plural} + + +### Translate _plural_ To translate a `plural`, translate its ICU format match values: @@ -521,7 +546,10 @@ To translate a `plural`, translate its ICU format match values: -### Translate _select_ +{@a translate-select} + + +### Translate _select_ The `select` behaves a little differently. Here again is the ICU format message in the component template: @@ -534,7 +562,7 @@ The `select` behaves a little differently. Here again is the ICU format message The extraction tool broke that into _two_ translation units. The first unit contains the text that was _outside_ the `select`. -In place of the `select` is a placeholder, ``, that represents the `select` message. +In place of the `select` is a placeholder, ``, that represents the `select` message. Translate the text and leave the placeholder where it is. @@ -568,7 +596,7 @@ Here they are together, after translation: -The entire template translation is complete. It's +The entire template translation is complete. It's time to incorporate that translation into the application. @@ -617,21 +645,21 @@ When the previous steps finish, the sample app _and_ its translation file are as To merge the translated text into component templates, compile the application with the completed translation file. -The process is the same whether the file is in `.xlf` format or -in another format (`.xlif` and `.xtb`) that Angular understands. +The process is the same whether the file is in `.xlf` format or +in another format that Angular understands, such as `.xlif` or `.xtb`. You provide the Angular compiler with three new pieces of information: - * the translation file - * the translation file format - * the _Locale ID_ - (`es` or `en-US` for instance) + * The translation file. + * The translation file format. + * The _Locale ID_ + (`es` or `en-US` for instance). _How_ you provide this information depends upon whether you compile with -the JIT (_Just-in-Time_) compiler or the AOT (_Ahead-of-Time_) compiler. +the JIT (_Just-in-Time_) compiler or the AOT (_Ahead-of-Time_) compiler. * With [JIT](guide/i18n#jit), you provide the information at bootstrap time. - * With [AOT](guide/i18n#aot), you pass the information as `ngc` options. + * With [AOT](guide/i18n#aot), you pass the information as `ngc` options. {@a jit} @@ -663,7 +691,7 @@ in the `index.html`. {@a text-plugin} -### SystemJS Text plugin +### SystemJS text plugin Notice the SystemJS mapping of `text` to a `systemjs-text-plugin.js`. With the help of a text plugin, SystemJS can read any file as raw text and @@ -679,16 +707,19 @@ Create the following `systemjs-text-plugin.js` in the `src/` folder: +{@a create-translation-providers} + + ### Create translation providers Three providers tell the JIT compiler how to translate the template texts for a particular language while compiling the application: * `TRANSLATIONS` is a string containing the content of the translation file. -* `TRANSLATIONS_FORMAT` is the format of the file: `xlf`, `xlif` or `xtb`. +* `TRANSLATIONS_FORMAT` is the format of the file: `xlf`, `xlif`, or `xtb`. * `LOCALE_ID` is the locale of the target language. -The `getTranslationProviders` function in the following `src/app/i18n-providers.ts` +The `getTranslationProviders()` function in the following `src/app/i18n-providers.ts` creates those providers based on the user's _locale_ and the corresponding translation file: @@ -704,22 +735,25 @@ and the corresponding translation file: The function returns an empty `noProviders` array as a `Promise`. It must return a `Promise` because this function could read a translation file asynchronously from the server. -1. It creates a transaction filename from the locale according to the name and location convention +1. It creates a transaction filename from the locale according to the name and location convention [described earlier](guide/i18n#localization-folder). -1. The `getTranslationsWithSystemJs` method reads the translation and returns the contents as a string. -Notice that it appends `!text` to the filename, telling SystemJS to use the [text plugin](guide/i18n#text-plugin). +1. The `getTranslationsWithSystemJs()` method reads the translation and returns the contents as a string. +Notice that it appends `!text` to the filename, telling SystemJS to use the [text plugin](guide/i18n#text-plugin). 1. The callback composes a providers array with the three translation providers. -1. Finally, `getTranslationProviders` returns the entire effort as a promise. +1. Finally, `getTranslationProviders()` returns the entire effort as a promise. + +{@a bootstrap-the-app} + ### Bootstrap the app with translation providers -The Angular `bootstrapModule` method has a second, _options_ parameter +The Angular `bootstrapModule()` method has a second _options_ parameter that can influence the behavior of the compiler. -You'll create an _options_ object with the translation providers from `getTranslationProviders` +You'll create an _options_ object with the translation providers from `getTranslationProviders()` and pass it to `bootstrapModule`. Open the `src/main.ts` and modify the bootstrap code as follows: @@ -729,7 +763,7 @@ Open the `src/main.ts` and modify the bootstrap code as follows: -Notice that it waits for the `getTranslationProviders` promise to resolve before +Notice that it waits for the `getTranslationProviders()` promise to resolve before bootstrapping the app. The app is now _internationalized_ for English and Spanish and there is a clear path for adding @@ -740,40 +774,40 @@ more languages. -### _Internationalize_ with the AOT compiler +### _Internationalization_ with the AOT compiler -The JIT compiler translates the application into the target language +The JIT compiler translates the application into the target language while compiling dynamically in the browser. -That's flexible but may not be fast enough for your users. +That's flexible but may not be fast enough for your users. -The AOT (_Ahead-of-Time_) compiler is part of a build process that +The AOT (_Ahead-of-Time_) compiler is part of a build process that produces a small, fast, ready-to-run application package. -When you internationalize with the AOT compiler, you pre-build +When you internationalize with the AOT compiler, you pre-build a separate application package for each -language. Then in the host web page (`index.html`), +language. Then in the host web page, in this case `index.html`, you determine which language the user needs and serve the appropriate application package. -This cookbook doesn't cover how to build multiple application packages and +This cookbook doesn't cover how to build multiple application packages and serve them according to the user's language preference. It does explain the few steps necessary to tell the AOT compiler to apply a translations file. -Internationalization with the AOT compiler requires -some setup specifically for AOT compilation. -Start with the application project as shown +Internationalization with the AOT compiler requires +some setup specifically for AOT compilation. +Start with the application project as shown [just before merging the translation file](guide/i18n#app-pre-translation) and refer to the [AOT cookbook](guide/aot-compiler) to make it _AOT-ready_. -Next, issue an `ngc` compile command for each supported language (including English). +Next, issue an `ngc` compile command for each supported language, including English. The result is a separate version of the application for each language. Tell AOT how to translate by adding three options to the `ngc` command: - * `--i18nFile`: the path to the translation file - * `--locale`: the name of the locale - * `--i18nFormat`: the format of the localization file + * `--i18nFile`: the path to the translation file. + * `--locale`: the name of the locale. + * `--i18nFormat`: the format of the localization file. -For this sample, the Spanish language command would be +For this sample, the Spanish language command would be: ./node_modules/.bin/ngc --i18nFile=./locale/messages.es.xlf --locale=es --i18nFormat=xlf @@ -803,19 +837,19 @@ Windows users may have to quote the command: ## Translation file maintenance and _id_ changes - -As the application evolves, you will change the _i18n_ markup + +As the application evolves, you will change the _i18n_ markup and re-run the `ng-xi18n` extraction tool many times. The _new_ markup that you add is not a problem; -but _most_ changes to _existing_ markup trigger -generation of _new_ `id`s for the affected translation units. +but _most_ changes to existing markup trigger +generation of new `id`s for the affected translation units. -After an `id` changes, the translation files are no longer in-sync. -**All translated versions of the application will fail** during re-compilation. -The error messages identify the old `id`s that are no longer valid but +After an `id` changes, the translation files are no longer in sync. +**All translated versions of the application will fail** during re-compilation. +The error messages identify the old `id`s that are no longer valid but they don't tell you what the new `id`s should be. -**Commit all translation message files to source control**, +**Commit all translation message files to source control**, especially the English source `messages.xlf`. The difference between the old and the new `messages.xlf` file help you find and update `id` changes across your translation files. \ No newline at end of file diff --git a/aio/content/guide/reactive-forms.md b/aio/content/guide/reactive-forms.md index 065edf18de..3da2ba3e1e 100644 --- a/aio/content/guide/reactive-forms.md +++ b/aio/content/guide/reactive-forms.md @@ -156,7 +156,7 @@ Then you'll learn about the [Angular form classes](guide/reactive-forms#essentia ## Setup -Follow the steps in the [_Setup_ guide](setup "Setup guide") +Follow the steps in the [_Setup_ guide](guide/setup "Setup guide") for creating a new project folder (perhaps called `reactive-forms`) based on the _QuickStart seed_. @@ -989,7 +989,7 @@ by binding to its `hero` input property. In this approach, the value of `hero` in the `HeroDetailComponent` changes every time the user selects a new hero. -You should call _setValue_ in the [ngOnChanges](guide/lifecyle-hooks#onchanges) +You should call _setValue_ in the [ngOnChanges](guide/lifecycle-hooks#onchanges) hook, which Angular calls whenever the input `hero` property changes as the following steps demonstrate. diff --git a/aio/content/guide/set-document-title.md b/aio/content/guide/set-document-title.md index bfe7f22dd6..569873ebb8 100644 --- a/aio/content/guide/set-document-title.md +++ b/aio/content/guide/set-document-title.md @@ -10,10 +10,10 @@ Setting the document or window title using the Title service. {@a top} -Our app should be able to make the browser title bar say whatever we want it to say. +Your app should be able to make the browser title bar say whatever you want it to say. This cookbook explains how to do it. -**See the **. +See the . @@ -49,11 +49,11 @@ The obvious approach is to bind a property of the component to the HTML ` Sorry but that won't work. -The root component of our application is an element contained within the `<body>` tag. +The root component of the application is an element contained within the `<body>` tag. The HTML `<title>` is in the document `<head>`, outside the body, making it inaccessible to Angular data binding. -We could grab the browser `document` object and set the title manually. -That's dirty and undermines our chances of running the app outside of a browser someday. +You could grab the browser `document` object and set the title manually. +That's dirty and undermines your chances of running the app outside of a browser someday. <div class="l-sub-section"> @@ -74,10 +74,10 @@ Fortunately, Angular bridges the gap by providing a `Title` service as part of t The [Title](api/platform-browser/index/Title-class) service is a simple class that provides an API for getting and setting the current HTML document title: -* `getTitle() : string` — Gets the title of the current HTML document. -* `setTitle( newTitle : string )` — Sets the title of the current HTML document. +* `getTitle() : string`—Gets the title of the current HTML document. +* `setTitle( newTitle : string )`—Sets the title of the current HTML document. -Let's inject the `Title` service into the root `AppComponent` and expose a bindable `setTitle` method that calls it: +You can inject the `Title` service into the root `AppComponent` and expose a bindable `setTitle` method that calls it: <code-example path="cb-set-document-title/src/app/app.component.ts" region="class" title="src/app/app.component.ts (class)" linenums="false"> @@ -86,7 +86,7 @@ Let's inject the `Title` service into the root `AppComponent` and expose a binda -We bind that method to three anchor tags and, voilà! +Bind that method to three anchor tags and voilà! <figure class='image-display'> <img src="assets/images/cookbooks/set-document-title/set-title-anim.gif" alt="Set title"></img> @@ -94,7 +94,7 @@ We bind that method to three anchor tags and, voilà! -Here's the complete solution +Here's the complete solution: <code-tabs> @@ -116,17 +116,18 @@ Here's the complete solution -## Why we provide the *Title* service in *bootstrap* +## Why provide the *Title* service in *bootstrap* -We generally recommended providing application-wide services in the root application component, `AppComponent`. +Generally you want to provide application-wide services in the root application component, `AppComponent`. -Here we recommend registering the title service during bootstrapping, -a location we reserve for configuring the runtime Angular environment. +This cookbook recommends registering the title service during bootstrapping, +a location you reserve for configuring the runtime Angular environment. -That's exactly what we're doing. +That's exactly what you're doing. The `Title` service is part of the Angular *browser platform*. -If we bootstrap our application into a different platform, -we'll have to provide a different `Title` service that understands the concept of a "document title" for that specific platform. -Ideally the application itself neither knows nor cares about the runtime environment. +If you bootstrap your application into a different platform, +you'll have to provide a different `Title` service that understands +the concept of a "document title" for that specific platform. +Ideally, the application itself neither knows nor cares about the runtime environment. [Back to top](guide/set-document-title#top) \ No newline at end of file diff --git a/aio/content/guide/structural-directives.md b/aio/content/guide/structural-directives.md index 6e948545ef..fe684347f9 100644 --- a/aio/content/guide/structural-directives.md +++ b/aio/content/guide/structural-directives.md @@ -32,10 +32,11 @@ how you can write your own structural directives to do the same thing. * [Inside the *NgSwitch* directives](guide/structural-directives#ngSwitch) * [Prefer the (*) prefix](guide/structural-directives#prefer-asterisk) -* [The <template> element](guide/structural-directives#template) +* [The <ng-template> element](guide/structural-directives#template) * [Group sibling elements with <ng-container>](guide/structural-directives#ng-container) * [Write a structural directive](guide/structural-directives#unless) + Try the <live-example></live-example>. @@ -67,7 +68,7 @@ No brackets. No parentheses. Just `*ngIf` set to a string. You'll learn in this guide that the [asterisk (*) is a convenience notation](guide/structural-directives#asterisk) and the string is a [_microsyntax_](guide/structural-directives#microsyntax) rather than the usual [template expression](guide/template-syntax#template-expressions). -Angular desugars this notation into a marked-up `<template>` that surrounds the +Angular desugars this notation into a marked-up `<ng-template>` that surrounds the host element and its descendents. Each structural directive does something different with that template. @@ -163,7 +164,7 @@ Confirm that fact using browser developer tools to inspect the DOM. The top paragraph is in the DOM. The bottom, disused paragraph is not; -in its place is a comment about "template bindings" (more about that [later](guide/structural-directives#asterisk)). +in its place is a comment about "bindings" (more about that [later](guide/structural-directives#asterisk)). When the condition is false, `NgIf` removes its host element from the DOM, detaches it from DOM events (the attachments that it made), @@ -243,7 +244,7 @@ First, it translates the `*ngIf="..."` into a template _attribute_, `template="n -Then it translates the template _attribute_ into a template _element_, wrapped around the host element, like this. +Then it translates the template _attribute_ into a `<ng-template>` _element_, wrapped around the host element, like this. <code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-template)" region="ngif-template"> @@ -252,8 +253,8 @@ Then it translates the template _attribute_ into a template _element_, wrapped a -* The `*ngIf` directive moved to the `<template>` element where it became a property binding,`[ngIf]`. -* The rest of the `<div>`, including its class attribute, moved inside the `<template>` element. +* The `*ngIf` directive moved to the `<ng-template>` element where it became a property binding,`[ngIf]`. +* The rest of the `<div>`, including its class attribute, moved inside the `<ng-template>` element. None of these forms are actually rendered. Only the finished product ends up in the DOM. @@ -265,8 +266,8 @@ Only the finished product ends up in the DOM. -Angular consumed the `<template>` content during its actual rendering and -replaced the `<template>` with a diagnostic comment. +Angular consumed the `<ng-template>` content during its actual rendering and +replaced the `<ng-template>` with a diagnostic comment. The [`NgFor`](guide/structural-directives#ngFor) and [`NgSwitch...`](guide/structural-directives#ngSwitch) directives follow the same pattern. @@ -278,7 +279,7 @@ The [`NgFor`](guide/structural-directives#ngFor) and [`NgSwitch...`](guide/struc ## Inside _*ngFor_ Angular transforms the `*ngFor` in similar fashion from asterisk (*) syntax through -template _attribute_ to template _element_. +template _attribute_ to `<ng-template>` _element_. Here's a full-featured application of `NgFor`, written all three ways: @@ -301,7 +302,7 @@ You enable these features in the string assigned to `ngFor`, which you write in Everything _outside_ the `ngFor` string stays with the host element -(the `<div>`) as it moves inside the `<template>`. +(the `<div>`) as it moves inside the `<ng-template>`. In this example, the `[ngClass]="odd"` stays on the `<div>`. @@ -315,7 +316,7 @@ In this example, the `[ngClass]="odd"` stays on the `<div>`. ### Microsyntax The Angular microsyntax lets you configure a directive in a compact, friendly string. -The microsyntax parser translates that string into attributes on the `<template>`: +The microsyntax parser translates that string into attributes on the `<ng-template>`: * The `let` keyword declares a [_template input variable_](guide/structural-directives#template-input-variable) that you reference within the template. The input variables in this example are `hero`, `i`, and `odd`. @@ -342,7 +343,10 @@ which `NgFor` has initialized with the hero for the current iteration. describes additional `NgFor` directive properties and context properties. These microsyntax mechanisms are available to you when you write your own structural directives. -Studying the source code for `NgIf` and `NgFor` is a great way to learn more. +Studying the +[source code for `NgIf`](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts "Source: NgIf") +and [`NgFor`](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_for_of.ts "Source: NgFor") +is a great way to learn more. @@ -446,7 +450,7 @@ can be desugared into the template _attribute_ form. -That, in turn, can be desugared into the `<template>` element form. +That, in turn, can be desugared into the `<ng-template>` element form. <code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngswitch-template)" region="ngswitch-template"> @@ -465,22 +469,21 @@ Use [<ng-container>](guide/structural-directives#ng-container) when there' to host the directive. While there's rarely a good reason to apply a structural directive in template _attribute_ or _element_ form, -it's still important to know that Angular creates a `<template>` and to understand how it works. -You'll refer to the `<template>` when you [write your own structural directive](guide/structural-directives#unless). +it's still important to know that Angular creates a `<ng-template>` and to understand how it works. +You'll refer to the `<ng-template>` when you [write your own structural directive](guide/structural-directives#unless). {@a template} -## The *<template>* +## The *<ng-template>* -The <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template" target="_blank" title="MDN: Template Tag">HTML 5 <template></a> -is a formula for rendering HTML. +The <ng-template> is an Angular element for rendering HTML. It is never displayed directly. -In fact, before rendering the view, Angular _replaces_ the `<template>` and its contents with a comment. +In fact, before rendering the view, Angular _replaces_ the `<ng-template>` and its contents with a comment. -If there is no structural directive and you merely wrap some elements in a `<template>`, +If there is no structural directive and you merely wrap some elements in a `<ng-template>`, those elements disappear. That's the fate of the middle "Hip!" in the phrase "Hip! Hip! Hooray!". @@ -500,7 +503,7 @@ Angular erases the middle "Hip!", leaving the cheer a bit less enthusiastic. -A structural directive puts a `<template>` to work +A structural directive puts a `<ng-template>` to work as you'll see when you [write your own structural directive](guide/structural-directives#unless). @@ -708,11 +711,11 @@ Angular's own directives do not. A simple structural directive like this one creates an [_embedded view_](api/core/index/EmbeddedViewRef-class "API: EmbeddedViewRef") -from the Angular-generated `<template>` and inserts that view in a +from the Angular-generated `<ng-template>` and inserts that view in a [_view container_](api/core/index/ViewContainerRef-class "API: ViewContainerRef") adjacent to the directive's original `<p>` host element. -You'll acquire the `<template>` contents with a +You'll acquire the `<ng-template>` contents with a [`TemplateRef`](api/core/index/TemplateRef-class "API: TemplateRef") and access the _view container_ through a [`ViewContainerRef`](api/core/index/ViewContainerRef-class "API: ViewContainerRef"). @@ -839,7 +842,7 @@ You learned * that structural directives manipulate HTML layout. * to use [`<ng-container>`](guide/structural-directives#ngcontainer) as a grouping element when there is no suitable host element. -* that the Angular desugars [asterisk (*) syntax](guide/structural-directives#asterisk) into a `<template>`. +* that the Angular desugars [asterisk (*) syntax](guide/structural-directives#asterisk) into a `<ng-template>`. * how that works for the `NgIf`, `NgFor` and `NgSwitch` built-in directives. -* about the [_microsyntax_](guide/structural-directives#microsyntax) that expands into a [`<template>`](guide/structural-directives#template). +* about the [_microsyntax_](guide/structural-directives#microsyntax) that expands into a [`<ng-template>`](guide/structural-directives#template). * to write a [custom structural directive](guide/structural-directives#unless), `UnlessDirective`. \ No newline at end of file diff --git a/aio/content/guide/style-guide.md b/aio/content/guide/style-guide.md index 60f43b6c31..3602c8c114 100644 --- a/aio/content/guide/style-guide.md +++ b/aio/content/guide/style-guide.md @@ -3028,11 +3028,11 @@ module are referenced across the entire application. -<div class="s-rule do"> +<div class="s-rule avoid"> -**Do** not provide services in shared modules. Services are usually +**Avoid** providing services in shared modules. Services are usually singletons that are provided once for the entire application or in a particular feature module. @@ -3949,7 +3949,7 @@ in those editors that support it; it won't help with CSS styles. -<div class="s-rule do"> +<div class="s-rule consider"> diff --git a/aio/content/guide/template-syntax.md b/aio/content/guide/template-syntax.md index 115071ef06..04e4d1dd3c 100644 --- a/aio/content/guide/template-syntax.md +++ b/aio/content/guide/template-syntax.md @@ -2028,7 +2028,7 @@ The string `"let hero of heroes"` means: > *Take each hero in the `heroes` array, store it in the local `hero` looping variable, and make it available to the templated HTML for each iteration.* -Angular translates this instruction into a `<template>` around the host element, +Angular translates this instruction into a `<ng-template>` around the host element, then uses this template repeatedly to create a new set of elements and bindings for each `hero` in the list. diff --git a/aio/content/tutorial/toh-pt1.md b/aio/content/tutorial/toh-pt1.md index 309ec76848..99859118be 100644 --- a/aio/content/tutorial/toh-pt1.md +++ b/aio/content/tutorial/toh-pt1.md @@ -157,7 +157,7 @@ Add these properties near the top of the `app.component.ts` file, just below the -In the `Hero` class, refactor the component's `hero` property to be of type `Hero`, +In the `AppComponent` class, refactor the component's `hero` property to be of type `Hero`, then initialize it with an `id` of `1` and the name `Windstorm`. diff --git a/aio/content/tutorial/toh-pt2.md b/aio/content/tutorial/toh-pt2.md index 055e53dde1..a91e61e603 100644 --- a/aio/content/tutorial/toh-pt2.md +++ b/aio/content/tutorial/toh-pt2.md @@ -163,7 +163,7 @@ Now you can fill the template with hero names. ### List heroes with ngFor -The goal is to bind the array of `heroes` in the component to the template, iterate over them, +The goal is to bind the array of heroes in the component to the template, iterate over them, and display them individually. Modify the `<li>` tag by adding the built-in directive `*ngFor`. @@ -255,7 +255,7 @@ In this case, the _master_ is the heroes list and the _detail_ is the selected h Next you'll connect the master to the detail through a `selectedHero` component property, which is bound to a click event. -### Add a click event +### Handle click events Add a click event binding to the `<li>` like this: @@ -309,7 +309,7 @@ Add an `onSelect()` method that sets the `selectedHero` property to the `hero` t The template still refers to the old `hero` property. -Bind to the new selectedHero property instead as follows: +Bind to the new `selectedHero` property instead as follows: @@ -321,7 +321,8 @@ Bind to the new selectedHero property instead as follows: ### Hide the empty detail with ngIf -When the app loads, the `selectedHero` is undefined and won't be defined until you click a hero's name. +When the app loads, `selectedHero` is undefined. +The selected hero is initialized when the user clicks a hero's name. Angular can't display properties of the undefined `selectedHero` and throws the following error, visible in the browser's console: @@ -360,7 +361,7 @@ Don't forget the asterisk (`*`) in front of `ngIf`. The app no longer fails and the list of names displays again in the browser. -When there is no `selectedHero`, the `ngIf` directive removes the hero detail HTML from the DOM. +When there is no selected hero, the `ngIf` directive removes the hero detail HTML from the DOM. There are no hero detail elements or bindings to worry about. When the user picks a hero, `selectedHero` becomes defined and @@ -461,5 +462,5 @@ Your app should look like this <live-example></live-example>. ## The road ahead You've expanded the Tour of Heroes app, but it's far from complete. -You can't put the entire app into a single component. -In the [next page](tutorial/toh-pt3), you'll split the app into sub-components and make them work together. \ No newline at end of file +An app shouldn't be one monolithic component. +In the [next page](tutorial/toh-pt3), you'll split the app into subcomponents and make them work together. \ No newline at end of file diff --git a/aio/content/tutorial/toh-pt3.md b/aio/content/tutorial/toh-pt3.md index 719374e6af..44f396ffd1 100644 --- a/aio/content/tutorial/toh-pt3.md +++ b/aio/content/tutorial/toh-pt3.md @@ -276,7 +276,7 @@ This module declares only the two application components, `AppComponent` and `He -Read more about Angular modules in the [NgModules](guide/ngmodule "Angular Modules (NgModule) guide. +Read more about Angular modules in the [NgModules](guide/ngmodule "Angular Modules (NgModule)") guide. </div> @@ -305,7 +305,7 @@ Coordinate the master `AppComponent` with the `HeroDetailComponent` by binding the `selectedHero` property of the `AppComponent` to the `hero` property of the `HeroDetailComponent`. -<code-example path="toh-3/app/app.component.1.html" region="hero-detail-binding" title="app.component.html (excerpt)" linenums="false"> +<code-example path="toh-3/app/app.component.1.html" region="hero-detail-binding" title="app.component.ts (excerpt)" linenums="false"> </code-example> diff --git a/aio/content/tutorial/toh-pt5.md b/aio/content/tutorial/toh-pt5.md index 22b3e1e13c..0c8b0efbc2 100644 --- a/aio/content/tutorial/toh-pt5.md +++ b/aio/content/tutorial/toh-pt5.md @@ -1066,8 +1066,8 @@ by telling the router where to go. This approach requires the following changes to the component class: -1. Import the `router` from the Angular router library. -1. Inject the `router` in the constructor, along with the `HeroService`. +1. Import the `Router` from the Angular router library. +1. Inject the `Router` in the constructor, along with the `HeroService`. 1. Implement `gotoDetail()` by calling the router `navigate()` method. @@ -1223,7 +1223,7 @@ Look at the app now. The dashboard, heroes, and navigation links are styled. <figure class='image-display'> - <img src='assets/images/devguide/toh/dashboard-top-heroes.png' alt="View navigations"></img> + <img src='assets/images/devguide/toh/heroes-dashboard-1.png' alt="View navigations"></img> </figure> diff --git a/aio/content/tutorial/toh-pt6.md b/aio/content/tutorial/toh-pt6.md index fa757961d1..ddd9135a23 100644 --- a/aio/content/tutorial/toh-pt6.md +++ b/aio/content/tutorial/toh-pt6.md @@ -503,8 +503,9 @@ The calling component can easily consume a single result in the form of a Promis But requests aren't always done only once. You may start one request, cancel it, and make a different request before the server has responded to the first request. -A *request-cancel-new-request* sequence is difficult to implement with *Promises*, but -easy with *Observables*. + +A *request-cancel-new-request* sequence is difficult to implement with `Promise`s, but +easy with `Observable`s. ### Add the ability to search by name You're going to add a *hero search* feature to the Tour of Heroes. diff --git a/aio/tools/examples/shared/boilerplate/src/systemjs-angular-loader.js b/aio/tools/examples/shared/boilerplate/src/systemjs-angular-loader.js index a0f7c54538..8b1005444e 100644 --- a/aio/tools/examples/shared/boilerplate/src/systemjs-angular-loader.js +++ b/aio/tools/examples/shared/boilerplate/src/systemjs-angular-loader.js @@ -3,6 +3,8 @@ var stylesRegex = /styleUrls *:(\s*\[[^\]]*?\])/g; var stringRegex = /(['`"])((?:[^\\]\\\1|.)*?)\1/g; module.exports.translate = function(load){ + if (load.source.indexOf('moduleId') != -1) return load; + var url = document.createElement('a'); url.href = load.address; @@ -15,11 +17,13 @@ module.exports.translate = function(load){ baseHref.href = this.baseURL; baseHref = baseHref.pathname; - basePath = basePath.replace(baseHref, ''); + if (!baseHref.startsWith('/base/')) { // it is not karma + basePath = basePath.replace(baseHref, ''); + } load.source = load.source .replace(templateUrlRegex, function(match, quote, url){ - let resolvedUrl = url; + var resolvedUrl = url; if (url.startsWith('.')) { resolvedUrl = basePath + url.substr(1);