fix: toh-p5 and p6.

This commit is contained in:
Zhimin YE (Rex) 2016-08-23 15:52:39 +01:00
parent b73cb2e1a1
commit e1d5af61d2
2 changed files with 262 additions and 238 deletions

View File

@ -325,7 +325,7 @@ block angular-router
和一套配置(`Routes`)。我们将先配置路由。
:marked
### Set the base tag
### Add the base tag
### 设置base标签
@ -400,12 +400,12 @@ block router-config-intro
+ifDocsFor('ts|js')
:marked
We'll export the `routing` constant using the **RouterModule.forRoot** method with our array of routes.
This returns a configured router module we'll add to our root NgModule, `AppModule`.
We'll export a `routing` constant initialized using the `RouterModule.forRoot` method applied to our !{_array} of routes.
This method returns a **configured router module** that we'll add to our root NgModule, `AppModule`.
使用**RouterModule.forRoot**方法,导出包含了路由数组的`routing`常量。它返回一个配置好的路由模块它将被加入到根NgModule - `AppModule`中。
使用`RouterModule.forRoot`方法,导出包含了路由数组的`routing`常量。它返回一个**配置好的路由模块**它将被加入到根NgModule - `AppModule`中。
+makeExcerpt('app/app.routing.1.ts (excerpt)', 'routing-export')
+makeExcerpt('app/app.routing.1.ts (excerpt)', 'routing-export')
.l-sub-section
:marked
@ -420,7 +420,7 @@ block router-config-intro
### 让路由器生效
We've setup our initial routes in our `app.routing.ts` file. Now we'll add it to our root NgModule.
We've setup initial routes in the `app.routing.ts` file. Now we'll add it to our root NgModule.
我们已经在`app.routing.ts`文件中设置好了初始路由接着把它加到根模块NgModule中。
@ -443,12 +443,12 @@ block router-config-intro
如果我们把路径`/heroes`粘贴到浏览器的地址栏,路由器会匹配到`'Heroes'`路由,并显示`HeroesComponent`组件。
但问题是,该把它显示在哪儿呢?
We have to ***tell it where*** by adding `<router-outlet>` marker tags to the bottom of the template.
`RouterOutlet` is one of the directives provided by the `RouterModule`.
We have to ***tell it where*** by adding a `<router-outlet>` element to the bottom of the template.
`RouterOutlet` is one of the <span if-docs="ts">directives provided by</span> the `!{_RouterModuleVsRouterDirectives}`.
The router displays each component immediately below the `<router-outlet>` as we navigate through the application.
我们必须***告诉它位置***,所以我们把`<router-outlet>`标签添加到模板的底部。
`RouterOutlet`是`ROUTER_DIRECTIVES`常量中的一员
`RouterOutlet`是`!{_RouterModuleVsRouterDirectives}`提供的<span if-docs="ts">指令之一</span>`
当我们在应用中导航时,路由器就把激活的组件显示在`<router-outlet>`里面。
### Router Links
@ -464,30 +464,33 @@ block router-config-intro
修改过的模板是这样的:
+makeExample('toh-5/ts/app/app.component.2.ts', 'template', 'app/app.component.ts (template v1)')(format=".")
:marked
Notice the `routerLink` binding in the anchor tag.
We bind the `RouterLink` directive (another of the `RouterModule` directives) to a string
that tells the router where to navigate when the user clicks the link.
+makeExcerpt('app/app.component.1.ts', 'template-v2')
注意a标签中的`[routerLink]`绑定。我们把`RouterLink`指令(`ROUTER_DIRECTIVES`中的另一个指令)绑定到一个数组。它将告诉路由器,当用户点击这个链接时,应该导航到哪里。
Since our link is not dynamic, we define a *routing instruction* with a **one-time binding** to our route **path**.
Looking back at the route configuration, we confirm that `'/heroes'` is the path of the route to the `HeroesComponent`.
由于这个链接不是动态的,我们只要用**一次性绑定**的方式绑定到路由的路径path就行了。
回来看路由配置表,我们清楚的看到,这个路径 —— `'/heroes'`就是指向`HeroesComponent`的那个路由的路径。
.l-sub-section
block routerLink
:marked
For more dynamic router links, learn about the *link parameters array* in the [Routing](../guide/router.html#link-parameters-array) chapter.
Notice the `routerLink` binding in the anchor tag.
We bind the `RouterLink` directive (another of the `RouterModule` directives) to a string
that tells the router where to navigate when the user clicks the link.
注意a标签中的`[routerLink]`绑定。我们把`RouterLink`指令(`ROUTER_DIRECTIVES`中的另一个指令)绑定到一个数组。它将告诉路由器,当用户点击这个链接时,应该导航到哪里。
Since our link is not dynamic, we define a *routing instruction* with a **one-time binding** to our route **path**.
Looking back at the route configuration, we confirm that `'/heroes'` is the path of the route to the `HeroesComponent`.
由于这个链接不是动态的,我们只要用**一次性绑定**的方式绑定到路由的路径path就行了。
回来看路由配置表,我们清楚的看到,这个路径 —— `'/heroes'`就是指向`HeroesComponent`的那个路由的路径。
如果要用动态路由器链接,参阅[路由](../guide/router.html#link-parameters-array)中的*链接参数数组*一节。
.l-sub-section
:marked
Learn more about dynamic router links and the *link parameters array*
in the [Routing](../guide/router.html#link-parameters-array) chapter.
参阅[路由](../guide/router.html#link-parameters-array)章学习更多动态路由器链接和*链接参数数组*的知识。
:marked
Refresh the browser. We see only the app title. We don't see the heroes list.
Refresh the browser. We see only the app title and heroes link. We don't see the heroes list.
刷新浏览器。我们只看到了应用标题。英雄列表到哪里去了?
刷新浏览器。我们只看到了应用标题和英雄链接。英雄列表到哪里去了?
.l-sub-section
:marked
@ -510,7 +513,7 @@ block router-config-intro
在这个阶段,`AppComponent`看起来是这样的:
+makeExample('toh-5/ts/app/app.component.2.ts',null, 'app/app.component.ts (v2)')
+makeExample('app/app.component.1.ts', 'v2', 'app/app.component.ts (v2)')
:marked
The *AppComponent* is now attached to a router and displaying routed views.
For this reason and to distinguish it from other kinds of components,
@ -532,7 +535,7 @@ block router-config-intro
先创建一个`DashboardComponent`的占位符,让我们可以导航到它或从它导航出来。
+makeExample('toh-5/ts/app/dashboard.component.1.ts',null, 'app/dashboard.component.ts (v1)')(format=".")
+makeExcerpt('app/dashboard.component.1.ts (v1)', '')
:marked
Well come back and make it more useful later.
@ -542,42 +545,47 @@ block router-config-intro
### 配置仪表盘路由
Go back to `app.routing.ts` and teach it to navigate to the dashboard.
Go back to `!{_appRoutingTsVsAppComp}` and teach it to navigate to the dashboard.
回到`app.routing.ts`文件,我们得教它如何导航到这个仪表盘。
回到`!{_appRoutingTsVsAppComp}`,我们得教它如何导航到这个仪表盘。
Import the `DashboardComponent` so we can reference it in the dashboard route definition.
Import the dashboard component and
add the following route definition to the `!{_RoutesVsAtRouteConfig}` !{_array} of definitions.
先导入`DashboardComponent`类,这样我们就可以在仪表盘的路由定义中引用它了
先导入`DashboardComponent`类,然后把下列路由的定义添加到`!{_RoutesVsAtRouteConfig}`数组中
Add the following `'Dashboard'` route definition to the `Routes` array of definitions.
- var _file = _docsFor == 'dart' ? 'lib/app_component.dart' : 'app/app.routing.ts'
+makeExcerpt(_file + ' (Dashboard route)', 'dashboard')
然后把下列`'Dashboard'`路由的定义添加到`Routes`数组中。
+makeExample('toh-5/ts/app/app.routing.2.ts','dashboard-route', 'app/app.routing.ts (Dashboard route)')(format=".")
:marked
We also need to add the `DashboardComponent` to our root NgModule's `declarations`.
我们还得把`DashboardComponent`添加到根模块的`declarations`数组中。
+ifDocsFor('ts|js')
:marked
Also import and add `DashboardComponent` to our root NgModule's `declarations`.
还得把`DashboardComponent`添加到根模块的`declarations`数组中。
+makeExcerpt('app/app.module.ts', 'dashboard')
.l-sub-section
:marked
**Redirect**
**重定向**
:marked
#### !{_redirectTo}
#### !{_redirectTo}
We want the app to show the dashboard when it starts and
we want to see a nice URL in the browser address bar that says `/dashboard`.
Remember that the browser launches with `/` in the address bar.
我们希望在应用启动的时候就显示仪表盘而且我们希望在浏览器的地址栏看到一个好看的URL比如`/dashboard`。
记住,浏览器启动时,在地址栏中使用的路径是`/`。
我们可以使用一个重定向路由来达到目的。
+makeExample('toh-5/ts/app/app.routing.2.ts','redirect-route', 'app/app.routing.ts (Redirect route)')(format=".")
我们希望在应用启动的时候就显示仪表盘而且我们希望在浏览器的地址栏看到一个好看的URL比如`/dashboard`。
记住,浏览器启动时,在地址栏中使用的路径是`/`。
我们可以使用一个重定向路由来达到目的。
block redirect-vs-use-as-default
:marked
We can use a redirect route to make this happen. Add the following
to our array of route definitions:
可以使用重定向路由来实现它。添加下面的内容到路由定义的数组中:
+makeExcerpt('app/app.routing.ts','redirect')
.l-sub-section
:marked
@ -587,10 +595,15 @@ block router-config-intro
:marked
#### Add navigation to the template
#### 添加导航到模版中
Finally, add a dashboard navigation link to the template, just above the *Heroes* link.
最后,在模板上添加一个到仪表盘的导航链接,就放在*英雄(Heroes)*链接的上方。
- var _vers = _docsFor == 'dart' ? '' : '.1'
+makeExcerpt('app/app.component' + _vers + '.ts', 'template-v3')
+makeExample('toh-5/ts/app/app.component.3.ts','template', 'app/app.component.ts (template)')(format=".")
.l-sub-section
@ -617,24 +630,27 @@ block router-config-intro
把元数据中的`template`属性替换为`templateUrl`属性,它将指向一个新的模板文件。
+makeExample('toh-5/ts/app/dashboard.component.ts', 'template-url', 'app/dashboard.component.ts (templateUrl)')(format=".")
+makeExcerpt('app/dashboard.component.ts', 'templateUrl')
.l-sub-section
:marked
We specify the path _all the way back to the application root_ &mdash; `app/` in this case &mdash;
because Angular doesn't support relative paths _by default_.
We _can_ switch to [component-relative paths](../cookbook/component-relative-paths.html) if we prefer.
block templateUrl-path-resolution
:marked
We specify the path _all the way back to the application root_ &mdash;
<span if-docs="ts">`app/` in this case &mdash;</span>
because Angular doesn't support relative paths _by default_.
We _can_ switch to [component-relative paths](../cookbook/component-relative-paths.html) if we prefer.
我们指定的所有路径_都是相对于该应用的根目录(这里是`app/`)的_。
因为Angular_默认_不支持使用相对于当前模块的路径。
只要喜欢我们也_可以_切换成[相对于组件的路径](../cookbook/component-relative-paths.html)模式。
我们指定的所有路径_都是相对于该应用的根目录 - <span if-docs="ts">这里是`app/`</span>
因为Angular_默认_不支持使用相对于当前模块的路径。
只要喜欢我们也_可以_切换成[相对于组件的路径](../cookbook/component-relative-paths.html)模式。
:marked
Create that file with these contents:
Create that file with this content:
使用下列内容创建文件:
+makeExample('toh-5/ts/app/dashboard.component.html', null, 'app/dashboard.component.html')(format=".")
+makeExcerpt('app/dashboard.component.html')
:marked
We use `*ngFor` once again to iterate over a list of heroes and display their names.
We added extra `<div>` elements to help with styling later in this chapter.
@ -653,14 +669,14 @@ block router-config-intro
### 共享*HeroService*
We'd like to re-use the `HeroService` to populate the component's `heroes` array.
We'd like to re-use the `HeroService` to populate the component's `heroes` !{_array}.
我们想要复用`HeroService`来存放组件的`heroes`数组。
Recall earlier in the chapter that we removed the `HeroService` from the `providers` array of the `HeroesComponent`
and added it to the `providers` array of the root `NgModule`.
Recall earlier in the chapter that we removed the `HeroService` from the `providers` !{_array} of `HeroesComponent`
and added it to the `providers` !{_array} of `!{_AppModuleVsAppComp}`.
回忆一下,在前面的章节中,我们从`HeroesComponent`的`providers`数组中移除了`HeroService`服务,并把它添加到顶级组件`AppComponent`的`providers`数组中。
回忆一下,在前面的章节中,我们从`HeroesComponent`的`providers`数组中移除了`HeroService`服务,并把它添加到顶级组件`!{_AppModuleVsAppComp}`的`providers`数组中。
That move created a singleton `HeroService` instance, available to *all* components of the application.
Angular will inject `HeroService` and we'll use it here in the `DashboardComponent`.
@ -672,11 +688,12 @@ block router-config-intro
### 获取英雄数组
Open the `dashboard.component.ts` and add the requisite `import` statements.
Open <span ngio-ex>dashboard.component.ts</span> and add the requisite `import` statements.
打开`dashboard.component.ts`文件,并把必备的`import`语句加进去。
打开<span ngio-ex>dashboard.component.ts</span>文件,并把必备的`import`语句加进去。
+makeExcerpt('app/dashboard.component.2.ts','imports')
+makeExample('toh-5/ts/app/dashboard.component.2.ts','imports', 'app/dashboard.component.ts (导入)')(format=".")
:marked
We need `OnInit` interface because we'll initialize the heroes in the `ngOnInit` method as we've done before.
We need the `Hero` and `HeroService` symbols in order to reference those types.
@ -688,29 +705,29 @@ block router-config-intro
我们现在就实现`DashboardComponent`类,像这样:
+makeExample('toh-5/ts/app/dashboard.component.2.ts','component', 'app/dashboard.component.ts (class)')
+makeExcerpt('app/dashboard.component.2.ts (class)', 'component')
:marked
We saw this kind of logic before in the `HeroesComponent`.
We've seen this kind of logic before in the `HeroesComponent`:
在`HeroesComponent`之前,我们也看到过类似的逻辑:
* create a `heroes` array property
* Define a `heroes` !{_array} property.
* 创建一个`heroes`数组属性
* inject the `HeroService` in the constructor and hold it in a private `heroService` field.
* Inject the `HeroService` in the constructor and hold it in a private `!{_priv}heroService` field.
* 把`HeroService`注入构造函数中,并且把它保存在一个私有的`heroService`字段中。
* 把`HeroService`注入构造函数中,并且把它保存在一个私有的`!{_priv}heroService`字段中。
* call the service to get heroes inside the Angular `ngOnInit` lifecycle hook.
* Call the service to get heroes inside the Angular `ngOnInit` lifecycle hook.
* 在Angular的`ngOnInit`生命周期钩子里面调用服务来获得英雄列表。
The noteworthy differences: we cherry-pick four heroes (2nd, 3rd, 4th, and 5th) with *slice*
The noteworthy differences: we cherry-pick four heroes (2nd, 3rd, 4th, and 5th)
and stub the `gotoDetail` method until we're ready to implement it.
值得注意的区别是:我们用*slice*随机提取了四个英雄第2、3、4、5个暂时隔离`gotoDetail`方法直到时机成熟。
值得注意的区别是我们提取了四个英雄第2、3、4、5个暂时隔离`gotoDetail`方法直到时机成熟。
Refresh the browser and see four heroes in the new dashboard.
@ -739,17 +756,17 @@ block router-config-intro
1. 把一个指向该英雄的“深链接”URL粘贴到浏览器的地址栏。
Adding a `'HeroDetail'` route seem an obvious place to start.
Adding a hero-detail route seems like an obvious place to start.
添加`'HeroDetail'`路由,是一个显而易见的起点。
添加`hero-detail`路由,是一个显而易见的起点。
### Routing to a hero detail
### 路由到一个英雄详情
We'll add a route to the `HeroDetailComponent` in the `app.routing.ts` where our other routes are configured.
We'll add a route to the `HeroDetailComponent` in `!{_appRoutingTsVsAppComp}` where our other routes are configured.
我们将在`app.routing.ts`中添加一个到`HeroDetailComponent`的路由,也就是配置其它路由的地方。
我们将在`!{_appRoutingTsVsAppComp}`中添加一个到`HeroDetailComponent`的路由,也就是配置其它路由的地方。
The new route is a bit unusual in that we must tell the `HeroDetailComponent` *which hero to show*.
We didn't have to tell the `HeroesComponent` or the `DashboardComponent` anything.
@ -757,11 +774,12 @@ block router-config-intro
新路由的不寻常之处在于,我们必须告诉`HeroDetailComponent`*该显示哪个英雄*。
以前的`HeroesComponent`组件和`DashboardComponent`组件还从未要求我们告诉它任何东西。
At the moment the parent `HeroesComponent` sets the component's `hero` property to a hero object with a binding like this.
At the moment the parent `HeroesComponent` sets the component's `hero` property to a
hero object with a binding like this.
现在,父组件`HeroesComponent`通过数据绑定来把一个英雄对象设置为组件的`hero`属性。就像这样:
code-example(format='').
code-example(language="html").
&lt;my-hero-detail [hero]="selectedHero">&lt;/my-hero-detail>
:marked
@ -775,7 +793,8 @@ code-example(format='').
### 参数化路由
We *can* add the hero's `id` to the URL. When routing to the hero whose `id` is 11, we could expect to see an URL such as this:
We *can* add the hero's `id` to the URL. When routing to the hero whose `id` is 11,
we could expect to see an URL such as this:
我们*可以*把英雄的`id`添加到URL中。当导航到一个`id`为11的英雄时我们期望的URL是这样的
@ -797,7 +816,8 @@ code-example(format='').
下面是我们将使用的*路由定义*。
+makeExample('toh-5/ts/app/app.routing.2.ts','hero-detail-route', 'app/app.routing.ts (route to HeroDetailComponent)')(format=".")
- var _file = _docsFor == 'dart' ? 'app/app.component.ts' : 'app/app.routing.ts'
+makeExcerpt(_file + ' (hero detail)','hero-detail')
:marked
The colon (:) in the path indicates that `:id` is a placeholder to be filled with a specific hero `id`
@ -805,20 +825,13 @@ code-example(format='').
路径中的冒号(:)表示`:id`是一个占位符,当导航到这个`HeroDetailComponent`组件时,它将被填入一个特定英雄的`id`。
.l-sub-section
:marked
Of course we have to import the `HeroDetailComponent` before we create this route:
当然,在创建这个路由之前,我们必须导入`HeroDetailComponent`类:
+makeExample('toh-5/ts/app/app.routing.2.ts','hero-detail-import')(format=".")
:marked
Add the `HeroDetailComponent` to our root NgModule's `declarations`.
把`HeroDetailComponent`添加到根模块的`declarations`数组中。
+makeExample('toh-5/ts/app/app.module.3.ts','hero-detail-declaration', 'app/app.module.ts (Hero Detail declaration)')(format=".")
+ifDocsFor('dart')
.l-sub-section
:marked
Remember to import the hero detail component before creating this route.
记得在创建这个路由前导入英雄详情组件。
:marked
We're finished with the application routes.
@ -861,65 +874,57 @@ code-example(format='').
模板不用修改,我们会用原来的方式显示英雄。导致这次大修的原因是如何获得这个英雄的数据。
We will no longer receive the hero in a parent component property binding.
The new `HeroDetailComponent` should take the `id` parameter from the `params` observable
in the `ActivatedRoute` service and use the `HeroService` to fetch the hero with that `id`.
我们不会再从父组件的属性绑定中取得英雄数据。
新的`HeroDetailComponent`应该从`ActivatedRoute`服务的可观察对象`params`中取得`id`参数,并通过`HeroService`服务获取具有这个指定`id`的英雄数据。
We need an import statement to reference the `ActivatedRoute` and `Params` types.
我们需要一个import语句来引用`ActivatedRoute`和`Params`类型。
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'import-activated-route')(format=".")
block route-params
:marked
We will no longer receive the hero in a parent component property binding.
The new `HeroDetailComponent` should take the `id` parameter from the `params` observable
in the `ActivatedRoute` service and use the `HeroService` to fetch the hero with that `id`.
我们不会再从父组件的属性绑定中取得英雄数据。
新的`HeroDetailComponent`应该从`ActivatedRoute`服务的可观察对象`params`中取得`id`参数,并通过`HeroService`服务获取具有这个指定`id`的英雄数据。
:marked
We import the `HeroService`so we can fetch a hero.
我们导入了`HeroService`,现在就能获取一个英雄了。
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'import-hero-service')(format=".")
First, add the requisite imports:
首先,添加需要的导入项目:
- var _vers = _docsFor == 'dart' ? '' : '.1'
+makeExcerpt('app/hero-detail.component' + _vers + '.ts', 'added-imports', '')
- var _ActivatedRoute = _docsFor == 'dart' ? 'RouteParams' : 'ActivatedRoute'
:marked
We import the `OnInit` interface because we'll call the `HeroService` inside the `ngOnInit` component lifecycle hook.
Let's have the `!{_ActivatedRoute}` service and the `HeroService` injected
into the constructor, saving their values in private fields:
然后注入`!{_ActivatedRoute}`和`HeroService`服务到构造函数中,将他们的值保存到私有变量中:
我们得导入`OnInit`接口,因为我们需要在组件的`ngOnInit`生命周期钩子中调用`HeroService`。
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'import-oninit')(format=".")
:marked
We inject the both the `ActivatedRoute` service and the `HeroService` into the constructor as we've done before,
making private variables for both:
像以前一样,我们把`RouteParams`服务和`HeroService`服务注入到构造函数中,让它们成为私有变量。
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'ctor', 'app/hero-detail.component.ts (构造函数)')(format=".")
+makeExcerpt('app/hero-detail.component.ts (constructor)', 'ctor')
:marked
We tell the class that we want to implement the `OnInit` interface.
我们告诉这个类,我们要实现`OnInit`接口。
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'implement')(format=".")
+makeExcerpt('app/hero-detail.component.ts', 'implement', '')(format=".")
:marked
Inside the `ngOnInit` lifecycle hook, we use the `params` observable to
extract the `id` parameter value from the `ActivateRoute` service
and use the `HeroService` to fetch the hero with that `id`.
block ngOnInit
:marked
Inside the `ngOnInit` lifecycle hook, we use the `params` observable to
extract the `id` parameter value from the `ActivateRoute` service
and use the `HeroService` to fetch the hero with that `id`.
在`ngOnInit`生命周期钩子中,从`RouteParams`服务中提取`id`参数,并且使用`HeroService`来获得具有这个`id`的英雄数据。
在`ngOnInit`生命周期钩子中,从`RouteParams`服务中提取`id`参数,并且使用`HeroService`来获得具有这个`id`的英雄数据。
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'ng-oninit', 'app/hero-detail.component.ts (ngOnInit)')(format=".")
+makeExcerpt('app/hero-detail.component.ts', 'ngOnInit')
:marked
Notice how we extract the `id` by calling the `forEach` method
which will deliver our array of route parameters.
注意我们提取`id`的方法:调用`forEach`方法,它会提供一个路由参数的数组。
block extract-id
:marked
Notice how we extract the `id` by calling the `forEach` method
which will deliver our !{_array} of route parameters.
注意我们提取`id`的方法:调用`forEach`方法,它会提供一个路由参数的数组。
- var _str2int = _docsFor == 'dart' ? '<code>int.parse</code> static method' : 'JavaScript (+) operator'
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'get-id')(format=".")
:marked
The hero `id` is a number. Route parameters are *always strings*.
So we convert the route parameter value to a number with the !{_str2int}.
@ -940,7 +945,7 @@ code-example(format='').
打开`HeroService`,并添加一个`getHero`方法,用来通过`id`从`getHeros`过滤英雄列表:
+makeExample('toh-5/ts/app/hero.service.ts', 'get-hero', 'app/hero.service.ts (getHero)')(format=".")
+makeExcerpt('app/hero.service.ts', 'getHero')
:marked
Let's return to the `HeroDetailComponent` to clean up loose ends.
@ -963,39 +968,41 @@ code-example(format='').
现在用户可以点击`AppComponent`中的两个链接,或点击浏览器的“后退”按钮。
我们来添加第三个选项:一个`goBack`方法,来根据浏览器的历史堆栈,后退一步。
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'go-back', 'app/hero-detail.component.ts (goBack)')(format=".")
+makeExcerpt('app/hero-detail.component.ts', 'goBack')
- var _CanDeactivateGuard = _docsFor == 'dart' ? '<em>routerCanDeactivate</em> hook' : '<em>CanDeactivate</em> guard'
- var _CanDeactivateGuardUri = _docsFor == 'dart' ? 'angular2.router/CanDeactivate-class' : 'router/index/CanDeactivate-interface'
.l-sub-section
:marked
Going back too far could take us out of the application.
That's acceptable in a demo. We'd guard against it in a real application,
perhaps with the [*CanDeactivate* guard](../api/router/index/CanDeactivate-interface.html).
回退太多步儿会跑出我们的应用。
在Demo中这算不上问题。但在真实的应用中我们需要对此进行防范。
也许你该用[*CanDeactivate*守卫](../api/router/index/CanDeactivate-interface.html).。
:marked
Going back too far could take us out of the application.
That's acceptable in a demo. We'd guard against it in a real application,
perhaps with the [!{_CanDeactivateGuard}](../api/!{_CanDeactivateGuardUri}.html).
回退太多步儿会跑出我们的应用。
在Demo中这算不上问题。但在真实的应用中我们需要对此进行防范。
也许你该用[!{_CanDeactivateGuard}](../api/!{_CanDeactivateGuardUri}.html).。
:marked
Then we wire this method with an event binding to a *Back* button that we add to the bottom of the component template.
然后,我们通过一个事件绑定把此方法绑定到模板底部的*后退(Back)*按钮上。
+makeExample('toh-5/ts/app/hero-detail.component.html', 'back-button')(format=".")
+makeExcerpt('app/hero-detail.component.html', 'back-button', '')
:marked
Modifing the template to add this button spurs us to take one more incremental improvement and migrate the template to its own file
called `hero-detail.component.html`
called <span ngio-ex>hero-detail.component.html</span>
修改模板,添加这个按钮以提醒我们还要做更多的改进,并把模板移到独立的`hero-detail.component.html`文件中去。
修改模板,添加这个按钮以提醒我们还要做更多的改进,并把模板移到独立的<span ngio-ex>hero-detail.component.html</span>文件中去。
+makeExample('toh-5/ts/app/hero-detail.component.html', '', 'app/hero-detail.component.html')(format=".")
+makeExample('app/hero-detail.component.html')
:marked
We update the component metadata with a `templateUrl` pointing to the template file that we just created.
然后更新组件的元数据,用一个`templateUrl`属性指向我们刚刚创建的模板文件。
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'template-url', 'app/hero-detail.component.ts (templateUrl)')(format=".")
+makeExcerpt('app/hero-detail.component.ts', 'templateUrl')
:marked
Here's the (nearly) finished `HeroDetailComponent`:
@ -1030,37 +1037,45 @@ code-example(format='').
当初我们重写`DashboardComponent`的时候,`gotoDetail`还是一个“桩方法”。
现在,我们给它一个真正的实现。
+makeExample('toh-5/ts/app/dashboard.component.ts','goto-detail', 'app/dashboard.component.ts (gotoDetail)')(format=".")
+makeExcerpt('app/dashboard.component.ts','gotoDetail')
:marked
The `gotoDetail` method navigates in two steps:
`gotoDetail`方法分两步完成导航:
1. set a route *link parameters array*
1. Set a route *link parameters !{_array}*
1. 生成路由的 *链接参数数组*
1. pass the array to the router's navigate method.
1. Pass the !{_array} to the router's navigate method
1. 把这个数组传给路由器的navigate方法。
We wrote *link parameters arrays* in the `AppComponent` for the navigation links.
Those arrays had only one element, the path of the destination route.
For navigation, we wrote router links <span if-docs="dart">as *link
parameters !{_array}s*</span> in the [`AppComponent`
template](#router-links). Those link<span if-docs="dart"> parameters
!{_array}</span>s had only one element, the !{_pathVsName} of the
destination route.
我们当初在`AppComponent`中生成导航链接的时候曾写过*链接参数数组*。
那些数组中只有一个元素:目标路由的路径。
我们为导航在[`AppComponent`的模板](#router-links)中生成导航链接<span if-docs="dart">as *link
parameters !{_array}s*</span>。这些链接<span if-docs="dart"> parameters
!{_array}</span>只有一个元素:目标路由的路径。
This link parameters !{_array} has two elements, the ***!{_pathVsName}*** of
the destination route and a ***route parameter*** <span if-docs="dart">with
an `id` field</span> set to the value of the selected hero's `id`.
这个链接参数数组有两个元素:目标路由的***路径(path)***和一个***路由参数对象***,其中包括一个`id`字段,它的取值是所选英雄的`id`。
The two !{_array} items align with the ***!{_pathVsName}*** and ***:id***
token in the parameterized hero detail route definition we added to
`!{_appRoutingTsVsAppComp}` earlier in the chapter:
This array has two elements, the ***path*** of the destination route and a ***route parameter***
with an `id` field set to the value of the selected hero's `id`.
这两个数组项目与我们之前在`!{_appRoutingTsVsAppComp}`中添加的***path***和***:id***为代号被参数化的英雄详情路由的配置对象对应。
这个数组则两个元素,目标路由的***路径(path)***,和一个***路由参数对象***,其中包括一个`id`字段,它的取值是所选英雄的`id`。
The two array items align with the ***path*** and ***:id*** token in the parameterized `HeroDetail` route configuration we added to `app.routing.ts` earlier in the chapter.
当初我们在`app.routing.ts`中添加路由的时候,这两个数组元素以***path***和***:id***为代号被参数化的`HeroDetail`路由配置对象中。
+makeExample('toh-5/ts/app/app.routing.2.ts','hero-detail-route', 'app/app.routing.ts (hero detail route)')(format=".")
- var _file = _docsFor == 'dart' ? 'app/app.component.ts' : 'app/app.routing.ts'
+makeExcerpt(_file + ' (hero detail)', 'hero-detail')
:marked
The `DashboardComponent` doesn't have the router yet. We obtain it in the usual way:
@ -1069,9 +1084,9 @@ code-example(format='').
`DashboardComponent`还没有路由器。我们使用常规的方式为它加上路由:
`import` `router`对象的引用,并且把它注入到构造函数中(就像`HeroService`那样)
+makeExample('toh-5/ts/app/dashboard.component.ts','import-router', 'app/dashboard.component.ts (节选)')(format=".")
+makeExcerpt('app/dashboard.component.ts ()','import-router', '')
+makeExample('toh-5/ts/app/dashboard.component.ts','ctor')(format=".")
+makeExcerpt('app/dashboard.component.ts', 'ctor', '')
:marked
Refresh the browser and select a hero from the dashboard; the app should navigate directly to that heros details.
@ -1122,7 +1137,7 @@ code-example(format='').
在模板底部原来放`<my-hero-detail>`的地方添加下列HTML片段
+makeExample('toh-5/ts/app/heroes.component.html','mini-detail')(format=".")
+makeExcerpt('app/heroes.component.html', 'mini-detail', '')
:marked
After clicking a hero, the user should see something like this below the hero list:
@ -1136,12 +1151,12 @@ figure.image-display
### 使用*UpperCasePipe*格式化
Notice that the hero's name is displayed in CAPITAL LETTERS. That's the effect of the `UpperCasePipe`
Notice that the hero's name is displayed in CAPITAL LETTERS. That's the effect of the `uppercase` pipe
that we slipped into the interpolation binding. Look for it right after the pipe operator ( | ).
注意,英雄的名字全被显示成大写字母。那是 `UpperCasePipe`的效果,借助它,我们能插手“插值表达式绑定”的过程。去管道操作符 ( | ) 后面找它。
注意,英雄的名字全被显示成大写字母。那是 `uppercase`管道的效果,借助它,我们能插手“插值表达式绑定”的过程。去管道操作符 ( | ) 后面找它。
+makeExample('toh-5/ts/app/heroes.component.html','pipe')(format=".")
+makeExcerpt('app/heroes.component.html', 'pipe', '')
:marked
Pipes are a good way to format strings, currency amounts, dates and other display data.
@ -1176,19 +1191,33 @@ figure.image-display
在做更多修改之前,我们先把模板和样式移到它们自己的文件中去:
1. *Cut-and-paste* the template contents into a new `heroes.component.html` file.
1. *Cut-and-paste* the template contents into a new <span ngio-ex>heroes.component.html</span> file.
1. 把模板内容*剪切并粘贴*到新的`heroes.component.html`文件。
1. 把模板内容*剪切并粘贴*到新的<span ngio-ex>heroes.component.html</span>文件。
1. *Cut-and-paste* the styles contents into a new `heroes.component.css` file.
1. *Cut-and-paste* the styles contents into a new <span ngio-ex>heroes.component.css</span> file.
1. 把样式内容*剪切并粘贴*到新的`heroes.component.css`文件。
1. 把样式内容*剪切并粘贴*到新的<span ngio-ex>heroes.component.css</span>文件。
1. *Set* the component metadata's `templateUrl` and `styleUrls` properties to refer to both files.
1. *设置*组件元数据的`templateUrl`和`styleUrls`属性,来分别引用这两个文件。
+makeExample('toh-5/ts/app/heroes.component.ts', 'metadata', 'app/heroes.component.ts (revised metadata)')(format=".")
.l-sub-section
:marked
The `styleUrls` property is !{_an} !{_array} of style file names (with paths).
We could list multiple style files from different locations if we needed them.
<span if-docs="ts">As with `templateUrl`, we must specify the path _all the way
back to the application root_.</span>
`styleUrls`属性是一个由样式文件的文件名(包括路径)组成的数组。
我们还可以列出来自多个不同位置的样式文件。
和`templateUrl`一样必须指定_相对于此应用根目录_的路径。
block heroes-component-cleanup
//- Only relevant for Dart.
+makeExcerpt('app/heroes.component.ts (revised metadata)', 'metadata')
:marked
Now we can see what's going on as we update the component class along the same lines as the dashboard:
@ -1213,7 +1242,7 @@ figure.image-display
下面是修改过的组件类:
+makeExample('toh-5/ts/app/heroes.component.ts', 'class', 'app/heroes.component.ts (类)')
+makeExcerpt('app/heroes.component.ts', 'class')
:marked
Refresh the browser and start clicking.
@ -1258,23 +1287,12 @@ figure.image-display
如果我们把这60来行CSS粘贴到组件元数据的`styles`中,它们会完全淹没组件的工作逻辑。
不能这么做。在一个独立的`*.css`文件中编辑CSS当然会更简单。
Add a `dashboard.component.css` file to the `app` folder and reference
that file in the component metadata's `styleUrls` array property like this:
Add a <span ngio-ex>dashboard.component.css</span> file to the `!{_appDir}` folder and reference
that file in the component metadata's `styleUrls` !{_array} property like this:
`dashboard.component.css`文件添加到`app`目录下,并在组件元数据的`styleUrls`数组属性中引用它。就像这样:
<span ngio-ex>dashboard.component.css</span>文件添加到`!{_appDir}`目录下,并在组件元数据的`styleUrls`数组属性中引用它。就像这样:
+makeExample('toh-5/ts/app/dashboard.component.ts', 'css', 'app/dashboard.component.ts (styleUrls)')(format=".")
:marked
.l-sub-section
:marked
The `styleUrls` property is an array of style file names (with paths).
We could list multiple style files from different locations if we needed them.
As with `templateUrl`, we must specify the path _all the way back to the application root_.
`styleUrls`属性是一个由样式文件的文件名(包括路径)组成的数组。
如果需要,我们还可以列出来自多个不同位置的样式文件。
和`templateUrl`一样我们必须指定_相对于此应用根目录_的路径。
+makeExcerpt('app/dashboard.component.ts (styleUrls)', 'css')
:marked
### Stylish Hero Details
@ -1285,21 +1303,28 @@ figure.image-display
设计师还给了我们`HeroDetailComponent`特有的CSS风格。
Add a `hero-detail.component.css` to the `app` folder and refer to that file inside
the `styleUrls` array as we did for `DashboardComponent`.
Add a <span ngio-ex>hero-detail.component.css</span> to the `!{_appDir}`
folder and refer to that file inside
the `styleUrls` !{_array} as we did for `DashboardComponent`.
Let's also remove the `hero` property `@Input` !{_decorator}
<span if-docs="ts">and its import</span>
while we are at it.
在`app`目录下添加`hero-detail.component.css`文件,并且在`styleUrls`数组中引用它 —— 就像当初在`DashboardComponent`中做过的那样。
在`!{_appDir}`目录下添加<span ngio-ex>hero-detail.component.css</span>文件,
并且在`styleUrls`数组中引用它 —— 就像当初在`DashboardComponent`中做过的那样。
同时删除`hero``@Input`装饰器属性<span if-docs="ts">和它的导入语句</span>。
Here's the content for the aforementioned component CSS files.
上述组件的CSS文件内容如下
+makeTabs(
`toh-5/ts/app/hero-detail.component.css,
toh-5/ts/app/dashboard.component.css`,
null,
`app/hero-detail.component.css,
app/dashboard.component.css`)
block css-files
+makeTabs(
`toh-5/ts/app/hero-detail.component.css,
toh-5/ts/app/dashboard.component.css`,
null,
`app/hero-detail.component.css,
app/dashboard.component.css`)
:marked
### Style the Navigation Links
@ -1312,34 +1337,34 @@ figure.image-display
设计师还给了我们一些CSS用于让`AppComponent`中的导航链接看起来更像可被选择的按钮。
要让它们协同工作,我们得把那些链接包含在`<nav>`标签中。
Add a `app.component.css` file to the `app` folder with the following content.
Add a <span ngio-ex>app.component.css</span> file to the `!{_appDir}` folder with the following content.
在`app`目录下添加一个`app.component.css`文件,内容如下:
在`!{_appDir}`目录下添加一个<span ngio-ex>app.component.css</span>文件,内容如下:
+makeExample('toh-5/ts/app/app.component.css', '', 'app/app.component.css (navigation styles)')
+makeExcerpt('app/app.component.css (navigation styles)', '')
.l-sub-section
block router-link-active
:marked
**The *routerLinkActive* directive**
***routerLinkActive*指令**
***routerLinkActive*指令**
The Angular Router provides a `routerLinkActive` directive we can use to
add a class to the HTML navigation element whose route matches the active route.
All we have to do is define the style for it. Sweet!
Angular路由器提供了`routerLinkActive`指令我们可以用它来为匹配了活动路由的HTML导航元素自动添加一个CSS类。
我们唯一要做的就是为它定义样式。真好!
The Angular Router provides a `routerLinkActive` directive we can use to
add a class to the HTML navigation element whose route matches the active route.
All we have to do is define the style for it. Sweet!
Angular路由器提供了`routerLinkActive`指令我们可以用它来为匹配了活动路由的HTML导航元素自动添加一个CSS类。
我们唯一要做的就是为它定义样式。真好!
+makeExample('toh-5/ts/app/app.component.ts', 'template', 'app/app.component.ts (active router links)')(format=".")
+makeExcerpt('app/app.component.ts (active router links)', 'template')
:marked
Set the `AppComponent`s `styleUrls` property to this CSS file.
设置`AppComponent`的`styleUrls`属性指向这个CSS文件。
+makeExample('toh-5/ts/app/app.component.ts','style-urls', 'app/app.component.ts (styleUrls)')(format=".")
+makeExcerpt('app/app.component.ts','styleUrls')
:marked
### Global application styles
@ -1368,7 +1393,7 @@ figure.image-display
[快速起步, "添加一些样式"](../quickstart.html#!#add-some-style))。
下面是摘录:
+makeExample('toh-5/ts/styles.1.css', 'toh-excerpt', 'styles.css (app styles excerpt)')(format=".")
+makeExcerpt('styles.css (excerpt)', 'toh')
- var styles_css = 'https://raw.githubusercontent.com/angular/angular.io/master/public/docs/_examples/styles.css'
@ -1379,16 +1404,16 @@ figure.image-display
如果在根目录下没有一个名叫`styles.css`的文件,就添加它。
确保它包含[这里给出的主样式](!{styles_css})。
If necessary, also edit `index.html` to refer to this stylesheet.
If necessary, also edit <span ngio-ex>index.html</span> to refer to this stylesheet.
如有必要,也可以编辑`index.html`来引用这个样式表。
如有必要,也可以编辑<span ngio-ex>index.html</span>来引用这个样式表。
+makeExample('toh-5/ts/index.html','css', 'index.html (link ref)')(format=".")
+makeExcerpt('index.html (link ref)', 'css')
:marked
Look at the app now. Our dashboard, heroes, and navigation links are styling!
看看现在的应用!我们的仪表盘、英雄列表和导航链接都漂亮多了!
看看现在的应用!我们的仪表盘、英雄列表和导航链接都漂亮多了!
figure.image-display
img(src='/resources/images/devguide/toh/dashboard-top-heroes.png' alt="查看导航栏")
@ -1447,7 +1472,7 @@ block file-tree-end
### 走过的路
We travelled a great distance in this chapter.
We travelled a great distance in this chapter
在本章中,我们往前走了很远:
@ -1459,9 +1484,9 @@ block file-tree-end
- 我们学会了如何创建路由链接来表示导航栏的菜单项。
- We used router parameters to navigate to the details of user selected hero.
- We used router link parameters to navigate to the details of user selected hero.
- 我们使用路由参数来导航到用户所选的英雄详情。
- 我们使用路由链接参数来导航到用户所选的英雄详情。
- We shared the `HeroService` among multiple components.

View File

@ -352,9 +352,9 @@ block get-heroes-details
### Post
We are using `post` to add new heroes. Post requests require a little bit more setup than Get requests, but the format is as follows:
We will be using `post` to add new heroes. Post requests require a little bit more setup than Get requests:
我们使用`post`来添加新的英雄。post请求比get请求稍多一点儿设置工作,大致写法如下
我们使用`post`来添加新的英雄。post请求比get请求稍多一点儿设置工作
+makeExcerpt('app/hero.service.ts', 'post')
@ -593,11 +593,10 @@ block review
figure.image-display
img(src='/resources/images/devguide/toh/toh-http.anim.gif' alt="Heroes List Editing w/ HTTP")
block observables-section
:marked
## !{_Observable}s
## 可观察对象Observable
:marked
## !{_Observable}s
## 可观察对象Observable
block observables-section-intro
:marked