|
|
|
@@ -226,7 +226,7 @@ include ../_util-fns
|
|
|
|
|
* JavaScript features new to ES2015, like arrow functions, `let`s and `const`s,
|
|
|
|
|
default function parameters, and destructuring assignments can also be gradually
|
|
|
|
|
added to make the code more expressive.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* 那些ES2015中新增的特性,比如箭头函数、`let`、`const`、默认函数参数、解构赋值等也能逐渐添加进来,让代码更有表现力。
|
|
|
|
|
|
|
|
|
|
* 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
|
|
|
|
|
exact [equivalents in Angular 2](lifecycle-hooks.html), so organizing component lifecycle
|
|
|
|
|
logic around them will ease the eventual Angular 2 upgrade process.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
控制器的生命周期钩子`$onInit()`、`$onDestroy()`和`$onChanges()`是Angular 1.5引入的另一些便利特性。
|
|
|
|
|
它们都很接近于[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
|
|
|
|
|
attribute syntax to bind the inputs and outputs**. This is a requirement for downgraded
|
|
|
|
|
components. The expressions themselves are still regular Angular 1 expressions.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
注意,虽然我们正在Angular 1的模板中,**但却在使用Angular 2的属性(Attribute)语法来绑定到输入属性与输出属性**。
|
|
|
|
|
这是降级的组件本身要求的。而表达式本身仍然是标准的Angular 1表达式。
|
|
|
|
|
|
|
|
|
@@ -809,16 +809,16 @@ figure
|
|
|
|
|
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
|
|
|
|
|
of multiple words. In Angular 2 we would bind these attributes using camelCase:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
为降级过的组件使用Angualr 2的属性(Attribute)语法规则时有一个值得注意的例外。
|
|
|
|
|
它适用于由多个单词组成的输入或输出属性。在Angular 2中,我们要使用小驼峰命名法绑定这些属性:
|
|
|
|
|
code-example(format="").
|
|
|
|
|
[myHero]="hero"
|
|
|
|
|
:marked
|
|
|
|
|
But when using them from Angular 1 templates, we need to use kebab-case:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
但是从Angular 1的模板中使用它们时,我们得使用中线命名法:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
code-example(format="").
|
|
|
|
|
[my-hero]="hero"
|
|
|
|
|
|
|
|
|
@@ -1147,7 +1147,7 @@ figure
|
|
|
|
|
.l-main-section
|
|
|
|
|
:marked
|
|
|
|
|
# PhoneCat Upgrade Tutorial
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# PhoneCat升级教程
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
[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)所要求的。
|
|
|
|
|
|
|
|
|
|
* 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
|
|
|
|
|
found, as described in the rules for
|
|
|
|
|
[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)中要求的那样。
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
## Switching to TypeScript
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 切换到TypeScript
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
the project HTTP server with `npm start`, you should see the fully functional
|
|
|
|
|
application in your browser.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
我们要做的下一件事是把JavaScript文件转换成TypeScript文件。
|
|
|
|
|
由于TypeScript是ECMAScript 2015的一个超集,而ES2015又是ECMAScript 5的超集,所以我们可以简单的把文件的扩展名从`.js`换成`.ts`,
|
|
|
|
|
它们就还会像以前一样工作。由于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
|
|
|
|
|
features. There's a lot of value the language can provide to Angular 1 applications.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
有了TypeScript,我们就可以从它的一些特性中获益了。此语言可以为Angular 1应用提供很多价值。
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
These include things like `let`s and `const`s, arrow functions, default function
|
|
|
|
|
parameters, and destructuring assignments.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
首先,TypeScript是一个ES2015的超集。任何以前用ES5写的程序(就像PhoneCat范例)都可以开始通过TypeScript
|
|
|
|
|
纳入那些添加到ES2015中的新特性。
|
|
|
|
|
这包括`let`、`const`、箭头函数、函数默认参数以及解构(destructure)赋值。
|
|
|
|
@@ -1372,7 +1372,7 @@ code-example(format="").
|
|
|
|
|
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
|
|
|
|
|
things like register components to Angular modules.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
我们能做的另一件事就是把*类型安全*添加到代码中。这实际上已经部分完成了,因为我们已经安装了Angular 1的类型定义。
|
|
|
|
|
当我们正确调用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
|
|
|
|
|
filter so that it explicitly expects booleans as arguments. This makes it clearer
|
|
|
|
|
what the filter is supposed to do.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
我们还能开始把*类型注解*添加到自己的代码中,来从TypeScript的类型系统中获得更多帮助。
|
|
|
|
|
比如,我们可以给`checkmark`过滤器加上注解,表明它期待一个`boolean`类型的参数。
|
|
|
|
|
这可以更清楚的表明此过滤器打算做什么
|
|
|
|
@@ -1390,7 +1390,7 @@ code-example(format="").
|
|
|
|
|
:marked
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在`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')
|
|
|
|
@@ -1399,7 +1399,7 @@ code-example(format="").
|
|
|
|
|
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
|
|
|
|
|
can verify we're calling their APIs with the correct kinds of arguments.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
我们可以在应用的路由配置中使用同样的技巧,那里我们用到了location和route服务。
|
|
|
|
|
一旦给它们提供了类型信息,TypeScript就能检查我们是否在用类型正确的参数来调用它们了。
|
|
|
|
|
|
|
|
|
@@ -1411,7 +1411,7 @@ code-example(format="").
|
|
|
|
|
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
|
|
|
|
|
fully type-annotated with the help of these definitions.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
我们用typings工具安装的这个[Angular 1.x类型定义文件](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/angularjs)
|
|
|
|
|
并不是由Angular开发组维护的,但它也已经足够全面了。借助这些类型定义的帮助,它可以为Angular 1.x程序加上全面的类型注解。
|
|
|
|
|
|
|
|
|
@@ -1442,7 +1442,7 @@ code-example(format="").
|
|
|
|
|
这也就意味着只要我们把一个类注册为组件控制器,Angular 1就会愉快的使用它。
|
|
|
|
|
|
|
|
|
|
Here's what our new class for the phone list component controller looks like:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
新的“电话列表(phone list)”组件控制器类看起来是这样的:
|
|
|
|
|
|
|
|
|
|
+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
|
|
|
|
|
referred to in the template, but for the sake of clarity we want to define all the
|
|
|
|
|
members our controller will have.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
该类额外声明了三个成员:电话列表、当前排序键的名字,以及搜索条件。
|
|
|
|
|
这些东西我们以前就加到了控制器上,只是从来没有在任何地方显式定义过它们。最后一个成员从未真正在TypeScript代码中用过,
|
|
|
|
|
因为它只是在模板中被引用过。但为了清晰起见,我们还是该定义出此控制器应有的所有成员。
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在电话详情控制器中,我们有两个成员:一个是用户正在查看的电话,另一个是正在显示的图像:
|
|
|
|
|
|
|
|
|
|
+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安装到项目中。
|
|
|
|
|
看看[“快速起步”](../quickstart.html)中的指南,并从那里获得如下配置:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Add Angular 2 and the other new dependencies to `package.json`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* 把添加Angular 2和其它新依赖添加到`package.json`中
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Add the new typings into `typings.json`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* 把这些新的类型定义添加到`typings.json`中
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* The SystemJS configuration file `systemjs.config.js` to the project root directory.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* 把SystemJS的配置文件`systemjs.config.js`添加到项目的根目录。
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
我们可以通过`index.html`来把Angular 2的依赖快速加载到应用中,
|
|
|
|
|
但首先,我们得做一些目录结构调整。这是因为我们正准备从`node_modules`中加载文件,然而目前项目中的每一个文件都是从`/app`目录下加载的。
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
instead of `app`:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
把`app/index.html`移入项目的根目录,然后把`package.json`中的开发服务器根目录也指向项目的根目录,而不再是`app`目录:
|
|
|
|
|
|
|
|
|
|
+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
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
现在,我们能把项目根目录下的每一样东西发给浏览器了。但我们并不想修改在应用代码中用到的每一个图片和数据的路径,
|
|
|
|
|
以适应我们开发环境中的设置。因此,我们往`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
|
|
|
|
|
SystemJS config to the end of the `<head>` section, and then we'll use `System.import`
|
|
|
|
|
to load the actual application:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
现在我们可以通过SystemJS加载Angular 2了。我们将把Angular 2的填充库(polyfills)
|
|
|
|
|
和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
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在我们从“快速起步”中拿来的`systemjs.config.js`文件中,我们还需要做一些调整,以适应我们的项目结构。
|
|
|
|
|
在使用SystemJS而不是`<base>` URL加载时,我们需要把浏览器指向项目的根目录。
|
|
|
|
|
|
|
|
|
@@ -1588,7 +1588,7 @@ code-example(format="").
|
|
|
|
|
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
|
|
|
|
|
we can start converting the individual pieces to Angular 2.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
我们后面将做的就是把该应用程序引导为一个同时支持Angular 1和Angular 2的*混合式应用*。
|
|
|
|
|
一旦我们做完了,就能开始把这些不可分割的小块儿转换到Angular 2了.
|
|
|
|
|
|
|
|
|
@@ -1597,7 +1597,7 @@ code-example(format="").
|
|
|
|
|
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
|
|
|
|
|
in `systemjs.config.js`, so it is already being loaded by the browser.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
要引导一个混合式应用,我们首先得初始化一个`UpgradeAdapter`,它[提供了胶水](#upgrading-with-the-upgrade-adapter)
|
|
|
|
|
来把框架的两个不同版本粘在一起。我们在一个新文件`app/main.ts`中导入`UpgradeAdapter`类。
|
|
|
|
|
这个文件已经在`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
|
|
|
|
|
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`:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
我们的应用现在是使用宿主页面中附加到`<html>`元素上的`ng-app`指令引导的。
|
|
|
|
|
但在Angular 2中,它不再工作了。我们得切换成JavaScript驱动的引导方式。
|
|
|
|
|
所以,从`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
|
|
|
|
|
an `UpgradeAdapter`, we're actually now running the app as a hybrid Angular 1+2
|
|
|
|
|
app.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
这里使用的参数是应用的根元素(也就是以前我们放`ng-app`的元素),和我们准备加载的Angular 1.x模块。
|
|
|
|
|
由于我们是通过`UpgradeAdapter`引导应用的,所以实际在运行的应用实际上是一个Angular 1+2的混合体。
|
|
|
|
|
|
|
|
|
@@ -1753,7 +1753,7 @@ code-example(format="").
|
|
|
|
|
`UpgradeAdapter` has a `downgradeNg2Provider` method for the purpose of making
|
|
|
|
|
Angular 2 services available to Angular 1 code. We can use it to plug in our
|
|
|
|
|
`Phone` service:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
`UpgradeAdapter`有个`downgradeNg2Provider`方法就是用来让Angular 2的服务在Angular 1的代码中可用的。
|
|
|
|
|
我们可以使用它来插入我们的`Phone`服务:
|
|
|
|
|
|
|
|
|
@@ -1766,19 +1766,19 @@ code-example(format="").
|
|
|
|
|
|
|
|
|
|
1. Register `Phone` as an **Angular 2 provider** with the `addProvider`
|
|
|
|
|
method. That's the same method that we used earlier for `HTTP_PROVIDERS`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1. 用`addProvider`方法注册了一个名叫`Phone`的**Angular 2供应商**。这和我们以前使用`HTTP_PROVIDERS`的方法一样。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2. Register an **Angular 1 factory** called `phone`, which will be a *downgraded*
|
|
|
|
|
version of the `Phone` Angular 2 service.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2. 注册了一个名叫`phone`的**Angular 1工厂**,它是一个`Phones`服务的*降级*版。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Now that we are loading `phone.service.ts` through an import that is resolved
|
|
|
|
|
by SystemJS, we should **remove the `<script>` tag** for the service from `index.html`.
|
|
|
|
|
This is something we'll do to all our components as we upgrade them. Simultaneously
|
|
|
|
|
with the Angular 1 to 2 upgrade we're also migrating our code from scripts to modules.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
现在,我们正在用SystemJS加载`phone.service.ts`,我们应该从`index.html`中**移除该服务的`<script>`标签**。
|
|
|
|
|
这也是我们在升级所有组件时将会做的事。在从Angular 1向2升级的同时,我们也把代码从脚本移植为模块。
|
|
|
|
|
|
|
|
|
@@ -1786,7 +1786,7 @@ code-example(format="").
|
|
|
|
|
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
|
|
|
|
|
accordingly:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
这时,我们可以把两个控制器从使用老的服务切换成使用新的。我们像降级过的`phones`工厂一样`$inject`它,
|
|
|
|
|
但它实际上是一个`Phones`类的实例,并且我们可以据此注解它的类型:
|
|
|
|
|
|
|
|
|
@@ -1810,28 +1810,28 @@ code-example(format="").
|
|
|
|
|
We could also use the `toPromise` method of `Observable` to turn those
|
|
|
|
|
Observables into Promises in the service. This can in many cases further
|
|
|
|
|
reduce the amount of changes needed in the component controllers.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
我们也能使用`Observable`的`toPromise`方法来在服务中把这些可观察对象转变成承诺,以进一步减小组件控制器中需要修改的代码量。
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
## Upgrading Components
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 升级组件
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
As we make these conversions, we'll also be defining our first Angular 2 *pipes*.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
接下来,我们把Angular 1的控制器升级成Angular 2的组件。我们每次升级一个,同时仍然保持应用运行在混合模式下。
|
|
|
|
|
在做转换的同时,我们还将自定义首个Angular 2*管道*。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
an Angular 2 component by just renaming the controller class and turning the
|
|
|
|
|
Angular 1 component definition object into an Angular 2 `@Component` decorator.
|
|
|
|
|
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')
|
|
|
|
|
|
|
|
|
|
: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
|
|
|
|
|
have these explicit selectors. This one will match elements with the name `phone-list`,
|
|
|
|
|
just like the Angular 1 version did.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
We now also need to convert the template of this component into Angular 2 syntax.
|
|
|
|
|
In the search controls we need to use Angular 2 syntax for the two `ngModel`s.
|
|
|
|
|
We should also no longer use the `$ctrl` prefix in expressions:
|
|
|
|
@@ -1851,7 +1851,7 @@ code-example(format="").
|
|
|
|
|
`let var of iterable` syntax, which is [described in our
|
|
|
|
|
Template Syntax guide](../guide/template-syntax.html#directives).
|
|
|
|
|
For the images, we can replace `ng-src` with a binding to the standard `src` property.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在列表中,我们需要把`ng-repeat`替换为`*ngFor`以及它的`let var of iterable`语法,
|
|
|
|
|
该语法在[模板语法指南中讲过](../guide/template-syntax.html#directives)。
|
|
|
|
|
对于图片,我们可以把`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
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
我们在这里做的另一件事就是移除了`filter`和`orderBy`过滤器的使用,并把它们换成对控制器中`getPhones()`方法的调用。
|
|
|
|
|
内建的`filter`和`orderBy`在Angular 2中已经不存在了,所以我们得自己进行过滤和排序。
|
|
|
|
|
我们可以为此定义自己的Angular 2管道,但是在这个案例中,在组件本身实现过滤和排序逻辑反倒更方便。
|
|
|
|
@@ -1894,12 +1894,12 @@ code-example(format="").
|
|
|
|
|
降级方法(`downgradeNg2Component`)的返回值能作为指令工厂使用。
|
|
|
|
|
|
|
|
|
|
At this point, also remove the `<script>` tag for the phone list component from `index.html`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
这时,也从`index.html`中移除电话列表组件的`<script>`标签。
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
现在我们可以开始看看另一个组件,那就是电话详情。把`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
|
|
|
|
|
`$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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
这和我们对电话列表所做的很相似。这里的一个新的更改是使用`@Inject`来获取`$routeParams`依赖。
|
|
|
|
|
它告诉Angular 2的注入器这个依赖该被映射成什么。我们在Angular 1的注入器中有一个名叫`$routeParams`的依赖,
|
|
|
|
|
它是由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
|
|
|
|
|
tell the `UpgradeAdapter` to upgrade `$routeParams` so that it is available for injection in
|
|
|
|
|
Angular 2. We can do it in `main.ts`:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
问题是,Angular 1的依赖不会自动对Angular 2的组件可用,所以如果我们现在运行它,它将无法工作。
|
|
|
|
|
我们得显式的告诉`UpgradeAdapter`去升级`$routeParams`,以便它能被注入到Angular 2中。
|
|
|
|
|
我们可以在`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
|
|
|
|
|
bindings for the standard `src` property.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* 正如我们在电话列表中做过的那样,我们把`ng-src`替换成了标准的`src`属性绑定。
|
|
|
|
|
|
|
|
|
|
* 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
|
|
|
|
|
when we try to refer to properties on undefined objects. We need to be explicit
|
|
|
|
|
about cases where this is expected.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* 我们把整个模板都包裹进了一个`ngIf`中,这导致只有当存在一个电话时它才会渲染。我们必须这么做,
|
|
|
|
|
是因为组件首次加载时我们还没有`phone`变量,这些表达式就会引用到一个不存在的值。
|
|
|
|
|
和Angular 1不同,当我们尝试引用未定义对象上的属性时,Angular 2中的表达式不会默默失败。
|
|
|
|
@@ -1987,7 +1987,7 @@ code-example(format="").
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在`main.ts`中,我们现在会注册一个`pcPhoneDetail`指令,而不再是组件。该指令是`PhoneDetail`组件的一个降级版。
|
|
|
|
|
|
|
|
|
|
+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
|
|
|
|
|
has something to attach to. It replaces the old Angular 1 `ng-view` directive:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
我们还要把这个`<pc-app>`元素放进HTML中,以便这个根组件可以附加上去。它代替了Angular 1中原来的`ng-view`指令:
|
|
|
|
|
|
|
|
|
|
+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
|
|
|
|
|
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`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
使用它,我们就可以把来自`UpgradeAdapter`中的`bootstrap`方法切换到Angular 2自己的`bootstrap`了。
|
|
|
|
|
通过路由器和`main.ts`中新的应用组件,我们把它们导入到一起:
|
|
|
|
|
|
|
|
|
@@ -2117,12 +2117,12 @@ code-example(format="").
|
|
|
|
|
We also configure a couple of things for the router here so that the application
|
|
|
|
|
URL paths match exactly those we had in the Angular 1 app: We want the
|
|
|
|
|
hash location strategy with the `!` prefix: `#!/phones`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
这里我们还为路由器配置了一组东西,以便应用的URL路径和我们在Angular 1应用中用过的完全匹配:
|
|
|
|
|
我们希望hash地址策略使用`!`前缀:`#!/phones`。
|
|
|
|
|
|
|
|
|
|
At this point we are running a pure Angular 2 application!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
此时,我们就在运行一个纯Angular 2应用了。
|
|
|
|
|
|
|
|
|
|
But there's actually one more cool thing we can do with the new router.
|
|
|
|
@@ -2139,14 +2139,14 @@ code-example(format="").
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
For this to work the directive just needs to be declared in the component:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
要让该指令能够工作,我们只需要把它在组件中声明一下:
|
|
|
|
|
|
|
|
|
|
+makeExample('upgrade-phonecat-3-final/ts/app/phone-list/phone-list.component.ts', 'top')
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
## Saying Goodbye to Angular 1
|
|
|
|
|
## 再见,Angular
|
|
|
|
|
## 再见,Angular 1
|
|
|
|
|
|
|
|
|
|
It is time to take off the training wheels and let our application begin
|
|
|
|
|
its new life as a pure, shiny Angular 2 app. The remaining tasks all have to
|
|
|
|
@@ -2157,11 +2157,11 @@ code-example(format="").
|
|
|
|
|
|
|
|
|
|
If you haven't already, remove all references to the `UpgradeAdapter` from `main.ts`.
|
|
|
|
|
Also remove the Angular 1 bootstrap code.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
请从`main.ts`中移除所有到`UpgradeAdapter`的引用,并移除Angular 1的引导代码。
|
|
|
|
|
|
|
|
|
|
When you're done, this is what `main.ts` should look like:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
都完成了之后,`main.ts`看起来应该像这样:
|
|
|
|
|
|
|
|
|
|
+makeExample('upgrade-phonecat-3-final/ts/app/main.ts', null, 'app/main.ts')
|
|
|
|
@@ -2169,7 +2169,7 @@ code-example(format="").
|
|
|
|
|
:marked
|
|
|
|
|
You may also completely remove the following files. They are Angular 1
|
|
|
|
|
module configuration files and not needed in Angular 2:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
我们还要完全移除了下列文件。它们是Angular 1的模块配置文件和类型定义文件,在Angular 2中不需要了:
|
|
|
|
|
|
|
|
|
|
* `app/app.module.ts`
|
|
|
|
@@ -2196,7 +2196,7 @@ code-example(format="").
|
|
|
|
|
Finally, from `index.html`, remove all references to
|
|
|
|
|
Angular 1 scripts, the Angular 2 upgrade module, and jQuery. When we're done,
|
|
|
|
|
this is what it should look like:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
最后,从`index.html`和`karma.conf.js`中,移除所有到Angular 1脚本的引用,比如jQuery。
|
|
|
|
|
当这些全部做完时,`index.html`看起来应该是这样的:
|
|
|
|
|
|
|
|
|
@@ -2211,14 +2211,18 @@ code-example(format="").
|
|
|
|
|
.l-main-section
|
|
|
|
|
:marked
|
|
|
|
|
# Appendix: Upgrading PhoneCat Tests
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 附录:升级PhoneCat的测试
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
break during the upgrade. E2E tests are especially useful for this purpose.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
测试不仅要在升级过程中被保留,它还是确保应用在升级过程中不会被破坏的一个安全指示器。
|
|
|
|
|
要达到这个目的,E2E测试尤其有用。
|
|
|
|
|
|
|
|
|
|
## E2E Tests
|
|
|
|
|
## E2E测试
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
@@ -2229,17 +2233,32 @@ code-example(format="").
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
PhoneCat项目中同时有基于Protractor的E2E测试和一些基于Karma的单元测试。
|
|
|
|
|
对这两者来说,E2E测试的转换要容易得多:根据定义,E2E测试通过与应用中显示的这些UI元素互动,从*外部*访问我们的应用来进行测试。
|
|
|
|
|
E2E测试实际上并不关心这些应用中各部件的内部结构。这也意味着,虽然我们已经修改了一点儿此应用程序,
|
|
|
|
|
但是E2E测试套件仍然应该能像以前一样全部通过。因为从用户的角度来说,我们并没有改变应用的行为。
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
|
in order to make things work with Angular 2:
|
|
|
|
|
|
|
|
|
|
在转成TypeScript期间,我们不用做什么就能让E2E测试正常工作。
|
|
|
|
|
只有当我们想做些修改而把组件及其模板升级到Angular 2时才需要做些处理。
|
|
|
|
|
这是因为E2E测试有一些匹配器是Angular 1中特有的。对于PhoneCat来说,为了让它能在Angular 2下工作,我们得做下列修改:
|
|
|
|
|
|
|
|
|
|
table
|
|
|
|
|
tr
|
|
|
|
|
th Previous code
|
|
|
|
|
th New code
|
|
|
|
|
th Notes
|
|
|
|
|
th
|
|
|
|
|
p Previous code
|
|
|
|
|
p 老代码
|
|
|
|
|
th
|
|
|
|
|
p New code
|
|
|
|
|
p 新代码
|
|
|
|
|
th
|
|
|
|
|
p Notes
|
|
|
|
|
p 说明
|
|
|
|
|
tr
|
|
|
|
|
td
|
|
|
|
|
:marked
|
|
|
|
@@ -2250,6 +2269,8 @@ table
|
|
|
|
|
td
|
|
|
|
|
:marked
|
|
|
|
|
The repeater matcher relies on Angular 1 `ng-repeat`
|
|
|
|
|
|
|
|
|
|
repeater匹配器依赖于Angular 1中的`ng-repeat`
|
|
|
|
|
tr
|
|
|
|
|
td
|
|
|
|
|
:marked
|
|
|
|
@@ -2260,6 +2281,8 @@ table
|
|
|
|
|
td
|
|
|
|
|
:marked
|
|
|
|
|
The repeater matcher relies on Angular 1 `ng-repeat`
|
|
|
|
|
|
|
|
|
|
repeater匹配器依赖于Angular 1中的`ng-repeat`
|
|
|
|
|
tr
|
|
|
|
|
td
|
|
|
|
|
:marked
|
|
|
|
@@ -2270,6 +2293,8 @@ table
|
|
|
|
|
td
|
|
|
|
|
:marked
|
|
|
|
|
The model matcher relies on Angular 1 `ng-model`
|
|
|
|
|
|
|
|
|
|
model匹配器依赖于Angular 1中的`ng-model`
|
|
|
|
|
tr
|
|
|
|
|
td
|
|
|
|
|
:marked
|
|
|
|
@@ -2280,6 +2305,8 @@ table
|
|
|
|
|
td
|
|
|
|
|
:marked
|
|
|
|
|
The model matcher relies on Angular 1 `ng-model`
|
|
|
|
|
|
|
|
|
|
model匹配器依赖于Angular 1中的`ng-model`
|
|
|
|
|
tr
|
|
|
|
|
td
|
|
|
|
|
:marked
|
|
|
|
@@ -2291,6 +2318,7 @@ table
|
|
|
|
|
:marked
|
|
|
|
|
The binding matcher relies on Angular 1 data binding
|
|
|
|
|
|
|
|
|
|
binding匹配器依赖于Angular 1的数据绑定
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
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
|
|
|
|
|
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="").
|
|
|
|
|
useAllAngular2AppRoots: true,
|
|
|
|
|
|
|
|
|
@@ -2309,11 +2341,16 @@ code-example(format="").
|
|
|
|
|
that use WebDriver's generic URL APIs instead. The first of these is
|
|
|
|
|
the redirection spec:
|
|
|
|
|
|
|
|
|
|
同样,我们的测试代码中有两个Protractor API调用内部使用了`$location`。该服务没有了,
|
|
|
|
|
我们就得把这些调用用一个WebDriver的通用URL API代替。第一个API是“重定向(redirect)”规约:
|
|
|
|
|
|
|
|
|
|
+makeExample('upgrade-phonecat-3-final/e2e-spec.js', 'redirect', 'e2e-tests/scenarios.js')
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
And the second is the phone links spec:
|
|
|
|
|
|
|
|
|
|
第二个是“电话链接(phone links)”规约:
|
|
|
|
|
|
|
|
|
|
+makeExample('upgrade-phonecat-3-final/e2e-spec.js', 'links', 'e2e-tests/scenarios.js')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2321,17 +2358,27 @@ code-example(format="").
|
|
|
|
|
:marked
|
|
|
|
|
## Unit Tests
|
|
|
|
|
|
|
|
|
|
## 单元测试
|
|
|
|
|
|
|
|
|
|
For unit tests, on the other hand, more conversion work is needed. Effectively
|
|
|
|
|
they need to be *upgraded* along with the production code.
|
|
|
|
|
|
|
|
|
|
另一方面,对于单元测试来说,需要更多的转化工作。实际上,它们需要随着产品代码一起升级。
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
|
features like arrow functions and block-scoped variables, but also type
|
|
|
|
|
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')
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
@@ -2339,15 +2386,22 @@ code-example(format="").
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
一旦我们开始了升级过程并引入了SystemJS,还需要对Karma进行配置修改。
|
|
|
|
|
我们需要让SystemJS加载所有的Angular 2新代码,
|
|
|
|
|
|
|
|
|
|
+makeExample('upgrade-phonecat-2-hybrid/ts/karma-test-shim.1.js', null, 'karma-test-shim.js')
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
The shim first loads the SystemJS configuration, then Angular 2's test support libraries,
|
|
|
|
|
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
|
|
|
|
|
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')
|
|
|
|
|
|
|
|
|
|
: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
|
|
|
|
|
the shim and SystemJS load them.
|
|
|
|
|
|
|
|
|
|
一旦这些完成了,我们就能加载SystemJS和其它依赖,并切换配置文件来加载那些应用文件,而*不用*在Karma页面中包含它们。
|
|
|
|
|
我们要让这个shim文件和SystemJS去加载它们。
|
|
|
|
|
|
|
|
|
|
+makeExample('upgrade-phonecat-2-hybrid/ts/karma.conf.ng1.js', 'files', 'karma.conf.js')
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
由于Angular 2组件中的HTML模板也同样要被加载,所以我们得帮Karma一把,帮它在正确的路径下找到这些模板:
|
|
|
|
|
|
|
|
|
|
+makeExample('upgrade-phonecat-2-hybrid/ts/karma.conf.ng1.js', 'html', 'karma.conf.js')
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
@@ -2368,18 +2427,24 @@ code-example(format="").
|
|
|
|
|
counterparts are switched. The specs for the checkmark pipe are probably the most straightforward,
|
|
|
|
|
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')
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
`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')
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
对于组件的规约,我们可以模拟出`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-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
|
|
|
|
|
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')
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
对于电话列表组件来说,我们需要为路由器本身略作设置,以便它的路由链接(`routerLink`)指令能够正常工作。
|
|
|
|
|
|
|
|
|
|
+makeExample('upgrade-phonecat-3-final/ts/app/phone-list/phone-list.component.spec.ts', 'routestuff', 'app/phone-list/phone-list.component.spec.ts')
|
|
|
|
|