翻译完了“升级”一章的新增部分

合并了测试索引
解决了移动设备上菜单显示不全的问题
文字微调
This commit is contained in:
Zhicheng Wang 2016-05-31 12:35:37 +08:00
parent 3c666d881e
commit 20bf6c0085
7 changed files with 309 additions and 113 deletions

View File

@ -105,6 +105,12 @@
"intro": "废弃的Beta版路由" "intro": "废弃的Beta版路由"
}, },
"router": {
"title": "路由与导航",
"intro": "揭示如何通过Angular 2路由进行基本的屏幕导航。",
"hide": true
},
"structural-directives": { "structural-directives": {
"title": "结构型指令", "title": "结构型指令",
"intro": "Angular有一个强力的模板引擎它能让你轻松维护元素的DOM树结构。" "intro": "Angular有一个强力的模板引擎它能让你轻松维护元素的DOM树结构。"

View File

@ -1,88 +1,194 @@
:marked :marked
We write **unit tests** to explore and confirm the **behavior** of parts of our application. We write **unit tests** to explore and confirm the **behavior** of parts of our application.
我们编写**单元测试**来探索和确认我们应用程序的**行为**部分。 我们编写**单元测试**来探索并巩固应用程序中的**行为**部分。
1. They **guard** against breaking existing code (“regressions”) when we make changes. 1. They **guard** against breaking existing code (“regressions”) when we make changes.
1. 当我们改变代码是,它们**守护**已有代码,以防被破坏。
1. 当我们做出修改时,它们会**守护**已有代码(回归测试),防止其被破坏。
1. They **clarify** what the code does both when used as intended and when faced with deviant conditions. 1. They **clarify** what the code does both when used as intended and when faced with deviant conditions.
1. 在我们正确使用代码和面对异常情况时,它们**澄清**代码做什么。
1. 当我们正确使用代码和面对异常情况时,它们会让代码的用途更加**明晰**。
1. They **reveal** mistakes in design and implementation. Tests force us to look at our code from many angles. When a part of our application seems hard to test, we may have discovered a design flaw, something we can cure now rather than later when it becomes expensive to fix. 1. They **reveal** mistakes in design and implementation. Tests force us to look at our code from many angles. When a part of our application seems hard to test, we may have discovered a design flaw, something we can cure now rather than later when it becomes expensive to fix.
1. 它们**揭示**我们设计和实现的错误。测试强迫我们从多个角度看代码。当应用程序的一个部分看起来很难测试,我们可能会发现设计缺陷,这是我们可以立刻修复的,而不是等到它变得很难修复的时候。
1. 它们会**揭露**我们设计和实现中的错误。测试会强迫我们从多种角度看代码。如果应用程序的一个部分看起来很难测试,这可能就意味着存在设计缺陷。
我们可以立即修复它,而不用等到它变得不可收拾的那一天。
a(id="top") a(id="top")
:marked :marked
# Table of Contents # Table of Contents
# 目录 # 目录
1. [Jasmine Testing 101](#jasmine-101) 1. [Jasmine Testing 101](#jasmine-101)
1. [Jasmine测试101](#jasmine-101)
1. [Jasmine测试简介](#jasmine-101)
- setup to run Jasmine tests in the browser - setup to run Jasmine tests in the browser
- 设置浏览器来运行Jasmine测试
- 设置浏览器来运行Jasmine测试
- basic Jasmine testing skills - basic Jasmine testing skills
- 基础Jasmine测试技能
- Jasmine测试的基本技能
- write simple Jasmine tests in TypeScript - write simple Jasmine tests in TypeScript
- 实用TypeScript来编写简单的Jasmine测试
- 用TypeScript编写简单的Jasmine测试
- debug a test in the browser - debug a test in the browser
- 在浏览器里调试测试
- 在浏览器里调试一个测试
1. [The Application Under Test](#aut) 1. [The Application Under Test](#aut)
1. [被测试的应用程序](#aut) 1. [被测试的应用程序](#aut)
1. [First app test](#first-app-tests) 1. [First app test](#first-app-tests)
1. [第一个应用程序测试](#first-app-tests) 1. [第一个应用程序测试](#first-app-tests)
- test a simple application interface outside of Angular - test a simple application interface outside of Angular
- 在Angular之外测试一个简单的应用程序接口
- where to put the test file
- 测试文件存放到哪儿
- load a test file with systemJS
- 使用systemJS调用一个测试文件
- 在Angular之外测试一个简单的应用程序接口
- where to put the test file
- 测试文件存放到哪儿
- load a test file with systemJS
- 使用systemJS调用一个测试文件
1. [Pipe driven development](#pipe-testing) 1. [Pipe driven development](#pipe-testing)
1. [测试驱动开发一个管道](#pipe-testing) 1. [测试驱动开发一个管道](#pipe-testing)
- create a test before creating a class - create a test before creating a class
- 在新建类之前,新建一个测试
- 创建类之前,先创建一个测试
- load multiple test files in our test harness, using system.js - load multiple test files in our test harness, using system.js
- 使用system.js加载多个测试文件到我们的测试套装里
- 使用system.js往我们的测试套件里加载多个测试文件
- add the Angular 2 library to our test harness - add the Angular 2 library to our test harness
- 添加Angular 2的类库到我们的测试套装里
- 往我们的测试套件里添加Angular 2的类库
- watch the new test fail, and fix it - watch the new test fail, and fix it
- 看着新测试失败,然后修复它 - 看着新测试失败,然后修复它
1. Test an Asynchronous Service (forthcoming) 1. Test an Asynchronous Service (forthcoming)
1. 测试异步服务(即将到来)
- test an asynchronous service class outside of Angular - test an asynchronous service class outside of Angular
- 在Angular外测试异步服务类
- write a test plan in code - write a test plan in code
- 用代码写测试计划
- fake a dependency - fake a dependency
- 伪造一个依赖
- master the `catch(fail).then(done)` pattern - master the `catch(fail).then(done)` pattern
- 掌握`catch(fail).then(done)`模式
- move setup to `beforeEach` - move setup to `beforeEach`
- 把设置工作移入`beforeEach`
- test when a dependency fails - test when a dependency fails
- 测试依赖失败时的情况
- control async test timeout - control async test timeout
- 控制异步测试的超时时间
1. The Angular Test Environment (forthcoming) 1. The Angular Test Environment (forthcoming)
1. Angular测试环境即将到来
- the Angular test environment and why we need help - the Angular test environment and why we need help
- Angular测试环境以及我们为什么需要它的帮助
- add the Angular Test libraries to the test harness - add the Angular Test libraries to the test harness
- 把Angular测试库加入测试挽具中
- test the same async service using Angular Dependency Injection - test the same async service using Angular Dependency Injection
- 使用Angular依赖注入测试同一个异步服务
- reduce friction with test helpers - reduce friction with test helpers
- 减少与测试助手的摩擦
- introducing spies - introducing spies
- 引入侦探类
1. Test a Component (forthcoming) 1. Test a Component (forthcoming)
- test the component outside of Angular
1. 测试组件(即将到来)
- test the component outside of Angular
- 在Angular外面测试组件
- mock the dependent asynchronous service - mock the dependent asynchronous service
- 模拟所依赖的异步服务
- simulate interaction with the view (no DOM) - simulate interaction with the view (no DOM)
- 仿真与视图的交互不涉及DOM
- use a spy-promise to control asynchronous test flow - use a spy-promise to control asynchronous test flow
- 使用侦探型承诺(spy-promise)来控制异步测试工作流
1. Test a Component in the DOM (forthcoming 1. Test a Component in the DOM (forthcoming
- test the component inside the Angular test environment
- use the `TestComponentBuilder`
- more test helpers
- interact with the DOM
- bind to a mock dependent asynchronous service
1. 在DOM中测试组件即将到来
- test the component inside the Angular test environment
- 在Angular测试环境中测试组件
- use the `TestComponentBuilder`
- 使用`TestComponentBuilder`
- more test helpers
- 更多测试助手
- interact with the DOM
- 与DOM交互
- bind to a mock dependent asynchronous service
- 绑定到一个模拟的异步服务
1. Run the tests with karma (forthcoming) 1. Run the tests with karma (forthcoming)
1. 用Karma运行测试即将到来
Its a big agenda. Fortunately, you can learn a little bit at a time and put each lesson to use. Its a big agenda. Fortunately, you can learn a little bit at a time and put each lesson to use.
这是一个很大的日程表。幸运的是,我们可以一次只学一小点,然后把它们投入实战。
a(href="#top").to-top Back to top a(href="#top").to-top Back to top
@ -90,37 +196,49 @@ a(href="#top").to-top Back to top
a(id="jasmine-101") a(id="jasmine-101")
:marked :marked
# Jasmine Testing 101 # Jasmine Testing 101
# Jasmine测试101
# Jasmine测试简介
!= partial("../testing/jasmine-testing-101") != partial("../testing/jasmine-testing-101")
a(href="#top").to-top Back to top a(href="#top").to-top Back to top
a(href="#top").to-top 回到顶部
.l-hr .l-hr
a(id="aut") a(id="aut")
:marked :marked
# The Application to Test # The Application to Test
# 被测试的应用程序 # 被测试的应用程序
!= partial("../testing/application-under-test") != partial("../testing/application-under-test")
a(href="#top").to-top Back to top a(href="#top").to-top Back to top
a(href="#top").to-top 回到顶部
.l-hr .l-hr
a(id="first-app-tests") a(id="first-app-tests")
:marked :marked
# First app test # First app test
# 第一个应用程序测试 # 第一个应用程序测试
!= partial("../testing/first-app-tests") != partial("../testing/first-app-tests")
a(href="#top").to-top Back to top a(href="#top").to-top Back to top
a(href="#top").to-top 回到顶部
.l-hr .l-hr
a(id="pipe-testing") a(id="pipe-testing")
:marked :marked
# Pipe driven development # Pipe driven development
# 测试驱动开发一个管道 # 测试驱动开发一个管道
!= partial("../testing/testing-an-angular-pipe") != partial("../testing/testing-an-angular-pipe")
a(href="#top").to-top Back to top a(href="#top").to-top Back to top
a(href="#top").to-top 回到顶部
.alert.is-important .alert.is-important
:marked :marked
The testing chapter is still under development. The testing chapter is still under development.
Please bear with us as we both update and complete it. Please bear with us as we both update and complete it.
测试章节正在开发中,请耐心,我们会更新并完成它。 测试章节正在开发中,请耐心,我们会更新并完成它。

View File

@ -226,7 +226,7 @@ include ../_util-fns
* JavaScript features new to ES2015, like arrow functions, `let`s and `const`s, * JavaScript features new to ES2015, like arrow functions, `let`s and `const`s,
default function parameters, and destructuring assignments can also be gradually default function parameters, and destructuring assignments can also be gradually
added to make the code more expressive. added to make the code more expressive.
* 那些ES2015中新增的特性比如箭头函数、`let`、`const`、默认函数参数、解构赋值等也能逐渐添加进来,让代码更有表现力。 * 那些ES2015中新增的特性比如箭头函数、`let`、`const`、默认函数参数、解构赋值等也能逐渐添加进来,让代码更有表现力。
* Services and controllers can be turned into *classes*. That way they'll be a step * Services and controllers can be turned into *classes*. That way they'll be a step
@ -353,7 +353,7 @@ include ../_util-fns
are another convenient feature that Angular 1.5 introduces. They all have nearly are another convenient feature that Angular 1.5 introduces. They all have nearly
exact [equivalents in Angular 2](lifecycle-hooks.html), so organizing component lifecycle exact [equivalents in Angular 2](lifecycle-hooks.html), so organizing component lifecycle
logic around them will ease the eventual Angular 2 upgrade process. logic around them will ease the eventual Angular 2 upgrade process.
控制器的生命周期钩子`$onInit()`、`$onDestroy()`和`$onChanges()`是Angular 1.5引入的另一些便利特性。 控制器的生命周期钩子`$onInit()`、`$onDestroy()`和`$onChanges()`是Angular 1.5引入的另一些便利特性。
它们都很接近于[Angular 2中的等价物](lifecycle-hooks.html),所以,围绕它们组织组件生命周期的逻辑会更容易升级。 它们都很接近于[Angular 2中的等价物](lifecycle-hooks.html),所以,围绕它们组织组件生命周期的逻辑会更容易升级。
@ -798,7 +798,7 @@ figure
Note that even though we are in an Angular 1 template, **we're using Angular 2 Note that even though we are in an Angular 1 template, **we're using Angular 2
attribute syntax to bind the inputs and outputs**. This is a requirement for downgraded attribute syntax to bind the inputs and outputs**. This is a requirement for downgraded
components. The expressions themselves are still regular Angular 1 expressions. components. The expressions themselves are still regular Angular 1 expressions.
注意虽然我们正在Angular 1的模板中**但却在使用Angular 2的属性(Attribute)语法来绑定到输入属性与输出属性**。 注意虽然我们正在Angular 1的模板中**但却在使用Angular 2的属性(Attribute)语法来绑定到输入属性与输出属性**。
这是降级的组件本身要求的。而表达式本身仍然是标准的Angular 1表达式。 这是降级的组件本身要求的。而表达式本身仍然是标准的Angular 1表达式。
@ -809,16 +809,16 @@ figure
There's one notable exception to the rule of using Angular 2 attribute syntax There's one notable exception to the rule of using Angular 2 attribute syntax
for downgraded components. It has to do with input or output names that consist for downgraded components. It has to do with input or output names that consist
of multiple words. In Angular 2 we would bind these attributes using camelCase: of multiple words. In Angular 2 we would bind these attributes using camelCase:
为降级过的组件使用Angualr 2的属性(Attribute)语法规则时有一个值得注意的例外。 为降级过的组件使用Angualr 2的属性(Attribute)语法规则时有一个值得注意的例外。
它适用于由多个单词组成的输入或输出属性。在Angular 2中我们要使用小驼峰命名法绑定这些属性 它适用于由多个单词组成的输入或输出属性。在Angular 2中我们要使用小驼峰命名法绑定这些属性
code-example(format=""). code-example(format="").
[myHero]="hero" [myHero]="hero"
:marked :marked
But when using them from Angular 1 templates, we need to use kebab-case: But when using them from Angular 1 templates, we need to use kebab-case:
但是从Angular 1的模板中使用它们时我们得使用中线命名法 但是从Angular 1的模板中使用它们时我们得使用中线命名法
code-example(format=""). code-example(format="").
[my-hero]="hero" [my-hero]="hero"
@ -1147,7 +1147,7 @@ figure
.l-main-section .l-main-section
:marked :marked
# PhoneCat Upgrade Tutorial # PhoneCat Upgrade Tutorial
# PhoneCat升级教程 # PhoneCat升级教程
In this section and we will look at a complete example of In this section and we will look at a complete example of
@ -1239,7 +1239,7 @@ figure
* Each component, service, and filter is in its own source file, as per the * Each component, service, and filter is in its own source file, as per the
[Rule of 1](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#single-responsibility). [Rule of 1](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#single-responsibility).
* 每个组件、服务和过滤器都在它自己的源文件中 —— 就像[规则1](https://github.com/johnpapa/angular-styleguide#single-responsibility)所要求的。 * 每个组件、服务和过滤器都在它自己的源文件中 —— 就像[规则1](https://github.com/johnpapa/angular-styleguide#single-responsibility)所要求的。
* The `core`, `phone-detail`, and `phone-list` modules are each in their * The `core`, `phone-detail`, and `phone-list` modules are each in their
@ -1256,13 +1256,13 @@ figure
* Unit tests are located side-by-side with application code where they are easily * Unit tests are located side-by-side with application code where they are easily
found, as described in the rules for found, as described in the rules for
[Organizing Tests](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#style-y197). [Organizing Tests](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#style-y197).
* 单元测试都和应用代码在一起,它们很容易找到。就像规则 * 单元测试都和应用代码在一起,它们很容易找到。就像规则
[组织测试文件](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#style-y197)中要求的那样。 [组织测试文件](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#style-y197)中要求的那样。
:marked :marked
## Switching to TypeScript ## Switching to TypeScript
## 切换到TypeScript ## 切换到TypeScript
Since we're going to be writing our Angular 2 code in TypeScript, it makes sense to Since we're going to be writing our Angular 2 code in TypeScript, it makes sense to
@ -1347,7 +1347,7 @@ code-example(format="").
compiled JavaScript is what actually gets executed. If you start compiled JavaScript is what actually gets executed. If you start
the project HTTP server with `npm start`, you should see the fully functional the project HTTP server with `npm start`, you should see the fully functional
application in your browser. application in your browser.
我们要做的下一件事是把JavaScript文件转换成TypeScript文件。 我们要做的下一件事是把JavaScript文件转换成TypeScript文件。
由于TypeScript是ECMAScript 2015的一个超集而ES2015又是ECMAScript 5的超集所以我们可以简单的把文件的扩展名从`.js`换成`.ts` 由于TypeScript是ECMAScript 2015的一个超集而ES2015又是ECMAScript 5的超集所以我们可以简单的把文件的扩展名从`.js`换成`.ts`
它们就还会像以前一样工作。由于TypeScript编译器仍在运行它会为每一个`.ts`文件生成对应的`.js`文件,而真正运行的是编译后的`.js`文件。 它们就还会像以前一样工作。由于TypeScript编译器仍在运行它会为每一个`.ts`文件生成对应的`.js`文件,而真正运行的是编译后的`.js`文件。
@ -1355,7 +1355,7 @@ code-example(format="").
Now that we have TypeScript though, we can start benefiting from some of its Now that we have TypeScript though, we can start benefiting from some of its
features. There's a lot of value the language can provide to Angular 1 applications. features. There's a lot of value the language can provide to Angular 1 applications.
有了TypeScript我们就可以从它的一些特性中获益了。此语言可以为Angular 1应用提供很多价值。 有了TypeScript我们就可以从它的一些特性中获益了。此语言可以为Angular 1应用提供很多价值。
For one thing, TypeScript is a superset of ES2015. Any app that has previously For one thing, TypeScript is a superset of ES2015. Any app that has previously
@ -1363,7 +1363,7 @@ code-example(format="").
start incorporating all of the JavaScript features that are new to ES2015. start incorporating all of the JavaScript features that are new to ES2015.
These include things like `let`s and `const`s, arrow functions, default function These include things like `let`s and `const`s, arrow functions, default function
parameters, and destructuring assignments. parameters, and destructuring assignments.
首先TypeScript是一个ES2015的超集。任何以前用ES5写的程序就像PhoneCat范例都可以开始通过TypeScript 首先TypeScript是一个ES2015的超集。任何以前用ES5写的程序就像PhoneCat范例都可以开始通过TypeScript
纳入那些添加到ES2015中的新特性。 纳入那些添加到ES2015中的新特性。
这包括`let`、`const`、箭头函数、函数默认参数以及解构(destructure)赋值。 这包括`let`、`const`、箭头函数、函数默认参数以及解构(destructure)赋值。
@ -1372,7 +1372,7 @@ code-example(format="").
actually partially already happened because of the Angular 1 typings we installed. actually partially already happened because of the Angular 1 typings we installed.
TypeScript are checking that we are calling Angular 1 APIs correctly when we do TypeScript are checking that we are calling Angular 1 APIs correctly when we do
things like register components to Angular modules. things like register components to Angular modules.
我们能做的另一件事就是把*类型安全*添加到代码中。这实际上已经部分完成了因为我们已经安装了Angular 1的类型定义。 我们能做的另一件事就是把*类型安全*添加到代码中。这实际上已经部分完成了因为我们已经安装了Angular 1的类型定义。
当我们正确调用Angular 1的API时TypeScript会帮我们检查它 —— 比如王Angular模块中添加组件。 当我们正确调用Angular 1的API时TypeScript会帮我们检查它 —— 比如王Angular模块中添加组件。
@ -1380,7 +1380,7 @@ code-example(format="").
out of TypeScript's type system. For instance, we can annotate the checkmark out of TypeScript's type system. For instance, we can annotate the checkmark
filter so that it explicitly expects booleans as arguments. This makes it clearer filter so that it explicitly expects booleans as arguments. This makes it clearer
what the filter is supposed to do. what the filter is supposed to do.
我们还能开始把*类型注解*添加到自己的代码中来从TypeScript的类型系统中获得更多帮助。 我们还能开始把*类型注解*添加到自己的代码中来从TypeScript的类型系统中获得更多帮助。
比如,我们可以给`checkmark`过滤器加上注解,表明它期待一个`boolean`类型的参数。 比如,我们可以给`checkmark`过滤器加上注解,表明它期待一个`boolean`类型的参数。
这可以更清楚的表明此过滤器打算做什么 这可以更清楚的表明此过滤器打算做什么
@ -1390,7 +1390,7 @@ code-example(format="").
:marked :marked
In the `Phone` service we can explicitly annotate the `$resource` service dependency In the `Phone` service we can explicitly annotate the `$resource` service dependency
as an `angular.resource.IResourceService` - a type defined by the Angular 1 typings. as an `angular.resource.IResourceService` - a type defined by the Angular 1 typings.
在`Phone`服务中,我们可以明确的把`$resource`服务声明为`angular.resource.IResourceService`一个在Angular 1类型定义中提供的类型。 在`Phone`服务中,我们可以明确的把`$resource`服务声明为`angular.resource.IResourceService`一个在Angular 1类型定义中提供的类型。
+makeExample('upgrade-phonecat-1-typescript/ts/app/core/phone/phone.service.ts', null, 'app/core/phone/phone.service.ts') +makeExample('upgrade-phonecat-1-typescript/ts/app/core/phone/phone.service.ts', null, 'app/core/phone/phone.service.ts')
@ -1399,7 +1399,7 @@ code-example(format="").
We can apply the same trick to the application's route configuration file in `app.config.ts`, We can apply the same trick to the application's route configuration file in `app.config.ts`,
where we are using the location and route services. By annotating them accordingly TypeScript where we are using the location and route services. By annotating them accordingly TypeScript
can verify we're calling their APIs with the correct kinds of arguments. can verify we're calling their APIs with the correct kinds of arguments.
我们可以在应用的路由配置中使用同样的技巧那里我们用到了location和route服务。 我们可以在应用的路由配置中使用同样的技巧那里我们用到了location和route服务。
一旦给它们提供了类型信息TypeScript就能检查我们是否在用类型正确的参数来调用它们了。 一旦给它们提供了类型信息TypeScript就能检查我们是否在用类型正确的参数来调用它们了。
@ -1411,7 +1411,7 @@ code-example(format="").
we installed with Typings are not officially maintained by the Angular team, we installed with Typings are not officially maintained by the Angular team,
but are quite comprehensive. It is possible to make an Angular 1.x application but are quite comprehensive. It is possible to make an Angular 1.x application
fully type-annotated with the help of these definitions. fully type-annotated with the help of these definitions.
我们用typings工具安装的这个[Angular 1.x类型定义文件](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/angularjs) 我们用typings工具安装的这个[Angular 1.x类型定义文件](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/angularjs)
并不是由Angular开发组维护的但它也已经足够全面了。借助这些类型定义的帮助它可以为Angular 1.x程序加上全面的类型注解。 并不是由Angular开发组维护的但它也已经足够全面了。借助这些类型定义的帮助它可以为Angular 1.x程序加上全面的类型注解。
@ -1442,7 +1442,7 @@ code-example(format="").
这也就意味着只要我们把一个类注册为组件控制器Angular 1就会愉快的使用它。 这也就意味着只要我们把一个类注册为组件控制器Angular 1就会愉快的使用它。
Here's what our new class for the phone list component controller looks like: Here's what our new class for the phone list component controller looks like:
新的“电话列表(phone list)”组件控制器类看起来是这样的: 新的“电话列表(phone list)”组件控制器类看起来是这样的:
+makeExample('upgrade-phonecat/ts/classes/app/js/phone_list/phone_list.controller.ts', null, 'app/js/phone_list/phone_list.controller.ts') +makeExample('upgrade-phonecat/ts/classes/app/js/phone_list/phone_list.controller.ts', null, 'app/js/phone_list/phone_list.controller.ts')
@ -1462,14 +1462,14 @@ code-example(format="").
The last one of these isn't actually used in the TypeScript code since it's only The last one of these isn't actually used in the TypeScript code since it's only
referred to in the template, but for the sake of clarity we want to define all the referred to in the template, but for the sake of clarity we want to define all the
members our controller will have. members our controller will have.
该类额外声明了三个成员:电话列表、当前排序键的名字,以及搜索条件。 该类额外声明了三个成员:电话列表、当前排序键的名字,以及搜索条件。
这些东西我们以前就加到了控制器上只是从来没有在任何地方显式定义过它们。最后一个成员从未真正在TypeScript代码中用过 这些东西我们以前就加到了控制器上只是从来没有在任何地方显式定义过它们。最后一个成员从未真正在TypeScript代码中用过
因为它只是在模板中被引用过。但为了清晰起见,我们还是该定义出此控制器应有的所有成员。 因为它只是在模板中被引用过。但为了清晰起见,我们还是该定义出此控制器应有的所有成员。
In the Phone detail controller we'll have two members: One for the phone In the Phone detail controller we'll have two members: One for the phone
that the user is looking at and another for the URL of the currently displayed image: that the user is looking at and another for the URL of the currently displayed image:
在电话详情控制器中,我们有两个成员:一个是用户正在查看的电话,另一个是正在显示的图像: 在电话详情控制器中,我们有两个成员:一个是用户正在查看的电话,另一个是正在显示的图像:
+makeExample('upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.component.ts', null, 'app/phone-detail/phone-detail.component.ts') +makeExample('upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.component.ts', null, 'app/phone-detail/phone-detail.component.ts')
@ -1512,17 +1512,17 @@ code-example(format="").
我们来使用SystemJS模块加载器把Angular 2安装到项目中。 我们来使用SystemJS模块加载器把Angular 2安装到项目中。
看看[“快速起步”](../quickstart.html)中的指南,并从那里获得如下配置: 看看[“快速起步”](../quickstart.html)中的指南,并从那里获得如下配置:
* Add Angular 2 and the other new dependencies to `package.json` * Add Angular 2 and the other new dependencies to `package.json`
* 把添加Angular 2和其它新依赖添加到`package.json`中 * 把添加Angular 2和其它新依赖添加到`package.json`中
* Add the new typings into `typings.json` * Add the new typings into `typings.json`
* 把这些新的类型定义添加到`typings.json`中 * 把这些新的类型定义添加到`typings.json`中
* The SystemJS configuration file `systemjs.config.js` to the project root directory. * The SystemJS configuration file `systemjs.config.js` to the project root directory.
* 把SystemJS的配置文件`systemjs.config.js`添加到项目的根目录。 * 把SystemJS的配置文件`systemjs.config.js`添加到项目的根目录。
Once these are done, run: Once these are done, run:
@ -1538,14 +1538,14 @@ code-example(format="").
but first we need to do some directory path adjustments. This is because we're going but first we need to do some directory path adjustments. This is because we're going
to need to load files from `node_modules` and the project root, whereas so far to need to load files from `node_modules` and the project root, whereas so far
in this project everything has been loaded from the `/app` directory. in this project everything has been loaded from the `/app` directory.
我们可以通过`index.html`来把Angular 2的依赖快速加载到应用中 我们可以通过`index.html`来把Angular 2的依赖快速加载到应用中
但首先,我们得做一些目录结构调整。这是因为我们正准备从`node_modules`中加载文件,然而目前项目中的每一个文件都是从`/app`目录下加载的。 但首先,我们得做一些目录结构调整。这是因为我们正准备从`node_modules`中加载文件,然而目前项目中的每一个文件都是从`/app`目录下加载的。
Move the `app/index.html` file to the project root directory. Then change the Move the `app/index.html` file to the project root directory. Then change the
development server root path in `package.json` to also point to the project root development server root path in `package.json` to also point to the project root
instead of `app`: instead of `app`:
把`app/index.html`移入项目的根目录,然后把`package.json`中的开发服务器根目录也指向项目的根目录,而不再是`app`目录: 把`app/index.html`移入项目的根目录,然后把`package.json`中的开发服务器根目录也指向项目的根目录,而不再是`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')
@ -1555,7 +1555,7 @@ code-example(format="").
want to have to change all the image and data paths used in the application code to match want to have to change all the image and data paths used in the application code to match
our development setup. For that reason, we'll add a `<base>` tag to `index.html`, which will our development setup. For that reason, we'll add a `<base>` tag to `index.html`, which will
cause relative URLs to be resolved back to the `/app` directory: cause relative URLs to be resolved back to the `/app` directory:
现在,我们能把项目根目录下的每一样东西发给浏览器了。但我们并不想修改在应用代码中用到的每一个图片和数据的路径, 现在,我们能把项目根目录下的每一样东西发给浏览器了。但我们并不想修改在应用代码中用到的每一个图片和数据的路径,
以适应我们开发环境中的设置。因此,我们往`index.html`中添加一个`<base>`标签,它将导致各种相对路径被解析回`/app`目录: 以适应我们开发环境中的设置。因此,我们往`index.html`中添加一个`<base>`标签,它将导致各种相对路径被解析回`/app`目录:
@ -1565,7 +1565,7 @@ code-example(format="").
Now we can load Angular 2 via SystemJS. We'll add the Angular 2 polyfills and the Now we can load Angular 2 via SystemJS. We'll add the Angular 2 polyfills and the
SystemJS config to the end of the `<head>` section, and then we'll use `System.import` SystemJS config to the end of the `<head>` section, and then we'll use `System.import`
to load the actual application: to load the actual application:
现在我们可以通过SystemJS加载Angular 2了。我们将把Angular 2的填充库(polyfills) 现在我们可以通过SystemJS加载Angular 2了。我们将把Angular 2的填充库(polyfills)
和SystemJS的配置加到`<head>`区的末尾,然后,我们就用`System.import`来加载实际的应用: 和SystemJS的配置加到`<head>`区的末尾,然后,我们就用`System.import`来加载实际的应用:
@ -1575,7 +1575,7 @@ code-example(format="").
In the `systemjs.config.js` file we got from the Quickstart we also need to make a couple In the `systemjs.config.js` file we got from the Quickstart we also need to make a couple
of adjustments because of our project structure. We want to point the browser to the project of adjustments because of our project structure. We want to point the browser to the project
root when loading things through SystemJS, instead of using the `<base>` URL: root when loading things through SystemJS, instead of using the `<base>` URL:
在我们从“快速起步”中拿来的`systemjs.config.js`文件中,我们还需要做一些调整,以适应我们的项目结构。 在我们从“快速起步”中拿来的`systemjs.config.js`文件中,我们还需要做一些调整,以适应我们的项目结构。
在使用SystemJS而不是`<base>` URL加载时我们需要把浏览器指向项目的根目录。 在使用SystemJS而不是`<base>` URL加载时我们需要把浏览器指向项目的根目录。
@ -1588,7 +1588,7 @@ code-example(format="").
What we'll do next is bootstrap the application as a *hybrid application* 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 that supports both Angular 1 and Angular 2 components. Once we've done that
we can start converting the individual pieces to Angular 2. we can start converting the individual pieces to Angular 2.
我们后面将做的就是把该应用程序引导为一个同时支持Angular 1和Angular 2的*混合式应用*。 我们后面将做的就是把该应用程序引导为一个同时支持Angular 1和Angular 2的*混合式应用*。
一旦我们做完了就能开始把这些不可分割的小块儿转换到Angular 2了. 一旦我们做完了就能开始把这些不可分割的小块儿转换到Angular 2了.
@ -1597,7 +1597,7 @@ code-example(format="").
versions of the framework together. Let's import the `UpgradeAdapter` class into a versions of the framework together. Let's import the `UpgradeAdapter` class into a
new file `app/main.ts`. This file has been configured as the application entrypoint new file `app/main.ts`. This file has been configured as the application entrypoint
in `systemjs.config.js`, so it is already being loaded by the browser. in `systemjs.config.js`, so it is already being loaded by the browser.
要引导一个混合式应用,我们首先得初始化一个`UpgradeAdapter`,它[提供了胶水](#upgrading-with-the-upgrade-adapter) 要引导一个混合式应用,我们首先得初始化一个`UpgradeAdapter`,它[提供了胶水](#upgrading-with-the-upgrade-adapter)
来把框架的两个不同版本粘在一起。我们在一个新文件`app/main.ts`中导入`UpgradeAdapter`类。 来把框架的两个不同版本粘在一起。我们在一个新文件`app/main.ts`中导入`UpgradeAdapter`类。
这个文件已经在`systemjs.config.js`文件中被配置成了应用的入口点,所以它已经被浏览器加载了。 这个文件已经在`systemjs.config.js`文件中被配置成了应用的入口点,所以它已经被浏览器加载了。
@ -1616,7 +1616,7 @@ code-example(format="").
attached to the `<html>` element of the host page. This will no longer work with attached to the `<html>` element of the host page. This will no longer work with
Angular 2. We should switch to a JavaScript-driven bootstrap instead. So, remove the Angular 2. We should switch to a JavaScript-driven bootstrap instead. So, remove the
`ng-app` attribute from `index.html`, and instead add this to `main.ts`: `ng-app` attribute from `index.html`, and instead add this to `main.ts`:
我们的应用现在是使用宿主页面中附加到`<html>`元素上的`ng-app`指令引导的。 我们的应用现在是使用宿主页面中附加到`<html>`元素上的`ng-app`指令引导的。
但在Angular 2中它不再工作了。我们得切换成JavaScript驱动的引导方式。 但在Angular 2中它不再工作了。我们得切换成JavaScript驱动的引导方式。
所以,从`index.html`中移除`ng-app`属性,并把这些加载`main.ts`中: 所以,从`index.html`中移除`ng-app`属性,并把这些加载`main.ts`中:
@ -1629,7 +1629,7 @@ code-example(format="").
that we want to load. Since we're bootstrapping the app through that we want to load. Since we're bootstrapping the app through
an `UpgradeAdapter`, we're actually now running the app as a hybrid Angular 1+2 an `UpgradeAdapter`, we're actually now running the app as a hybrid Angular 1+2
app. app.
这里使用的参数是应用的根元素(也就是以前我们放`ng-app`的元素)和我们准备加载的Angular 1.x模块。 这里使用的参数是应用的根元素(也就是以前我们放`ng-app`的元素)和我们准备加载的Angular 1.x模块。
由于我们是通过`UpgradeAdapter`引导应用的所以实际在运行的应用实际上是一个Angular 1+2的混合体。 由于我们是通过`UpgradeAdapter`引导应用的所以实际在运行的应用实际上是一个Angular 1+2的混合体。
@ -1753,7 +1753,7 @@ code-example(format="").
`UpgradeAdapter` has a `downgradeNg2Provider` method for the purpose of making `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 Angular 2 services available to Angular 1 code. We can use it to plug in our
`Phone` service: `Phone` service:
`UpgradeAdapter`有个`downgradeNg2Provider`方法就是用来让Angular 2的服务在Angular 1的代码中可用的。 `UpgradeAdapter`有个`downgradeNg2Provider`方法就是用来让Angular 2的服务在Angular 1的代码中可用的。
我们可以使用它来插入我们的`Phone`服务: 我们可以使用它来插入我们的`Phone`服务:
@ -1766,19 +1766,19 @@ code-example(format="").
1. Register `Phone` as an **Angular 2 provider** with the `addProvider` 1. Register `Phone` as an **Angular 2 provider** with the `addProvider`
method. That's the same method that we used earlier for `HTTP_PROVIDERS`. method. That's the same method that we used earlier for `HTTP_PROVIDERS`.
1. 用`addProvider`方法注册了一个名叫`Phone`的**Angular 2供应商**。这和我们以前使用`HTTP_PROVIDERS`的方法一样。 1. 用`addProvider`方法注册了一个名叫`Phone`的**Angular 2供应商**。这和我们以前使用`HTTP_PROVIDERS`的方法一样。
2. Register an **Angular 1 factory** called `phone`, which will be a *downgraded* 2. Register an **Angular 1 factory** called `phone`, which will be a *downgraded*
version of the `Phone` Angular 2 service. version of the `Phone` Angular 2 service.
2. 注册了一个名叫`phone`的**Angular 1工厂**,它是一个`Phones`服务的*降级*版。 2. 注册了一个名叫`phone`的**Angular 1工厂**,它是一个`Phones`服务的*降级*版。
Now that we are loading `phone.service.ts` through an import that is resolved 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`. 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 This is something we'll do to all our components as we upgrade them. Simultaneously
with the Angular 1 to 2 upgrade we're also migrating our code from scripts to modules. with the Angular 1 to 2 upgrade we're also migrating our code from scripts to modules.
现在我们正在用SystemJS加载`phone.service.ts`,我们应该从`index.html`中**移除该服务的`<script>`标签**。 现在我们正在用SystemJS加载`phone.service.ts`,我们应该从`index.html`中**移除该服务的`<script>`标签**。
这也是我们在升级所有组件时将会做的事。在从Angular 1向2升级的同时我们也把代码从脚本移植为模块。 这也是我们在升级所有组件时将会做的事。在从Angular 1向2升级的同时我们也把代码从脚本移植为模块。
@ -1786,7 +1786,7 @@ code-example(format="").
instead of the old one. We `$inject` it as the downgraded `phone` factory, instead of the old one. We `$inject` it as the downgraded `phone` factory,
but it's really an instance of the `Phone` class and we can annotate its type but it's really an instance of the `Phone` class and we can annotate its type
accordingly: accordingly:
这时,我们可以把两个控制器从使用老的服务切换成使用新的。我们像降级过的`phones`工厂一样`$inject`它, 这时,我们可以把两个控制器从使用老的服务切换成使用新的。我们像降级过的`phones`工厂一样`$inject`它,
但它实际上是一个`Phones`类的实例,并且我们可以据此注解它的类型: 但它实际上是一个`Phones`类的实例,并且我们可以据此注解它的类型:
@ -1810,28 +1810,28 @@ code-example(format="").
We could also use the `toPromise` method of `Observable` to turn those We could also use the `toPromise` method of `Observable` to turn those
Observables into Promises in the service. This can in many cases further Observables into Promises in the service. This can in many cases further
reduce the amount of changes needed in the component controllers. reduce the amount of changes needed in the component controllers.
我们也能使用`Observable`的`toPromise`方法来在服务中把这些可观察对象转变成承诺,以进一步减小组件控制器中需要修改的代码量。 我们也能使用`Observable`的`toPromise`方法来在服务中把这些可观察对象转变成承诺,以进一步减小组件控制器中需要修改的代码量。
:marked :marked
## Upgrading Components ## Upgrading Components
## 升级组件 ## 升级组件
Next, let's upgrade our Angular 1 components to Angular 2 components. We'll Next, let's upgrade our Angular 1 components to Angular 2 components. We'll
do it one at a time, while still keeping the application in hybrid mode. do it one at a time, while still keeping the application in hybrid mode.
As we make these conversions, we'll also be defining our first Angular 2 *pipes*. As we make these conversions, we'll also be defining our first Angular 2 *pipes*.
接下来我们把Angular 1的控制器升级成Angular 2的组件。我们每次升级一个同时仍然保持应用运行在混合模式下。 接下来我们把Angular 1的控制器升级成Angular 2的组件。我们每次升级一个同时仍然保持应用运行在混合模式下。
在做转换的同时我们还将自定义首个Angular 2*管道*。 在做转换的同时我们还将自定义首个Angular 2*管道*。
Let's look at the phone list component first. Right now it contains a TypeScript Let's look at the phone list component first. Right now it contains a TypeScript
controller class and a component definition object. We can morph this into controller class and a component definition object. We can morph this into
an Angular 2 component by just renaming the controller class and turning the an Angular 2 component by just renaming the controller class and turning the
Angular 1 component definition object into an Angular 2 `@Component` decorator. Angular 1 component definition object into an Angular 2 `@Component` decorator.
We can then also remove the static `$inject` property from the class: We can then also remove the static `$inject` property from the class:
+makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ts', 'initialclass', 'app/phone-list/phone-list.component.ts') +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ts', 'initialclass', 'app/phone-list/phone-list.component.ts')
:marked :marked
@ -1839,7 +1839,7 @@ code-example(format="").
should go. In Angular 1 we do matching based on component names, but in Angular 2 we should go. In Angular 1 we do matching based on component names, but in Angular 2 we
have these explicit selectors. This one will match elements with the name `phone-list`, have these explicit selectors. This one will match elements with the name `phone-list`,
just like the Angular 1 version did. just like the Angular 1 version did.
We now also need to convert the template of this component into Angular 2 syntax. 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. 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: We should also no longer use the `$ctrl` prefix in expressions:
@ -1851,7 +1851,7 @@ code-example(format="").
`let var of iterable` syntax, which is [described in our `let var of iterable` syntax, which is [described in our
Template Syntax guide](../guide/template-syntax.html#directives). Template Syntax guide](../guide/template-syntax.html#directives).
For the images, we can replace `ng-src` with a binding to the standard `src` property. For the images, we can replace `ng-src` with a binding to the standard `src` property.
在列表中,我们需要把`ng-repeat`替换为`*ngFor`以及它的`let var of iterable`语法, 在列表中,我们需要把`ng-repeat`替换为`*ngFor`以及它的`let var of iterable`语法,
该语法在[模板语法指南中讲过](../guide/template-syntax.html#directives)。 该语法在[模板语法指南中讲过](../guide/template-syntax.html#directives)。
对于图片,我们可以把`ng-src`替换为一个标准的`src`属性(property)绑定。 对于图片,我们可以把`ng-src`替换为一个标准的`src`属性(property)绑定。
@ -1866,7 +1866,7 @@ code-example(format="").
pipes for this purpose, but in this case it is more convenient to just implement the filtering 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 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. where the current filtering and ordering has been applied.
我们在这里做的另一件事就是移除了`filter`和`orderBy`过滤器的使用,并把它们换成对控制器中`getPhones()`方法的调用。 我们在这里做的另一件事就是移除了`filter`和`orderBy`过滤器的使用,并把它们换成对控制器中`getPhones()`方法的调用。
内建的`filter`和`orderBy`在Angular 2中已经不存在了所以我们得自己进行过滤和排序。 内建的`filter`和`orderBy`在Angular 2中已经不存在了所以我们得自己进行过滤和排序。
我们可以为此定义自己的Angular 2管道但是在这个案例中在组件本身实现过滤和排序逻辑反倒更方便。 我们可以为此定义自己的Angular 2管道但是在这个案例中在组件本身实现过滤和排序逻辑反倒更方便。
@ -1894,12 +1894,12 @@ code-example(format="").
降级方法(`downgradeNg2Component`)的返回值能作为指令工厂使用。 降级方法(`downgradeNg2Component`)的返回值能作为指令工厂使用。
At this point, also remove the `<script>` tag for the phone list component from `index.html`. At this point, also remove the `<script>` tag for the phone list component from `index.html`.
这时,也从`index.html`中移除电话列表组件的`<script>`标签。 这时,也从`index.html`中移除电话列表组件的`<script>`标签。
Now we can start looking at our other component, which is the one for 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: the phone details. Set the contents of `phone-detail.component.ts` as follows:
现在我们可以开始看看另一个组件,那就是电话详情。把`phone-detail.component.ts`的内容设置为这样: 现在我们可以开始看看另一个组件,那就是电话详情。把`phone-detail.component.ts`的内容设置为这样:
+makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ts', 'initialclass', 'app/phone-detail/phone-detail.component.ts') +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ts', 'initialclass', 'app/phone-detail/phone-detail.component.ts')
@ -1910,7 +1910,7 @@ code-example(format="").
Angular 2 injector what this dependency should map to. We have a dependency called 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. `$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. That is what we were already using when `PhoneDetails` was still an Angular 1 controller.
这和我们对电话列表所做的很相似。这里的一个新的更改是使用`@Inject`来获取`$routeParams`依赖。 这和我们对电话列表所做的很相似。这里的一个新的更改是使用`@Inject`来获取`$routeParams`依赖。
它告诉Angular 2的注入器这个依赖该被映射成什么。我们在Angular 1的注入器中有一个名叫`$routeParams`的依赖, 它告诉Angular 2的注入器这个依赖该被映射成什么。我们在Angular 1的注入器中有一个名叫`$routeParams`的依赖,
它是由Angular 1路由器提供的。 它是由Angular 1路由器提供的。
@ -1920,11 +1920,11 @@ code-example(format="").
Angular 2 components, so if we were to run this now, it would not work. We need to explicitly 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 tell the `UpgradeAdapter` to upgrade `$routeParams` so that it is available for injection in
Angular 2. We can do it in `main.ts`: Angular 2. We can do it in `main.ts`:
问题是Angular 1的依赖不会自动对Angular 2的组件可用所以如果我们现在运行它它将无法工作。 问题是Angular 1的依赖不会自动对Angular 2的组件可用所以如果我们现在运行它它将无法工作。
我们得显式的告诉`UpgradeAdapter`去升级`$routeParams`以便它能被注入到Angular 2中。 我们得显式的告诉`UpgradeAdapter`去升级`$routeParams`以便它能被注入到Angular 2中。
我们可以在`main.ts`中这么做: 我们可以在`main.ts`中这么做:
+makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'routeparams', 'app/main.ts') +makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'routeparams', 'app/main.ts')
@ -1949,7 +1949,7 @@ code-example(format="").
* Just like we did in the phone list, we've replaced `ng-src` with property * Just like we did in the phone list, we've replaced `ng-src` with property
bindings for the standard `src` property. bindings for the standard `src` property.
* 正如我们在电话列表中做过的那样,我们把`ng-src`替换成了标准的`src`属性绑定。 * 正如我们在电话列表中做过的那样,我们把`ng-src`替换成了标准的`src`属性绑定。
* We're using the property binding syntax around `ng-class`. Though Angular 2 * We're using the property binding syntax around `ng-class`. Though Angular 2
@ -1977,7 +1977,7 @@ code-example(format="").
non-existing value. Unlike in Angular 1, Angular 2 expressions do not fail silently non-existing value. Unlike in Angular 1, Angular 2 expressions do not fail silently
when we try to refer to properties on undefined objects. We need to be explicit when we try to refer to properties on undefined objects. We need to be explicit
about cases where this is expected. about cases where this is expected.
* 我们把整个模板都包裹进了一个`ngIf`中,这导致只有当存在一个电话时它才会渲染。我们必须这么做, * 我们把整个模板都包裹进了一个`ngIf`中,这导致只有当存在一个电话时它才会渲染。我们必须这么做,
是因为组件首次加载时我们还没有`phone`变量,这些表达式就会引用到一个不存在的值。 是因为组件首次加载时我们还没有`phone`变量,这些表达式就会引用到一个不存在的值。
和Angular 1不同当我们尝试引用未定义对象上的属性时Angular 2中的表达式不会默默失败。 和Angular 1不同当我们尝试引用未定义对象上的属性时Angular 2中的表达式不会默默失败。
@ -1987,7 +1987,7 @@ code-example(format="").
In `main.ts` we'll now register a `phoneDetail` directive instead of a 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. The directive is a downgraded version of the `PhoneDetail` Angular 2
component. component.
在`main.ts`中,我们现在会注册一个`pcPhoneDetail`指令,而不再是组件。该指令是`PhoneDetail`组件的一个降级版。 在`main.ts`中,我们现在会注册一个`pcPhoneDetail`指令,而不再是组件。该指令是`PhoneDetail`组件的一个降级版。
+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')
@ -2070,7 +2070,7 @@ code-example(format="").
We should put this `<phonecat-app>` element in the HTML so that the root component We should put this `<phonecat-app>` element in the HTML so that the root component
has something to attach to. It replaces the old Angular 1 `ng-view` directive: has something to attach to. It replaces the old Angular 1 `ng-view` directive:
我们还要把这个`<pc-app>`元素放进HTML中以便这个根组件可以附加上去。它代替了Angular 1中原来的`ng-view`指令: 我们还要把这个`<pc-app>`元素放进HTML中以便这个根组件可以附加上去。它代替了Angular 1中原来的`ng-view`指令:
+makeExample('upgrade-phonecat-3-final/ts/index.html', 'appcomponent', 'index.html') +makeExample('upgrade-phonecat-3-final/ts/index.html', 'appcomponent', 'index.html')
@ -2091,7 +2091,7 @@ code-example(format="").
With that, we're ready to switch the bootstrap method of the application from that 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 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` with the router, the new app component, and everything else in `main.ts`
使用它,我们就可以把来自`UpgradeAdapter`中的`bootstrap`方法切换到Angular 2自己的`bootstrap`了。 使用它,我们就可以把来自`UpgradeAdapter`中的`bootstrap`方法切换到Angular 2自己的`bootstrap`了。
通过路由器和`main.ts`中新的应用组件,我们把它们导入到一起: 通过路由器和`main.ts`中新的应用组件,我们把它们导入到一起:
@ -2117,12 +2117,12 @@ code-example(format="").
We also configure a couple of things for the router here so that the application 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 URL paths match exactly those we had in the Angular 1 app: We want the
hash location strategy with the `!` prefix: `#!/phones`. hash location strategy with the `!` prefix: `#!/phones`.
这里我们还为路由器配置了一组东西以便应用的URL路径和我们在Angular 1应用中用过的完全匹配 这里我们还为路由器配置了一组东西以便应用的URL路径和我们在Angular 1应用中用过的完全匹配
我们希望hash地址策略使用`!`前缀:`#!/phones`。 我们希望hash地址策略使用`!`前缀:`#!/phones`。
At this point we are running a pure Angular 2 application! At this point we are running a pure Angular 2 application!
此时我们就在运行一个纯Angular 2应用了。 此时我们就在运行一个纯Angular 2应用了。
But there's actually one more cool thing we can do with the new router. But there's actually one more cool thing we can do with the new router.
@ -2139,14 +2139,14 @@ code-example(format="").
:marked :marked
For this to work the directive just needs to be declared in the component: 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') +makeExample('upgrade-phonecat-3-final/ts/app/phone-list/phone-list.component.ts', 'top')
:marked :marked
## Saying Goodbye to Angular 1 ## Saying Goodbye to Angular 1
## 再见Angular ## 再见Angular 1
It is time to take off the training wheels and let our application begin 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 its new life as a pure, shiny Angular 2 app. The remaining tasks all have to
@ -2157,11 +2157,11 @@ code-example(format="").
If you haven't already, remove all references to the `UpgradeAdapter` from `main.ts`. If you haven't already, remove all references to the `UpgradeAdapter` from `main.ts`.
Also remove the Angular 1 bootstrap code. Also remove the Angular 1 bootstrap code.
请从`main.ts`中移除所有到`UpgradeAdapter`的引用并移除Angular 1的引导代码。 请从`main.ts`中移除所有到`UpgradeAdapter`的引用并移除Angular 1的引导代码。
When you're done, this is what `main.ts` should look like: When you're done, this is what `main.ts` should look like:
都完成了之后,`main.ts`看起来应该像这样: 都完成了之后,`main.ts`看起来应该像这样:
+makeExample('upgrade-phonecat-3-final/ts/app/main.ts', null, 'app/main.ts') +makeExample('upgrade-phonecat-3-final/ts/app/main.ts', null, 'app/main.ts')
@ -2169,7 +2169,7 @@ code-example(format="").
:marked :marked
You may also completely remove the following files. They are Angular 1 You may also completely remove the following files. They are Angular 1
module configuration files and not needed in Angular 2: module configuration files and not needed in Angular 2:
我们还要完全移除了下列文件。它们是Angular 1的模块配置文件和类型定义文件在Angular 2中不需要了 我们还要完全移除了下列文件。它们是Angular 1的模块配置文件和类型定义文件在Angular 2中不需要了
* `app/app.module.ts` * `app/app.module.ts`
@ -2196,7 +2196,7 @@ code-example(format="").
Finally, from `index.html`, remove all references to Finally, from `index.html`, remove all references to
Angular 1 scripts, the Angular 2 upgrade module, and jQuery. When we're done, Angular 1 scripts, the Angular 2 upgrade module, and jQuery. When we're done,
this is what it should look like: this is what it should look like:
最后,从`index.html`和`karma.conf.js`中移除所有到Angular 1脚本的引用比如jQuery。 最后,从`index.html`和`karma.conf.js`中移除所有到Angular 1脚本的引用比如jQuery。
当这些全部做完时,`index.html`看起来应该是这样的: 当这些全部做完时,`index.html`看起来应该是这样的:
@ -2211,14 +2211,18 @@ code-example(format="").
.l-main-section .l-main-section
:marked :marked
# Appendix: Upgrading PhoneCat Tests # Appendix: Upgrading PhoneCat Tests
# 附录升级PhoneCat的测试 # 附录升级PhoneCat的测试
Tests can not only be retained through an upgrade process, but they can also be Tests can not only be retained through an upgrade process, but they can also be
used as a valuable safety measure when ensuring that the application does not used as a valuable safety measure when ensuring that the application does not
break during the upgrade. E2E tests are especially useful for this purpose. break during the upgrade. E2E tests are especially useful for this purpose.
测试不仅要在升级过程中被保留,它还是确保应用在升级过程中不会被破坏的一个安全指示器。
要达到这个目的E2E测试尤其有用。
## E2E Tests ## E2E Tests
## E2E测试
The PhoneCat project has both E2E Protractor tests and some Karma unit tests in it. The PhoneCat project has both E2E Protractor tests and some Karma unit tests in it.
Of these two, E2E tests can be dealt with much more easily: By definition, Of these two, E2E tests can be dealt with much more easily: By definition,
@ -2229,17 +2233,32 @@ code-example(format="").
test suite should keep passing with just minor modifications. This is because test suite should keep passing with just minor modifications. This is because
we don't change how the application behaves from the user's point of view. we don't change how the application behaves from the user's point of view.
PhoneCat项目中同时有基于Protractor的E2E测试和一些基于Karma的单元测试。
对这两者来说E2E测试的转换要容易得多根据定义E2E测试通过与应用中显示的这些UI元素互动从*外部*访问我们的应用来进行测试。
E2E测试实际上并不关心这些应用中各部件的内部结构。这也意味着虽然我们已经修改了一点儿此应用程序
但是E2E测试套件仍然应该能像以前一样全部通过。因为从用户的角度来说我们并没有改变应用的行为。
During TypeScript conversion, there is nothing we have to do to keep E2E tests During TypeScript conversion, there is nothing we have to do to keep E2E tests
working. It is only when we start to upgrade components and their template to Angular 2 working. It is only when we start to upgrade components and their template to Angular 2
that we need to make some changes. This is because the E2E tests have matchers that we need to make some changes. This is because the E2E tests have matchers
that are specific to Angular 1. For PhoneCat we need to make the following changes that are specific to Angular 1. For PhoneCat we need to make the following changes
in order to make things work with Angular 2: in order to make things work with Angular 2:
在转成TypeScript期间我们不用做什么就能让E2E测试正常工作。
只有当我们想做些修改而把组件及其模板升级到Angular 2时才需要做些处理。
这是因为E2E测试有一些匹配器是Angular 1中特有的。对于PhoneCat来说为了让它能在Angular 2下工作我们得做下列修改
table table
tr tr
th Previous code th
th New code p Previous code
th Notes p 老代码
th
p New code
p 新代码
th
p Notes
p 说明
tr tr
td td
:marked :marked
@ -2250,6 +2269,8 @@ table
td td
:marked :marked
The repeater matcher relies on Angular 1 `ng-repeat` The repeater matcher relies on Angular 1 `ng-repeat`
repeater匹配器依赖于Angular 1中的`ng-repeat`
tr tr
td td
:marked :marked
@ -2260,6 +2281,8 @@ table
td td
:marked :marked
The repeater matcher relies on Angular 1 `ng-repeat` The repeater matcher relies on Angular 1 `ng-repeat`
repeater匹配器依赖于Angular 1中的`ng-repeat`
tr tr
td td
:marked :marked
@ -2270,6 +2293,8 @@ table
td td
:marked :marked
The model matcher relies on Angular 1 `ng-model` The model matcher relies on Angular 1 `ng-model`
model匹配器依赖于Angular 1中的`ng-model`
tr tr
td td
:marked :marked
@ -2280,6 +2305,8 @@ table
td td
:marked :marked
The model matcher relies on Angular 1 `ng-model` The model matcher relies on Angular 1 `ng-model`
model匹配器依赖于Angular 1中的`ng-model`
tr tr
td td
:marked :marked
@ -2291,6 +2318,7 @@ table
:marked :marked
The binding matcher relies on Angular 1 data binding The binding matcher relies on Angular 1 data binding
binding匹配器依赖于Angular 1的数据绑定
:marked :marked
When the bootstrap method is switched from that of `UpgradeAdapter` to When the bootstrap method is switched from that of `UpgradeAdapter` to
@ -2299,6 +2327,10 @@ table
an Angular 1 app anymore, but instead it should find *Angular 2 apps* from an Angular 1 app anymore, but instead it should find *Angular 2 apps* from
the page. The following change is then needed in `protractor-conf.js`: the page. The following change is then needed in `protractor-conf.js`:
当引导方式从`UpgradeAdapter`切换到纯Angular 2的时Angular 1就从页面中完全消失了。
此时我们需要告诉Protractor它不用再找Angular 1应用了而是从页面中查找*Angular 2*应用。
于是在`protractor-conf.js`中做下列修改:
code-example(format=""). code-example(format="").
useAllAngular2AppRoots: true, useAllAngular2AppRoots: true,
@ -2309,11 +2341,16 @@ code-example(format="").
that use WebDriver's generic URL APIs instead. The first of these is that use WebDriver's generic URL APIs instead. The first of these is
the redirection spec: the redirection spec:
同样我们的测试代码中有两个Protractor API调用内部使用了`$location`。该服务没有了,
我们就得把这些调用用一个WebDriver的通用URL API代替。第一个API是“重定向(redirect)”规约:
+makeExample('upgrade-phonecat-3-final/e2e-spec.js', 'redirect', 'e2e-tests/scenarios.js') +makeExample('upgrade-phonecat-3-final/e2e-spec.js', 'redirect', 'e2e-tests/scenarios.js')
:marked :marked
And the second is the phone links spec: And the second is the phone links spec:
第二个是“电话链接(phone links)”规约:
+makeExample('upgrade-phonecat-3-final/e2e-spec.js', 'links', 'e2e-tests/scenarios.js') +makeExample('upgrade-phonecat-3-final/e2e-spec.js', 'links', 'e2e-tests/scenarios.js')
@ -2321,17 +2358,27 @@ code-example(format="").
:marked :marked
## Unit Tests ## Unit Tests
## 单元测试
For unit tests, on the other hand, more conversion work is needed. Effectively For unit tests, on the other hand, more conversion work is needed. Effectively
they need to be *upgraded* along with the production code. they need to be *upgraded* along with the production code.
另一方面,对于单元测试来说,需要更多的转化工作。实际上,它们需要随着产品代码一起升级。
During TypeScript conversion no changes are strictly necessary. But it may be During TypeScript conversion no changes are strictly necessary. But it may be
a good idea to convert the unit test code into TypeScript as well, as the same a good idea to convert the unit test code into TypeScript as well, as the same
benefits we from TypeScript in production code also applies to tests. benefits we from TypeScript in production code also applies to tests.
在转成TypeScript期间严格来讲没有什么改动是必须的。但把单元测试代码转成TypeScript仍然是个好主意
产品代码从TypeScript中获得的那些增益也同样适用于测试代码。
For instance, in the phone detail component spec we can use not only ES2015 For instance, in the phone detail component spec we can use not only ES2015
features like arrow functions and block-scoped variables, but also type features like arrow functions and block-scoped variables, but also type
definitions for some of the Angular 1 services we're consuming: definitions for some of the Angular 1 services we're consuming:
比如在这个电话详情组件的规约中我们不仅用到了ES2015中的箭头函数和块作用域变量这些特性还为所用的一些
Angular 1服务提供了类型定义。
+makeExample('upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.component.spec.ts', null, 'app/phone-detail/phone-detail.component.spec.ts') +makeExample('upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.component.spec.ts', null, 'app/phone-detail/phone-detail.component.spec.ts')
:marked :marked
@ -2339,15 +2386,22 @@ code-example(format="").
are needed for Karma. We need to let SystemJS load all the new Angular 2 code, are needed for Karma. We need to let SystemJS load all the new Angular 2 code,
which can be done with the following kind of shim file: which can be done with the following kind of shim file:
一旦我们开始了升级过程并引入了SystemJS还需要对Karma进行配置修改。
我们需要让SystemJS加载所有的Angular 2新代码
+makeExample('upgrade-phonecat-2-hybrid/ts/karma-test-shim.1.js', null, 'karma-test-shim.js') +makeExample('upgrade-phonecat-2-hybrid/ts/karma-test-shim.1.js', null, 'karma-test-shim.js')
:marked :marked
The shim first loads the SystemJS configuration, then Angular 2's test support libraries, The shim first loads the SystemJS configuration, then Angular 2's test support libraries,
and then the application's spec files themselves. and then the application's spec files themselves.
这个shim文件首先加载了SystemJS的配置然后是Angular 2的测试支持库然后是应用本身的规约文件。
Karma configuration should then be changed so that it uses the application root dir Karma configuration should then be changed so that it uses the application root dir
as the base directory, instead of `app`. as the base directory, instead of `app`.
然后需要修改Karma配置来让它使用本应用的根目录作为基础目录(base directory),而不是`app`。
+makeExample('upgrade-phonecat-2-hybrid/ts/karma.conf.ng1.js', 'basepath', 'karma.conf.js') +makeExample('upgrade-phonecat-2-hybrid/ts/karma.conf.ng1.js', 'basepath', 'karma.conf.js')
:marked :marked
@ -2355,12 +2409,17 @@ code-example(format="").
for loading application files so that they are *not* included to the page by Karma. We'll let for loading application files so that they are *not* included to the page by Karma. We'll let
the shim and SystemJS load them. the shim and SystemJS load them.
一旦这些完成了我们就能加载SystemJS和其它依赖并切换配置文件来加载那些应用文件而*不用*在Karma页面中包含它们。
我们要让这个shim文件和SystemJS去加载它们。
+makeExample('upgrade-phonecat-2-hybrid/ts/karma.conf.ng1.js', 'files', 'karma.conf.js') +makeExample('upgrade-phonecat-2-hybrid/ts/karma.conf.ng1.js', 'files', 'karma.conf.js')
:marked :marked
Since the HTML templates of Angular 2 components will be loaded as well, we need to help Since the HTML templates of Angular 2 components will be loaded as well, we need to help
Karma out a bit so that it can route them to the right paths: Karma out a bit so that it can route them to the right paths:
由于Angular 2组件中的HTML模板也同样要被加载所以我们得帮Karma一把帮它在正确的路径下找到这些模板
+makeExample('upgrade-phonecat-2-hybrid/ts/karma.conf.ng1.js', 'html', 'karma.conf.js') +makeExample('upgrade-phonecat-2-hybrid/ts/karma.conf.ng1.js', 'html', 'karma.conf.js')
:marked :marked
@ -2368,18 +2427,24 @@ code-example(format="").
counterparts are switched. The specs for the checkmark pipe are probably the most straightforward, counterparts are switched. The specs for the checkmark pipe are probably the most straightforward,
as the pipe has no dependencies: as the pipe has no dependencies:
如果产品代码被切换到了Angular 2单元测试文件本身也需要切换过来。对勾儿(checkmark)管道的规约可能是最简单的,因为它没有任何依赖:
+makeExample('upgrade-phonecat-2-hybrid/ts/app/core/checkmark/checkmark.pipe.spec.ts', null, 'app/core/checkmark/checkmark.pipe.spec.ts') +makeExample('upgrade-phonecat-2-hybrid/ts/app/core/checkmark/checkmark.pipe.spec.ts', null, 'app/core/checkmark/checkmark.pipe.spec.ts')
:marked :marked
The unit test for the phone service is a bit more involved. We need to switch from the mocked-out The unit test for the phone service is a bit more involved. We need to switch from the mocked-out
Angular 1 `$httpBackend` to a mocked-out Angular 2 Http backend. Angular 1 `$httpBackend` to a mocked-out Angular 2 Http backend.
`Phone`服务的测试会牵扯到一点别的。我们需要把模拟版的Angular 1 `$httpBackend`服务切换到模拟板的Angular 2 Http后端。
+makeExample('upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.spec.ts', null, 'app/core/phone/phone.service.spec.ts') +makeExample('upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.spec.ts', null, 'app/core/phone/phone.service.spec.ts')
:marked :marked
For the component specs we can mock out the `Phone` service itself, and have it provide For the component specs we can mock out the `Phone` service itself, and have it provide
canned phone data. We use Angular's component unit testing APIs for both components. canned phone data. We use Angular's component unit testing APIs for both components.
对于组件的规约,我们可以模拟出`Phone`服务本身并且让它提供电话的数据。我们可以对这些组件使用Angular的组件单元测试API。
+makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.spec.ts', null, 'app/phone-detail/phone-detail.component.spec.ts') +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.spec.ts', null, 'app/phone-detail/phone-detail.component.spec.ts')
+makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.spec.ts', null, 'app/phone-list/phone-list.component.spec.ts') +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.spec.ts', null, 'app/phone-list/phone-list.component.spec.ts')
@ -2390,10 +2455,15 @@ code-example(format="").
router. For the details component we need to provide an Angular 2 `RouteParams` object router. For the details component we need to provide an Angular 2 `RouteParams` object
instead of using the Angular 1 `$routeParams`. instead of using the Angular 1 `$routeParams`.
最后当我们切换到Angular 2路由时我们需要重新过一遍这些组件测试。对详情组件来说我们需要提供一个Angular 2的
`RouteParams`对象而不再用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', 'routeparams', 'app/phone-detail/phone-detail.component.spec.ts')
:marked :marked
And for the phone list component we need to set up a few things for the router itself so that And for the phone list component we need to set up a few things for the router itself so that
the route link directive will work. the route link directive will work.
对于电话列表组件来说,我们需要为路由器本身略作设置,以便它的路由链接(`routerLink`)指令能够正常工作。
+makeExample('upgrade-phonecat-3-final/ts/app/phone-list/phone-list.component.spec.ts', 'routestuff', 'app/phone-list/phone-list.component.spec.ts') +makeExample('upgrade-phonecat-3-final/ts/app/phone-list/phone-list.component.spec.ts', 'routestuff', 'app/phone-list/phone-list.component.spec.ts')

View File

@ -11,7 +11,7 @@ include ../_util-fns
It's an excellent alternative to the *SystemJS* approach we use throughout the documentation. It's an excellent alternative to the *SystemJS* approach we use throughout the documentation.
In this guide we get a taste of Webpack and how to use it with Angular 2 applications. In this guide we get a taste of Webpack and how to use it with Angular 2 applications.
这是我们在文档中到处使用的这个*SystemJS*的一个卓越替代品。这篇指南会带我们尝尝Webpack的滋味并学习如何在Angular 2程序中使用它。 这是我们在文档中到处使用的这个*SystemJS*的一个优秀替代品。这篇指南会带我们尝尝Webpack的滋味并学习如何在Angular 2程序中使用它。
<a id="top"></a> <a id="top"></a>
## Table of contents ## Table of contents

View File

@ -34,7 +34,7 @@
1. Jasmine Testing 101 1. Jasmine Testing 101
1. Jasmine测试101 1. Jasmine测试简介
- setup to run Jasmine tests in the browser - setup to run Jasmine tests in the browser

View File

@ -337,7 +337,7 @@ figure.image-display
Congratulations … youve completed Jasmine testing 101. Congratulations … youve completed Jasmine testing 101.
恭喜...你完成了Jasmine测试101 恭喜...你完成了Jasmine测试简介
Now that were familiar with Jasmine on its own, were ready to test an application. Now that were familiar with Jasmine on its own, were ready to test an application.

View File

@ -8,7 +8,6 @@
box-shadow: 3px 0px 6px rgba($coal, .3); box-shadow: 3px 0px 6px rgba($coal, .3);
width: 232px; width: 232px;
bottom: 0px; bottom: 0px;
height: calc(100vh - 56px);
overflow: auto; overflow: auto;
@media handheld and (max-width: $phone-breakpoint), @media handheld and (max-width: $phone-breakpoint),
@ -149,7 +148,10 @@
screen and (max-device-width: $phone-breakpoint), screen and (max-device-width: $phone-breakpoint),
screen and (max-width: $tablet-breakpoint) { screen and (max-width: $tablet-breakpoint) {
display: none; display: none;
//max-height: ($phone-breakpoint * 0.60); &.is-visible {
height: calc(100vh - 56px - 48px);
overflow: auto;
}
} }
// FLAT NAV (.nav) // FLAT NAV (.nav)