parent
dc5e87aad0
commit
8f01383b6c
File diff suppressed because it is too large
Load Diff
|
@ -3,25 +3,25 @@ include ../_util-fns
|
|||
: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.
|
||||
|
||||
有时候手动编写和维护表单需要工作量和时间过多。特别是需要编写大量的表单时,表单都非常类似,而且随着商务和政策需求的迅速变化,表单也需要随之变化,维护成本过高。
|
||||
有时候手动编写和维护表单所需工作量和时间会过大。特别是在需要编写大量表单时。表单都很相似,而且随着业务和监管需求的迅速变化,表单也要随之变化,这样维护的成本过高。
|
||||
|
||||
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.
|
||||
It's a primitive start.
|
||||
It might evolve to support a much richer variety of questions, more graceful rendering, and superior user experience.
|
||||
All such greatness has humble beginnings.
|
||||
|
||||
在此烹饪书中,我们会展示如何利用`ngFormModel`来动态渲染一个简单的表单,包括多种类型控制器和验证规则。
|
||||
这只是一个初级的开始,但是任何伟大都是从谦卑开始的。我们可以在这个基础上添加种类丰富的问卷问题,更加优美的渲染和更加优越的用户体验。
|
||||
在此烹饪书中,我们会展示如何利用`ngFormModel`来动态渲染一个简单的表单,包括各种控件类型和验证规则。
|
||||
这个起点很简陋,但我们可以在这个基础上添加丰富多彩的问卷问题、更优美的渲染以及更卓越的用户体验。
|
||||
|
||||
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.
|
||||
We can create the forms on the fly *without changing our application code*.
|
||||
|
||||
在本例中,我们使用动态表单,为正在找工作的英雄们创建一个在线申请问卷表。职业中介在不断的修改申请流程。我们可以在*不修改程序*的情况下,动态建立一个表格。
|
||||
在本例中,我们使用动态表单,为正在找工作的英雄们创建一个在线申请表。职介中心会不断修改申请流程,我们要在*不修改应用代码*的情况下,动态创建这些表单。
|
||||
|
||||
<a id="toc"></a>
|
||||
:marked
|
||||
|
@ -58,11 +58,11 @@ include ../_util-fns
|
|||
The hero application process involves a form with a lot of questions.
|
||||
The "question" is the most fundamental object in the model.
|
||||
|
||||
第一步是定义一个对象模型,用来描述所有表单功能需要的场景。英雄申请流程涉及到一个包含很多问卷问题的表单。问卷问题是最基础的对象模型。
|
||||
第一步是定义一个对象模型,用来描述所有表单功能需要的场景。英雄的申请流程涉及到一个包含很多问卷问题的表单。问卷问题是最基础的对象模型。
|
||||
|
||||
We have created `QuestionBase` as the most fundamental question class.
|
||||
|
||||
下面是我们建立的非常基础的问卷问题基础类,名叫`QuestionBase`。
|
||||
下面是我们建立的最基础的问卷问题基类,名叫`QuestionBase`。
|
||||
|
||||
+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.
|
||||
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`通过`type`属性,支持多种HTML5元素类型,比如文本、邮件、网址等。
|
||||
`TextboxQuestion`可以通过`type`属性来支持多种HTML5元素类型,比如文本、邮件、网址等。
|
||||
|
||||
+makeExample('cb-dynamic-form/ts/app/question-textbox.ts',null,'app/question-textbox.ts')(format='.')
|
||||
|
||||
:marked
|
||||
`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='.')
|
||||
|
||||
|
@ -89,8 +89,8 @@ include ../_util-fns
|
|||
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.
|
||||
|
||||
接下来,我们定义了`QuestionControlService`,一个可以把我们的问卷问题转换为ngForm控制群的服务。
|
||||
简而言之,这个ngForm控制群使用问卷模型的元数据,允许我们设置默认值和验证规则。
|
||||
接下来,我们定义了`QuestionControlService`,一个可以把我们的问卷问题转换为一组ngForm控件的服务。
|
||||
简而言之,这组ngForm控件使用问卷模型的元数据,并允许我们设置默认值和验证规则。
|
||||
|
||||
+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.
|
||||
|
||||
现在我们已经有一个已定义的完整模型了,我们可以开始创建一个动态表单的组件。
|
||||
现在我们已经有一个定义好的完整模型了,接着就可以开始创建一个展现动态表单的组件。
|
||||
|
||||
:marked
|
||||
`DynamicForm` is the entry point and the main container for the form.
|
||||
|
||||
`DynamicForm`是我们表单的主要载体和切入口。
|
||||
`DynamicForm`是我们表单的主要容器和入口点。
|
||||
|
||||
+makeTabs(
|
||||
`cb-dynamic-form/ts/app/dynamic-form.component.html,
|
||||
|
@ -120,8 +120,8 @@ include ../_util-fns
|
|||
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.
|
||||
|
||||
它代表了问卷问题列表,每个问题都在`<df-question>`组件元素之内。
|
||||
`<df-question>`标签是组件`DynamicFormQuestionComponent`,该组件的作用是根据每个问卷问题对象的值来动态渲染表单控制器。
|
||||
它代表了问卷问题列表,每个问题都被绑定到一个`<df-question>`组件元素。
|
||||
`<df-question>`标签匹配到的是组件`DynamicFormQuestionComponent`,该组件的职责是根据每个问卷问题对象的值来动态渲染表单控件。
|
||||
|
||||
+makeTabs(
|
||||
`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.
|
||||
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
|
||||
underlying control objects, populated from the question model with display and validation rules.
|
||||
|
||||
在两个组件中,我们依赖Angular的**ngFormModel**来把模板HTML链接到底层控制对象,该对象从问卷问题模型里获取渲染和验证规则。
|
||||
在这两个组件中,我们依赖Angular的**ngFormModel**来把模板HTML和底层控件对象连接起来,该对象从问卷问题模型里获取渲染和验证规则。
|
||||
|
||||
<a id="questionnaire-metadata"></a>
|
||||
:marked
|
||||
|
@ -150,24 +150,25 @@ include ../_util-fns
|
|||
:marked
|
||||
`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`.
|
||||
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`.
|
||||
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')
|
||||
|
||||
:marked
|
||||
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')
|
||||
|
||||
|
@ -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
|
||||
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
|
||||
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.
|
||||
In addition to control metadata, we are also adding validation dynamically.
|
||||
|
||||
这点非常重要,因为只要与我们的*问卷*对象模型兼容,我们可以为任何类型的调查问卷重复使用这些组件。
|
||||
关键是运用动态数据绑定的元数据来渲染表单,不对问卷问题有任何硬性的假设。除了控制器元数据外,我们还可以动态添加验证规则。
|
||||
这点非常重要,因为只要与我们的*问卷*对象模型兼容,就可以在任何类型的调查问卷中复用这些组件。
|
||||
这里的关键是用到元数据的动态数据绑定来渲染表单,对问卷问题没有任何硬性的假设。除控件的元数据外,我们还可以动态添加验证规则。
|
||||
|
||||
The *Save* button is disabled until the form is in a valid state.
|
||||
When the form is valid, we can click *Save* and the app renders the current form values as JSON.
|
||||
This proves that any user input is bound back to the data model.
|
||||
Saving and retrieving the data is an exercise for another time.
|
||||
|
||||
在表单的验证通过之前,*保存*按钮是禁用的。当表单验证通过后,我们可以点击*保存*,程序会把当前的值渲染成为Json。
|
||||
它证明了任何用户输入都会被传到了数据模型里。如何储存和提取数据是另一话题。
|
||||
表单验证通过之前,*保存*按钮是禁用的。验证通过后,我们就可以点击*保存*按钮,程序会把当前值渲染成JSON显示出来。
|
||||
这表明任何用户输入都被传到了数据模型里。至于如何储存和提取数据则是另一话题了。
|
||||
|
||||
:marked
|
||||
The final form looks like this:
|
||||
|
||||
完整表单看起来是这样:
|
||||
完整的表单看起来是这样的:
|
||||
|
||||
figure.image-display
|
||||
img(src="/resources/images/cookbooks/dynamic-form/dynamic-form.png" alt="Dynamic-Form")
|
||||
|
|
|
@ -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.
|
||||
This cookbook explains how to do it.
|
||||
|
||||
应用程序应该能让浏览器标题栏显示我们想要它显示的内容。本*烹饪书*解释怎么做。
|
||||
应用程序应该能让浏览器标题栏显示我们想让它显示的内容。本*烹饪书*解释怎么做。
|
||||
:marked
|
||||
**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:
|
||||
|
||||
最显然的方法是绑定一个组件属性到HTML的`<title>`标签上,像这样:
|
||||
显而易见的方法是把组件的属性绑定到HTML的`<title>`标签上,像这样:
|
||||
|
||||
code-example(format='')
|
||||
<title>{{This_Does_Not_Work}}</title>
|
||||
|
@ -34,12 +34,12 @@ code-example(format='')
|
|||
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.
|
||||
|
||||
对不起,但是这样不行。我们应用程序的是一个被包含在`<body>`标签里的元素。该HTML`<title>`在文档的`<head>`元素里,在主体内容之外,Angular的数据绑定无法访问它。
|
||||
抱歉,这样不行。我们应用程序的根组件是一个包含在`<body>`标签里的元素。该HTML的`<title>`在文档的`<head>`元素里,在`<body>`之外,Angular的数据绑定无法访问到它。
|
||||
|
||||
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.
|
||||
|
||||
我们可以得到浏览器的`document`对象,并且手动设置标题。但是这样不干净,并且我们无法在将来在浏览器之外运行应用程序。
|
||||
我们可以得到浏览器的`document`对象,并且手动设置标题。但是这样看起来很脏,而且我们将无法在浏览器之外运行应用程序。
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
|
@ -48,8 +48,9 @@ code-example(format='')
|
|||
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.
|
||||
|
||||
在浏览器之外运行应用程序的意思是:利用服务器端预先渲染,实现几乎即时的第一应用程序渲染时间,同时支持SEO(搜索引擎优化)。它意味着你可以在一个
|
||||
Web Worker中运行你的应用程序,通过使用多个线程增强应用程序的响应性。它还意味着你可以在Electron.js或者Windows Universal里面运行,发布给桌面(环境)。
|
||||
在浏览器外运行应用程序意味着:利用服务器端预先渲染,为应用程序实现几乎实时的首次渲染,同时还能支持SEO(搜索引擎优化)。
|
||||
意味着你可以在一个Web Worker中运行你的应用程序,通过多线程技术增强应用程序的响应性。
|
||||
还意味着你可以在Electron.js或者Windows Universal里面运行,发布到桌面环境。
|
||||
|
||||
:marked
|
||||
## 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
|
||||
for getting and setting the current HTML document title:
|
||||
|
||||
幸运的是,Angular 2在*Browser platform*包中,提供了一个`Title`服务,桥接这个间隔。
|
||||
[Title](../api/platform/browser/Title-class.html)服务是一个简单地类,提供了一个API,用来获取和设置当前HTML文档的标题。
|
||||
幸运的是,Angular 2在*浏览器平台*的包中,提供了一个`Title`服务,弥补了这个差别。
|
||||
[Title](../api/platform/browser/Title-class.html)服务是一个简单的类,提供了一个API,用来获取和设置当前HTML文档的标题。
|
||||
|
||||
* `getTitle() : string` — Gets the title of the current HTML document.
|
||||
|
||||
*`getTitle():string` — 获取当前HTML文档的标题。
|
||||
*`getTitle(): string` —— 获取当前HTML文档的标题。
|
||||
|
||||
* `setTitle( newTitle : string )` — Sets the title of the current HTML document.
|
||||
|
||||
* `setTitle( newTitle: string)` — 设置当前HTML文档的标题。
|
||||
* `setTitle( newTitle: string)` —— 设置当前HTML文档的标题。
|
||||
|
||||
While this class is part of the Browser platform package, it is *not part of the default Browser
|
||||
platform providers* that Angular loads automatically.
|
||||
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:
|
||||
|
||||
虽然该类是Browser platform包的一部分,它*不是*Angular自动默认装载的*Browser platform providers的一部分*。
|
||||
这意味着,我们在使用Browser platform的`bootstrap()`函数来引导我们的应用程序时,我们必须要明确地把`Title`服务作为引导的供应商之一加入进来:
|
||||
虽然该类是浏览器平台包的一部分,但它*没有被*Angular加载为*浏览器平台上的默认服务供应商*。
|
||||
这意味着,我们在使用浏览器平台的`bootstrap()`函数来引导我们的应用程序时,我们必须要明确地把`Title`服务作为引导期的供应商之一加入进来:
|
||||
|
||||
+makeExample( "cb-set-document-title/ts/app/main.ts", "bootstrap-title", "app/main.ts (provide Title service)" )(format='.')
|
||||
:marked
|
||||
Once we've explicitly provided the `Title` service we can then inject the `Title` service into any of our
|
||||
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:
|
||||
|
||||
让我们把`Title`服务注入到根`AppComponent`组件,并暴露可以绑定的`setTitle`方法来调用该服务:
|
||||
我们来把`Title`服务注入到根组件`AppComponent`,并暴露出可供绑定的`setTitle`方法让别人来调用该服务:
|
||||
|
||||
+makeExample( "cb-set-document-title/ts/app/app.component.ts", "class", "app/app.component.ts (class)" )(format='.')
|
||||
:marked
|
||||
We bind that method to three anchor tags and, voila!
|
||||
|
||||
我们绑定这个方法到三个锚标签,瞧瞧!
|
||||
我们把这个方法绑定到三个A标签,瞧瞧!
|
||||
|
||||
figure.image-display
|
||||
img(src="/resources/images/cookbooks/set-document-title/set-title-anim.gif" alt="Set title")
|
||||
|
@ -121,16 +122,16 @@ figure.image-display
|
|||
:marked
|
||||
## 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`.
|
||||
|
||||
我们一般推荐在应用程序的根组件`AppComponent`提供应用程序全范围服务。
|
||||
我们通常会推荐在应用程序的根组件`AppComponent`中提供应用程序级的服务。
|
||||
|
||||
Here we recommend registering the title service during bootstrapping,
|
||||
a location we reserve for configuring the runtime Angular enviroment.
|
||||
|
||||
这里,我们推荐在引导过程中注册这个标题服务,一个我们为设置Angular运行环境而保留的地方。
|
||||
但这里,我们推荐在引导过程中注册这个Title服务,这个位置是我们为设置Angular运行环境而保留的。
|
||||
|
||||
That's exactly what we're doing.
|
||||
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.
|
||||
Ideally the application itself neither knows nor cares about the runtime environment.
|
||||
|
||||
这正好是我们要做的。`Title`服务是Angular *browser platform*的一部分。如果我们在另一个不同的平台上引导我们的应用程序,我们将会提供一个不同的,专门为这个平台准备的`Title`服务。
|
||||
我们的做法正是如此。这里的`Title`服务是Angular*浏览器平台*的一部分。如果我们在其它平台上引导应用程序,就得提供另一个专为那个平台准备的`Title`服务。
|
||||
:marked
|
||||
[Back to top](#top)
|
||||
|
||||
|
|
|
@ -1948,7 +1948,7 @@ a(href="#toc") 回到顶部
|
|||
: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.
|
||||
|
||||
**为何?**组件是从指令衍生的,所以它们的选择器可以是元素、特性或者其他选择器。把选择器作为元素来定义,统一了通过模块提供内容的组件。
|
||||
**为何?**组件是从指令派生出来的,所以它们的选择器可以是元素、特性或者其他选择器。把选择器作为元素来定义,统一了通过模块提供内容的组件。
|
||||
|
||||
.s-why.s-why-last
|
||||
:marked
|
||||
|
@ -2515,7 +2515,7 @@ a(href="#toc") 回到顶部
|
|||
:marked
|
||||
**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
|
||||
:marked
|
||||
|
@ -2527,7 +2527,7 @@ a(href="#toc") 回到顶部
|
|||
: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.
|
||||
|
||||
**为何?**当服务只接受类型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)
|
||||
:marked
|
||||
|
|
Loading…
Reference in New Issue