烹饪书-依赖注入 二审完毕

烹饪书-动态表单 二审完毕
烹饪书-设置文档标题 二审完毕
This commit is contained in:
Zhicheng Wang 2016-05-18 11:38:10 +08:00
parent dc5e87aad0
commit 8f01383b6c
4 changed files with 230 additions and 226 deletions

File diff suppressed because it is too large Load Diff

View File

@ -3,25 +3,25 @@ include ../_util-fns
:marked :marked
We can't always justify the cost and time to build handcrafted forms, especially if we'll need a great number of them, they're similar to each other, and they change frequently to meet rapidly changing business and regulatory requirements. We can't always justify the cost and time to build handcrafted forms, especially if we'll need a great number of them, they're similar to each other, and they change frequently to meet rapidly changing business and regulatory requirements.
有时候手动编写和维护表单需要工作量和时间过多。特别是需要编写大量的表单时,表单都非常类似,而且随着商务和政策需求的迅速变化,表单也需要随之变化,维护成本过高。 有时候手动编写和维护表单所需工作量和时间会过大。特别是在需要编写大量表单时。表单都很相似,而且随着业务和监管需求的迅速变化,表单也要随之变化,这样维护的成本过高。
It may be more economical to create the forms dynamically, based on metadata that describe the business object model. It may be more economical to create the forms dynamically, based on metadata that describe the business object model.
基于商务对象模型元数据,动态建立表单可能更加划算。 基于业务对象模型的元数据,动态创建表单可能会更划算。
In this cookbook we show how to use `ngFormModel` to dynamically render a simple form with different control types and validation. In this cookbook we show how to use `ngFormModel` to dynamically render a simple form with different control types and validation.
It's a primitive start. It's a primitive start.
It might evolve to support a much richer variety of questions, more graceful rendering, and superior user experience. It might evolve to support a much richer variety of questions, more graceful rendering, and superior user experience.
All such greatness has humble beginnings. All such greatness has humble beginnings.
在此烹饪书中,我们会展示如何利用`ngFormModel`来动态渲染一个简单的表单,包括多种类型控制器和验证规则。 在此烹饪书中,我们会展示如何利用`ngFormModel`来动态渲染一个简单的表单,包括各种控件类型和验证规则。
只是一个初级的开始,但是任何伟大都是从谦卑开始的。我们可以在这个基础上添加种类丰富的问卷问题,更加优美的渲染和更加优越的用户体验。 个起点很简陋,但我们可以在这个基础上添加丰富多彩的问卷问题、更优美的渲染以及更卓越的用户体验。
In our example we use a dynamic form to build an online application experience for heroes seeking employment. In our example we use a dynamic form to build an online application experience for heroes seeking employment.
The agency is constantly tinkering with the application process. The agency is constantly tinkering with the application process.
We can create the forms on the fly *without changing our application code*. We can create the forms on the fly *without changing our application code*.
在本例中,我们使用动态表单,为正在找工作的英雄们创建一个在线申请问卷表。职业中介在不断的修改申请流程。我们可以在*不修改程序*的情况下,动态建立一个表格 在本例中,我们使用动态表单,为正在找工作的英雄们创建一个在线申请表。职介中心会不断修改申请流程,我们要在*不修改应用代码*的情况下,动态创建这些表单
<a id="toc"></a> <a id="toc"></a>
:marked :marked
@ -58,11 +58,11 @@ include ../_util-fns
The hero application process involves a form with a lot of questions. The hero application process involves a form with a lot of questions.
The "question" is the most fundamental object in the model. The "question" is the most fundamental object in the model.
第一步是定义一个对象模型,用来描述所有表单功能需要的场景。英雄申请流程涉及到一个包含很多问卷问题的表单。问卷问题是最基础的对象模型。 第一步是定义一个对象模型,用来描述所有表单功能需要的场景。英雄申请流程涉及到一个包含很多问卷问题的表单。问卷问题是最基础的对象模型。
We have created `QuestionBase` as the most fundamental question class. We have created `QuestionBase` as the most fundamental question class.
下面是我们建立的非常基础的问卷问题基础类,名叫`QuestionBase`。 下面是我们建立的最基础的问卷问题基类,名叫`QuestionBase`。
+makeExample('cb-dynamic-form/ts/app/question-base.ts','','app/question-base.ts') +makeExample('cb-dynamic-form/ts/app/question-base.ts','','app/question-base.ts')
@ -70,18 +70,18 @@ include ../_util-fns
From this base we derived two new classes in `TextboxQuestion` and `DropdownQuestion` that represent Textbox and Dropdown questions. From this base we derived two new classes in `TextboxQuestion` and `DropdownQuestion` that represent Textbox and Dropdown questions.
The idea is that the form will be bound to specific question types and render the appropriate controls dynamically. The idea is that the form will be bound to specific question types and render the appropriate controls dynamically.
在这个基础上,我们衍生了两个新类`TextboxQuestion` 和 `DropdownQuestion`,分别代表文本框和下拉框。这么做的初衷是,表单能动态的绑定特定的问卷问题类型,并动态渲染合适的控制器 在这个基础上,我们派生出两个新类`TextboxQuestion` 和 `DropdownQuestion`,分别代表文本框和下拉框。这么做的初衷是,表单能动态绑定到特定的问卷问题类型,并动态渲染出合适的控件
`TextboxQuestion` supports multiple html5 types like text, email, url etc via the `type` property. `TextboxQuestion` supports multiple html5 types like text, email, url etc via the `type` property.
`TextboxQuestion`通过`type`属性,支持多种HTML5元素类型比如文本、邮件、网址等。 `TextboxQuestion`可以通过`type`属性来支持多种HTML5元素类型比如文本、邮件、网址等。
+makeExample('cb-dynamic-form/ts/app/question-textbox.ts',null,'app/question-textbox.ts')(format='.') +makeExample('cb-dynamic-form/ts/app/question-textbox.ts',null,'app/question-textbox.ts')(format='.')
:marked :marked
`DropdownQuestion` presents a list of choices in a select box. `DropdownQuestion` presents a list of choices in a select box.
`DropdownQuestion`代表一个拥有可选项目列表的选择框。 `DropdownQuestion`表示一个带可选项列表的选择框。
+makeExample('cb-dynamic-form/ts/app/question-dropdown.ts',null,'app/question-dropdown.ts')(format='.') +makeExample('cb-dynamic-form/ts/app/question-dropdown.ts',null,'app/question-dropdown.ts')(format='.')
@ -89,8 +89,8 @@ include ../_util-fns
Next we have defined `QuestionControlService`, a simple service for transforming our questions to an ngForm control group. Next we have defined `QuestionControlService`, a simple service for transforming our questions to an ngForm control group.
In a nutshell, the control group consumes the metadata from the question model and allows us to specify default values and validation rules. In a nutshell, the control group consumes the metadata from the question model and allows us to specify default values and validation rules.
接下来,我们定义了`QuestionControlService`,一个可以把我们的问卷问题转换为ngForm控制群的服务。 接下来,我们定义了`QuestionControlService`,一个可以把我们的问卷问题转换为一组ngForm控件的服务。
简而言之,这个ngForm控制群使用问卷模型的元数据允许我们设置默认值和验证规则。 简而言之,这组ngForm控件使用问卷模型的元数据允许我们设置默认值和验证规则。
+makeExample('cb-dynamic-form/ts/app/question-control.service.ts',null,'app/question-control.service.ts')(format='.') +makeExample('cb-dynamic-form/ts/app/question-control.service.ts',null,'app/question-control.service.ts')(format='.')
@ -101,12 +101,12 @@ include ../_util-fns
Now that we have defined the complete model we are ready to create components to represent the dynamic form. Now that we have defined the complete model we are ready to create components to represent the dynamic form.
现在我们已经有一个已定义的完整模型了,我们可以开始创建一个动态表单的组件。 现在我们已经有一个定义好的完整模型了,接着就可以开始创建一个展现动态表单的组件。
:marked :marked
`DynamicForm` is the entry point and the main container for the form. `DynamicForm` is the entry point and the main container for the form.
`DynamicForm`是我们表单的主要载体和切入口 `DynamicForm`是我们表单的主要容器和入口点
+makeTabs( +makeTabs(
`cb-dynamic-form/ts/app/dynamic-form.component.html, `cb-dynamic-form/ts/app/dynamic-form.component.html,
@ -120,8 +120,8 @@ include ../_util-fns
The `<df-question>` tag matches the `DynamicFormQuestionComponent`, The `<df-question>` tag matches the `DynamicFormQuestionComponent`,
the component responsible for rendering the details of each _individual_ question based on values in the data-bound question object. the component responsible for rendering the details of each _individual_ question based on values in the data-bound question object.
它代表了问卷问题列表,每个问题都在`<df-question>`组件元素之内 它代表了问卷问题列表,每个问题都被绑定到一个`<df-question>`组件元素
`<df-question>`标签是组件`DynamicFormQuestionComponent`,该组件的作用是根据每个问卷问题对象的值来动态渲染表单控制器 `<df-question>`标签匹配到的是组件`DynamicFormQuestionComponent`,该组件的职责是根据每个问卷问题对象的值来动态渲染表单控件
+makeTabs( +makeTabs(
`cb-dynamic-form/ts/app/dynamic-form-question.component.html, `cb-dynamic-form/ts/app/dynamic-form-question.component.html,
@ -135,12 +135,12 @@ include ../_util-fns
We only have two types of questions at this point but we can imagine many more. We only have two types of questions at this point but we can imagine many more.
The `ngSwitch` determines which type of question to display. The `ngSwitch` determines which type of question to display.
请注意,这个组件能代表模型里的任何问卷问题类型。目前,我们只有两种问卷问题类型,但是我们可以添加更多类型。`ngSwitch`判断显示哪一个类型的问卷问题。 请注意,这个组件能代表模型里的任何问题类型。目前,还只有两种问题类型,但我们可以添加更多类型。可以用`ngSwitch`决定显示哪种类型的问题。
In both components we're relying on Angular's **ngFormModel** to connect the template HTML to the In both components we're relying on Angular's **ngFormModel** to connect the template HTML to the
underlying control objects, populated from the question model with display and validation rules. underlying control objects, populated from the question model with display and validation rules.
在两个组件中我们依赖Angular的**ngFormModel**来把模板HTML链接到底层控制对象,该对象从问卷问题模型里获取渲染和验证规则。 两个组件中我们依赖Angular的**ngFormModel**来把模板HTML和底层控件对象连接起来,该对象从问卷问题模型里获取渲染和验证规则。
<a id="questionnaire-metadata"></a> <a id="questionnaire-metadata"></a>
:marked :marked
@ -150,24 +150,25 @@ include ../_util-fns
:marked :marked
`DynamicForm` expects the list of questions in the form of an array bound to `@Input() questions`. `DynamicForm` expects the list of questions in the form of an array bound to `@Input() questions`.
`DynamicForm`期得到一个问题列表,该列表被绑定到`@Input() questions`属性。 `DynamicForm`期得到一个问题列表,该列表被绑定到`@Input() questions`属性。
The set of questions we have defined for the job application is returned from the `QuestionService`. The set of questions we have defined for the job application is returned from the `QuestionService`.
In a real app we'd retrieve these questions from storage. In a real app we'd retrieve these questions from storage.
`QuestionService`返回工作申请表的问卷问题列表。在一个真实的应用程序环境中,我们会从数据库里面提取问卷列表。 `QuestionService`会返回我们为工作申请表定义的那组问题列表。在真实的应用程序环境中,我们会从数据库里获得这些问题列表。
The key point is that we control the hero job application questions entirely through the objects returned from `QuestionService`. The key point is that we control the hero job application questions entirely through the objects returned from `QuestionService`.
Questionnaire maintenance is a simple matter of adding, updating, and removing objects from the `questions` array. Questionnaire maintenance is a simple matter of adding, updating, and removing objects from the `questions` array.
最关键的是,我们全部通过从`QuestionService`返回的对象,来控制英雄工作申请问卷。要维护问卷,我们要做的是非常简单的添加、更新和删除`问题`数组中的对象。 关键是,我们完全根据`QuestionService`返回的对象来控制英雄的工作申请表。
要维护这份问卷,我们只要非常简单的添加、更新和删除`questions`数组中的对象就可以了。
+makeExample('cb-dynamic-form/ts/app/question.service.ts','','app/question.service.ts') +makeExample('cb-dynamic-form/ts/app/question.service.ts','','app/question.service.ts')
:marked :marked
Finally, we display an instance of the form in the `AppComponent` shell. Finally, we display an instance of the form in the `AppComponent` shell.
最后,我们在`AppComponent`里显示表单。 最后,我们在`AppComponent`里显示表单。
+makeExample('cb-dynamic-form/ts/app/app.component.ts','','app.component.ts') +makeExample('cb-dynamic-form/ts/app/app.component.ts','','app.component.ts')
@ -179,7 +180,7 @@ include ../_util-fns
Although in this example we're modelling a job application for heroes, there are no references to any specific hero question Although in this example we're modelling a job application for heroes, there are no references to any specific hero question
outside the objects returned by `QuestionService`. outside the objects returned by `QuestionService`.
虽然在这个例子中,我们是在为英雄工作申请表建模,但是除了`QuestionService`返回的对象外,没有其它任何地方有指定英雄问卷相关的内容 在这个例子中,虽然我们是在为英雄工作申请表建模,但是除了`QuestionService`返回的那些对象外,没有其它任何地方是与英雄有关的
This is very important since it allows us to repurpose the components for any type of survey This is very important since it allows us to repurpose the components for any type of survey
as long as it's compatible with our *question* object model. as long as it's compatible with our *question* object model.
@ -187,21 +188,21 @@ include ../_util-fns
without making any hardcoded assumptions about specific questions. without making any hardcoded assumptions about specific questions.
In addition to control metadata, we are also adding validation dynamically. In addition to control metadata, we are also adding validation dynamically.
这点非常重要,因为只要与我们的*问卷*对象模型兼容,我们可以为任何类型的调查问卷重复使用这些组件。 这点非常重要,因为只要与我们的*问卷*对象模型兼容,就可以在任何类型的调查问卷中复用这些组件。
关键是运用动态数据绑定的元数据来渲染表单,不对问卷问题有任何硬性的假设。除了控制器元数据外,我们还可以动态添加验证规则。 这里的关键是用到元数据的动态数据绑定来渲染表单,对问卷问题没有任何硬性的假设。除控件的元数据外,我们还可以动态添加验证规则。
The *Save* button is disabled until the form is in a valid state. The *Save* button is disabled until the form is in a valid state.
When the form is valid, we can click *Save* and the app renders the current form values as JSON. When the form is valid, we can click *Save* and the app renders the current form values as JSON.
This proves that any user input is bound back to the data model. This proves that any user input is bound back to the data model.
Saving and retrieving the data is an exercise for another time. Saving and retrieving the data is an exercise for another time.
表单验证通过之前,*保存*按钮是禁用的。当表单验证通过后,我们可以点击*保存*程序会把当前的值渲染成为Json 表单验证通过之前,*保存*按钮是禁用的。验证通过后,我们就可以点击*保存*按钮程序会把当前值渲染成JSON显示出来
它证明了任何用户输入都会被传到了数据模型里。如何储存和提取数据是另一话题 这表明任何用户输入都被传到了数据模型里。至于如何储存和提取数据则是另一话题了
:marked :marked
The final form looks like this: The final form looks like this:
完整表单看起来是这样: 完整表单看起来是这样
figure.image-display figure.image-display
img(src="/resources/images/cookbooks/dynamic-form/dynamic-form.png" alt="Dynamic-Form") img(src="/resources/images/cookbooks/dynamic-form/dynamic-form.png" alt="Dynamic-Form")

View File

@ -5,7 +5,7 @@ a(id='top')
Our app should be able to make the browser title bar say whatever we want it to say. Our app should be able to make the browser title bar say whatever we want it to say.
This cookbook explains how to do it. This cookbook explains how to do it.
应用程序应该能让浏览器标题栏显示我们想它显示的内容。本*烹饪书*解释怎么做。 应用程序应该能让浏览器标题栏显示我们想它显示的内容。本*烹饪书*解释怎么做。
:marked :marked
**See the [live example](/resources/live-examples/cb-set-document-title/ts/plnkr.html)**. **See the [live example](/resources/live-examples/cb-set-document-title/ts/plnkr.html)**.
@ -25,7 +25,7 @@ a(id='top')
The obvious approach is to bind a property of the component to the HTML `<title>` like this: The obvious approach is to bind a property of the component to the HTML `<title>` like this:
最显然的方法是绑定一个组件属性到HTML的`<title>`标签上,像这样: 显而易见的方法是把组件的属性绑定到HTML的`<title>`标签上,像这样:
code-example(format='') code-example(format='')
&lt;title&gt;{{This_Does_Not_Work}}&lt;/title&gt; &lt;title&gt;{{This_Does_Not_Work}}&lt;/title&gt;
@ -34,12 +34,12 @@ code-example(format='')
The root component of our application is an element contained within the `<body>` tag. The root component of our application is an element contained within the `<body>` tag.
The HTML `<title>` is in the document `<head>`, outside the body, making it inaccessible to Angular data binding. The HTML `<title>` is in the document `<head>`, outside the body, making it inaccessible to Angular data binding.
对不起,但是这样不行。我们应用程序的是一个被包含在`<body>`标签里的元素。该HTML`<title>`在文档的`<head>`元素里,在主体内容之外Angular的数据绑定无法访问它。 抱歉,这样不行。我们应用程序的根组件是一个包含在`<body>`标签里的元素。该HTML`<title>`在文档的`<head>`元素里,在`<body>`之外Angular的数据绑定无法访问到它。
We could grab the browser `document` object and set the title manually. We could grab the browser `document` object and set the title manually.
That's dirty and undermines our chances of running the app outside of a browser someday. That's dirty and undermines our chances of running the app outside of a browser someday.
我们可以得到浏览器的`document`对象,并且手动设置标题。但是这样不干净,并且我们无法在将来在浏览器之外运行应用程序。 我们可以得到浏览器的`document`对象,并且手动设置标题。但是这样看起来很脏,而且我们将无法在浏览器之外运行应用程序。
.l-sub-section .l-sub-section
:marked :marked
@ -48,8 +48,9 @@ code-example(format='')
inside a Web Worker to improve your app's responsiveness by using multiple threads. And it inside a Web Worker to improve your app's responsiveness by using multiple threads. And it
means that you could run your app inside Electron.js or Windows Universal to deliver it to the desktop. means that you could run your app inside Electron.js or Windows Universal to deliver it to the desktop.
在浏览器之外运行应用程序的意思是利用服务器端预先渲染实现几乎即时的第一应用程序渲染时间同时支持SEO搜索引擎优化。它意味着你可以在一个 在浏览器外运行应用程序意味着利用服务器端预先渲染为应用程序实现几乎实时的首次渲染同时还能支持SEO搜索引擎优化
Web Worker中运行你的应用程序通过使用多个线程增强应用程序的响应性。它还意味着你可以在Electron.js或者Windows Universal里面运行发布给桌面环境 意味着你可以在一个Web Worker中运行你的应用程序通过多线程技术增强应用程序的响应性。
还意味着你可以在Electron.js或者Windows Universal里面运行发布到桌面环境。
:marked :marked
## Use the *Title* service ## Use the *Title* service
@ -60,41 +61,41 @@ code-example(format='')
The [Title](../api/platform/browser/Title-class.html) service is a simple class that provides an API The [Title](../api/platform/browser/Title-class.html) service is a simple class that provides an API
for getting and setting the current HTML document title: for getting and setting the current HTML document title:
幸运的是Angular 2在*Browser platform*包中,提供了一个`Title`服务,桥接这个间隔 幸运的是Angular 2在*浏览器平台*的包中,提供了一个`Title`服务,弥补了这个差别
[Title](../api/platform/browser/Title-class.html)服务是一个简单提供了一个API用来获取和设置当前HTML文档的标题。 [Title](../api/platform/browser/Title-class.html)服务是一个简单提供了一个API用来获取和设置当前HTML文档的标题。
* `getTitle() : string` &mdash; Gets the title of the current HTML document. * `getTitle() : string` &mdash; Gets the title of the current HTML document.
*`getTitle():string` &mdash; 获取当前HTML文档的标题。 *`getTitle(): string` —— 获取当前HTML文档的标题。
* `setTitle( newTitle : string )` &mdash; Sets the title of the current HTML document. * `setTitle( newTitle : string )` &mdash; Sets the title of the current HTML document.
* `setTitle( newTitle: string)` &mdash; 设置当前HTML文档的标题。 * `setTitle( newTitle: string)` —— 设置当前HTML文档的标题。
While this class is part of the Browser platform package, it is *not part of the default Browser While this class is part of the Browser platform package, it is *not part of the default Browser
platform providers* that Angular loads automatically. platform providers* that Angular loads automatically.
This means as we bootstrap our application using the Browser platform `boostrap()` This means as we bootstrap our application using the Browser platform `boostrap()`
function, we'll also have to include `Title` service explicitly as one of the bootstrap providers: function, we'll also have to include `Title` service explicitly as one of the bootstrap providers:
虽然该类是Browser platform包的一部分它*不是*Angular自动默认装载的*Browser platform providers的一部分*。 虽然该类是浏览器平台包的一部分,但它*没有被*Angular加载为*浏览器平台上的默认服务供应商*。
这意味着,我们在使用Browser platform的`bootstrap()`函数来引导我们的应用程序时,我们必须要明确地把`Title`服务作为引导的供应商之一加入进来: 这意味着,我们在使用浏览器平台的`bootstrap()`函数来引导我们的应用程序时,我们必须要明确地把`Title`服务作为引导的供应商之一加入进来:
+makeExample( "cb-set-document-title/ts/app/main.ts", "bootstrap-title", "app/main.ts (provide Title service)" )(format='.') +makeExample( "cb-set-document-title/ts/app/main.ts", "bootstrap-title", "app/main.ts (provide Title service)" )(format='.')
:marked :marked
Once we've explicitly provided the `Title` service we can then inject the `Title` service into any of our Once we've explicitly provided the `Title` service we can then inject the `Title` service into any of our
custom application components and services. custom application components and services.
一旦我们明确提供了`Title`服务,我们就能把`Title`服务注入到任何一个应用程序内组件和服务里面。 一旦我们明确提供了`Title`服务,就能把`Title`服务注入到任何一个应用程序内组件和服务里面。
Let's inject the `Title` service into the root `AppComponent` and expose a bindable `setTitle` method that calls it: Let's inject the `Title` service into the root `AppComponent` and expose a bindable `setTitle` method that calls it:
让我们把`Title`服务注入到根`AppComponent`组件,并暴露可以绑定的`setTitle`方法来调用该服务: 我们来把`Title`服务注入到根组件`AppComponent`,并暴露出可供绑定的`setTitle`方法让别人来调用该服务:
+makeExample( "cb-set-document-title/ts/app/app.component.ts", "class", "app/app.component.ts (class)" )(format='.') +makeExample( "cb-set-document-title/ts/app/app.component.ts", "class", "app/app.component.ts (class)" )(format='.')
:marked :marked
We bind that method to three anchor tags and, voila! We bind that method to three anchor tags and, voila!
我们绑定这个方法到三个锚标签,瞧瞧! 我们把这个方法绑定到三个A标签,瞧瞧!
figure.image-display figure.image-display
img(src="/resources/images/cookbooks/set-document-title/set-title-anim.gif" alt="Set title") img(src="/resources/images/cookbooks/set-document-title/set-title-anim.gif" alt="Set title")
@ -121,16 +122,16 @@ figure.image-display
:marked :marked
## Why we provide the *Title* service in *bootstrap* ## Why we provide the *Title* service in *bootstrap*
## 我们为什么在*bootstrap*里面提供这个*Title*服务 ## 为什么我们要在*bootstrap*里面提供这个*Title*服务
We generally recommended providing application-wide services in the root application component, `AppComponent`. We generally recommended providing application-wide services in the root application component, `AppComponent`.
我们一般推荐在应用程序的根组件`AppComponent`提供应用程序全范围服务。 我们通常会推荐在应用程序的根组件`AppComponent`中提供应用程序级的服务。
Here we recommend registering the title service during bootstrapping, Here we recommend registering the title service during bootstrapping,
a location we reserve for configuring the runtime Angular enviroment. a location we reserve for configuring the runtime Angular enviroment.
这里,我们推荐在引导过程中注册这个标题服务一个我们为设置Angular运行环境而保留的地方 这里,我们推荐在引导过程中注册这个Title服务这个位置是我们为设置Angular运行环境而保留的
That's exactly what we're doing. That's exactly what we're doing.
The `Title` service is part of the Angular *browser platform*. The `Title` service is part of the Angular *browser platform*.
@ -138,7 +139,7 @@ figure.image-display
we'll have to provide a different `Title` service that understands the concept of a "document title" for that specific platform. we'll have to provide a different `Title` service that understands the concept of a "document title" for that specific platform.
Ideally the application itself neither knows nor cares about the runtime environment. Ideally the application itself neither knows nor cares about the runtime environment.
这正好是我们要做的。`Title`服务是Angular *browser platform*的一部分。如果我们在另一个不同的平台上引导我们的应用程序,我们将会提供一个不同的,专门为这个平台准备的`Title`服务。 我们的做法正是如此。这里的`Title`服务是Angular*浏览器平台*的一部分。如果我们在其它平台上引导应用程序,就得提供另一个专为那个平台准备的`Title`服务。
:marked :marked
[Back to top](#top) [Back to top](#top)

View File

@ -1948,7 +1948,7 @@ a(href="#toc") 回到顶部
:marked :marked
**Why?** Components are derived from Directives, and thus their selectors can be elements, attributes, or other selectors. Defining the selector as an element provides consistency for components that represent content with a template. **Why?** Components are derived from Directives, and thus their selectors can be elements, attributes, or other selectors. Defining the selector as an element provides consistency for components that represent content with a template.
**为何?**组件是从指令衍生的,所以它们的选择器可以是元素、特性或者其他选择器。把选择器作为元素来定义,统一了通过模块提供内容的组件。 **为何?**组件是从指令派生出来的,所以它们的选择器可以是元素、特性或者其他选择器。把选择器作为元素来定义,统一了通过模块提供内容的组件。
.s-why.s-why-last .s-why.s-why-last
:marked :marked
@ -2515,7 +2515,7 @@ a(href="#toc") 回到顶部
:marked :marked
**Do** use the `@Injectable` class decorator instead of the `@Inject` parameter decorator when using types as tokens for the dependencies of a service. **Do** use the `@Injectable` class decorator instead of the `@Inject` parameter decorator when using types as tokens for the dependencies of a service.
**坚持**当使用类型作为Token来注入服务的依赖时,使用`@Injectable`类装饰器,而非`@Inject`参数装饰器。 **坚持**当使用类型作为令牌来注入服务的依赖时,使用`@Injectable`类装饰器,而非`@Inject`参数装饰器。
.s-why .s-why
:marked :marked
@ -2527,7 +2527,7 @@ a(href="#toc") 回到顶部
:marked :marked
**Why?** When a service accepts only dependencies associated with type tokens, the `@Injectable()` syntax is much less verbose compared to using `@Inject()` on each individual constructor parameter. **Why?** When a service accepts only dependencies associated with type tokens, the `@Injectable()` syntax is much less verbose compared to using `@Inject()` on each individual constructor parameter.
**为何?**当服务只接受类型Token相关的依赖时,比起在每个构造函数参数上使用`@Inject()``@Injectable()`的语法简洁多了。 **为何?**当服务只接受类型令牌相关的依赖时,比起在每个构造函数参数上使用`@Inject()``@Injectable()`的语法简洁多了。
+makeExample('style-guide/ts/07-04/app/heroes/shared/hero-arena.service.avoid.ts', 'example', 'app/heroes/shared/hero-arena.service.ts')(avoid=1) +makeExample('style-guide/ts/07-04/app/heroes/shared/hero-arena.service.avoid.ts', 'example', 'app/heroes/shared/hero-arena.service.ts')(avoid=1)
:marked :marked