| 
									
										
										
										
											2016-02-05 23:27:06 -08:00
										 |  |  |  | include ../_util-fns | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-09 17:38:25 +01:00
										 |  |  |  | .alert.is-important | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     This guide is still in the process of being updated to RC5 and it's samples | 
					
						
							|  |  |  |  |     may not work correctly. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-16 14:29:37 +01:00
										 |  |  |  |     我们正在为RC5更新本指南,目前本指南中的例子暂时不会正常运行。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   Having an existing Angular 1 application doesn't mean that we can't | 
					
						
							| 
									
										
										
										
											2016-02-26 18:21:31 +02:00
										 |  |  |  |   begin enjoying everything Angular 2 has to offer. That's because Angular 2 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   comes with built-in tools for migrating Angular 1 projects over to the | 
					
						
							|  |  |  |  |   Angular 2 platform. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 17:10:02 +01:00
										 |  |  |  |   已经有了一个Angular 1的程序并不表示我们就不能享受Angular 2提供的一切。 | 
					
						
							| 
									
										
										
										
											2016-09-17 11:46:17 +08:00
										 |  |  |  |   这是因为Angular 2带来了一些内置工具,来帮助我们把Angular 1的项目迁移到Angular 2平台。 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Some applications will be easier to upgrade than others, and there are | 
					
						
							|  |  |  |  |   ways in which we can make it easier for ourselves. It is possible to | 
					
						
							|  |  |  |  |   prepare and align Angular 1 applications with Angular 2 even before beginning | 
					
						
							|  |  |  |  |   the upgrade process. These preparation steps are all about making the code | 
					
						
							|  |  |  |  |   more decoupled, more maintainable, and up to speed with modern development | 
					
						
							|  |  |  |  |   tools. That means the preparation work will not only make the eventual upgrade | 
					
						
							|  |  |  |  |   easier, but will also generally improve our Angular 1 applications. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 17:10:02 +01:00
										 |  |  |  |   有些应用可能比其它的升级起来简单,还有一些方法能让把这项工作变得更简单。 | 
					
						
							|  |  |  |  |   即使在正式开始升级过程之前,我们可以准备Angular 1的程序,让它向Angular 2看齐。 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |   这些准备步骤几乎都是关于如何让代码更加松耦合、更有可维护性,以及用现代开发工具提高速度的。 | 
					
						
							|  |  |  |  |   这意味着,这种准备工作不仅能让最终的升级变得更简单,而且还能提升Angular 1程序的质量。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   One of the keys to a successful upgrade is to do it incrementally, | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   by running the two frameworks side by side in the same application, and | 
					
						
							|  |  |  |  |   porting Angular 1 components to Angular 2 one by one. This makes it possible | 
					
						
							|  |  |  |  |   to upgrade even large and complex applications without disrupting other | 
					
						
							|  |  |  |  |   business, because the work can be done collaboratively and spread over | 
					
						
							|  |  |  |  |   a period of time. The `upgrade` module in Angular 2 has been designed to | 
					
						
							|  |  |  |  |   make incremental upgrading seamless. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   成功升级的关键之一是增量式的实现它,通过在同一个应用中一起运行这两个框架,并且逐个把Angular 1的组件迁移到Angular 2中。 | 
					
						
							| 
									
										
										
										
											2016-06-07 17:10:02 +01:00
										 |  |  |  |   这意味着可以在不必打断其他业务的前提下,升级更大、更复杂的应用程序,因为这项工作可以多人协作完成,在一段时间内逐渐铺开。 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |   Angular 2 `upgrade`模块的设计目标就是让你渐进、无缝的完成升级。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   1. [Preparation](#preparation) | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |   1. [准备工作](#preparation) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |       1. [Following The Angular Style Guide](#following-the-angular-style-guide) | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |       1. [遵循Angular风格指南](#following-the-angular-style-guide) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |       2. [Using a Module Loader](#using-a-module-loader) | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |       2. [使用模块加载器](#using-a-module-loader) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |       3. [Migrating to TypeScript](#migrating-to-typescript) | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |       3. [迁移到TypeScript](#migrating-to-typescript) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |       4. [Using Component Directives](#using-component-directives) | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |       4. [使用组件型指令](#using-component-directives) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   2. [Upgrading with The Upgrade Adapter](#upgrading-with-the-upgrade-adapter) | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |   2. [通过升级适配器进行升级](#upgrading-with-the-upgrade-adapter) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |       1. [How The Upgrade Adapter Works](#how-the-upgrade-adapter-works) | 
					
						
							| 
									
										
										
										
											2016-06-07 17:10:02 +01:00
										 |  |  |  |       1. [如何升级适配器](#how-the-upgrade-adapter-works) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |       2. [Bootstrapping Hybrid Angular 1+2 Applications](#bootstrapping-hybrid-angular-1-2-applications) | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |       2. [引导Angular 1和2的混合(hybrid)应用](#bootstrapping-hybrid-angular-1-2-applications) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |       3. [Using Angular 2 Components from Angular 1 Code](#using-angular-2-components-from-angular-1-code) | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |       3. [从Angular 1的代码中使用Angular 2的组件](#using-angular-2-components-from-angular-1-code) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |       4. [Using Angular 1 Component Directives from Angular 2 Code](#using-angular-1-component-directives-from-angular-2-code) | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |       4. [从Angular 2的代码中使用Angular 1的组件](#using-angular-1-component-directives-from-angular-2-code) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |       5. [Projecting Angular 1 Content into Angular 2 Components](#projecting-angular-1-content-into-angular-2-components) | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |       5. [把Angular 1的内容投影(project)进Angular 2组件中](#projecting-angular-1-content-into-angular-2-components) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |       6. [Transcluding Angular 2 Content into Angular 1 Component Directives](#transcluding-angular-2-content-into-angular-1-component-directives) | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |       6. [把Angular 2的内容透传(transclude)到Angular 1的组件型指令中](#transcluding-angular-2-content-into-angular-1-component-directives) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |       7. [Making Angular 1 Dependencies Injectable to Angular 2](#making-angular-1-dependencies-injectable-to-angular-2) | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |       7. [让Angular 1提供的依赖可以被注入到Angular 2](#making-angular-1-dependencies-injectable-to-angular-2) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |       8. [Making Angular 2 Dependencies Injectable to Angular 1](#making-angular-2-dependencies-injectable-to-angular-1) | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |       8. [让Angular 2提供的依赖可以被注入到Angular 1](#making-angular-2-dependencies-injectable-to-angular-1) | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   3. [PhoneCat Upgrade Tutorial](#phonecat-upgrade-tutorial) | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |   3. [PhoneCat准备工作教程](#phonecat-preparation-tutorial) | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |       1. [Switching to TypeScript](#switching-to-typescript) | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |       1. [切换到TypeScript](#switching-to-typescript) | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |       2. [Installing Angular 2](#installing-angular-2) | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |       2. [安装Angular 2](#installing-angular-2) | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |       3. [Bootstrapping A Hybrid 1+2 PhoneCat](#bootstrapping-a-hybrid-1-2-phonecat) | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |       3. [引导Angular 1+2的混合版PhoneCat](#bootstrapping-a-hybrid-1-2-phonecat) | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |       4. [Upgrading the Phone service](#upgrading-the-phone-service) | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |       4. [升级Phone服务](#upgrading-the-phone-service) | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |       5. [Upgrading Components](#upgrading-components) | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |       5. [升级组件](#upgrading-components) | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |       6. [Switching To The Angular 2 Router And Bootstrap](#switching-to-the-angular-2-router-and-bootstrap) | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |       6. [切换到Angular 2的路由器并引导](#switching-to-the-angular-2-router-and-bootstrap) | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |       7. [Saying Goodbye to Angular 1](#saying-goodbye-to-angular-1) | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |       7. [再见,Angular 1!](#saying-goodbye-to-angular-1) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | .l-main-section | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   # Preparation | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |   # 准备工作 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   There are many ways to structure Angular 1 applications. When we begin | 
					
						
							|  |  |  |  |   to upgrade these applications to Angular 2, some will turn out to be | 
					
						
							|  |  |  |  |   much more easy to work with than others. There are a few key techniques | 
					
						
							|  |  |  |  |   and patterns that we can apply to future proof our apps even before we | 
					
						
							|  |  |  |  |   begin the migration. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   Angular 1应用程序的组织方式有很多种。当我们想把它们升级到Angular 2的时候, | 
					
						
							|  |  |  |  |   有些做起来会比其它的更容易些。即使在我们开始升级之前,也有一些关键的技术和模式可以让我们将来升级时更轻松。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   ## Following The Angular Style Guide | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   ## 遵循Angular风格指南 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   The [Angular 1 Style Guide](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#single-responsibility) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   collects patterns and practices that have been proven to result in | 
					
						
							|  |  |  |  |   cleaner and more maintainable Angular 1 applications. It contains a wealth | 
					
						
							|  |  |  |  |   of information about how to write and organize Angular code - and equally | 
					
						
							|  |  |  |  |   importantly - how **not** to write and organize Angular code. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 17:10:02 +01:00
										 |  |  |  |   [Angular风格指南](https://github.com/johnpapa/angular-styleguide)收集了一些已证明能写出干净且可维护的Angular 1程序的模式与实践。 | 
					
						
							|  |  |  |  |   它包含了很多关于如何书写和组织Angular代码的有价值信息,同样重要的是,**不应该**采用的书写和组织Angular代码的方式。 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Angular 2 is a reimagined version of the best parts of Angular 1. In that | 
					
						
							|  |  |  |  |   sense, its goals are the same as the Angular Style Guide's: To preserve | 
					
						
							|  |  |  |  |   the good parts of Angular 1, and to avoid the bad parts. There's a lot | 
					
						
							|  |  |  |  |   more to Angular 2 than just that of course, but this does mean that | 
					
						
							|  |  |  |  |   *following the style guide helps make your Angular 1 app more closely | 
					
						
							|  |  |  |  |   aligned with Angular 2*. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   Angular 2是一个基于Angular 1中最好的部分构思出来的版本。在这种意义上,它的目标和Angular风格指南是一样的: | 
					
						
							|  |  |  |  |   保留Angular 1中好的部分,去掉坏的部分。当然,Angular 2还做了更多。 | 
					
						
							| 
									
										
										
										
											2016-06-07 17:10:02 +01:00
										 |  |  |  |   说这些的意思是:*遵循这个风格指南可以让你写出更接近Angular 2程序的Angular 1程序*。 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   There are a few rules in particular that will make it much easier to do | 
					
						
							|  |  |  |  |   *an incremental upgrade* using the Angular 2 `upgrade` module: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   特别是某些规则会让使用Angular 2的`upgrade`模块进行*增量升级*变得更简单: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-20 22:17:09 -07:00
										 |  |  |  |   * The [Rule of 1](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#single-responsibility) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |     states that there should be one component per file. This not only makes | 
					
						
							|  |  |  |  |     components easy to navigate and find, but will also allow us to migrate | 
					
						
							|  |  |  |  |     them between languages and frameworks one at a time. In this example application, | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |     each controller, component, service, and filter is in its own source file. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 17:10:02 +01:00
										 |  |  |  |   * [单一规则](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#single-responsibility) | 
					
						
							|  |  |  |  |     规定每个文件应该只放一个组件。这不仅让组件更容易浏览和查找,而且还将允许我们逐个迁移它们的语言和框架。 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |     在这个范例程序中,每个控制器、工厂和过滤器都在它自己的源文件中。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-20 22:17:09 -07:00
										 |  |  |  |   * The [Folders-by-Feature Structure](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#folders-by-feature-structure) | 
					
						
							|  |  |  |  |     and [Modularity](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#modularity) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |     rules define similar principles on a higher level of abstraction: Different parts of the | 
					
						
							|  |  |  |  |     application should reside in different directories and Angular modules. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 17:10:02 +01:00
										 |  |  |  |   * [按特性分目录的结构](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#folders-by-feature-structure)和[模块化](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#modularity)规则在较高的抽象层定义了一些相似的原则:应用程序中的不同部分应该被分到不同的目录和Angular模块中。 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   When an application is laid out feature per feature in this way, it can also be | 
					
						
							|  |  |  |  |   migrated one feature at a time. For applications that don't already look like | 
					
						
							|  |  |  |  |   this, applying the rules in the Angular style guide is a highly recommended | 
					
						
							|  |  |  |  |   preparation step. And this is not just for the sake of the upgrade - it is just | 
					
						
							|  |  |  |  |   solid advice in general! | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   如果应用程序能用这种方式把每个特性分到一个独立目录中,它也就能每次迁移一个特性。 | 
					
						
							|  |  |  |  |   对于那些还没有这么做的程序,强烈建议把应用这条规则作为准备步骤。而且这也不仅仅对升级有价值, | 
					
						
							|  |  |  |  |   它还是一个通用的规则,可以让你的程序更“坚实”。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   ## Using a Module Loader | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   ## 使用模块加载器 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   When we break application code down into one component per file, we often end | 
					
						
							|  |  |  |  |   up with a project structure with a large number of relatively small files. This is | 
					
						
							|  |  |  |  |   a much neater way to organize things than a small number of large files, but it | 
					
						
							|  |  |  |  |   doesn't work that well if you have to load all those files to the HTML page with | 
					
						
							| 
									
										
										
										
											2016-06-02 01:54:54 +02:00
										 |  |  |  |   <script> tags. Especially when you also have to maintain those tags in the correct | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   order. That's why it's a good idea to start using a *module loader*. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   当我们把应用代码分解成每个文件中放一个组件之后,我们通常会得到一个由大量相对较小的文件组成的项目结构。 | 
					
						
							| 
									
										
										
										
											2016-06-07 17:10:02 +01:00
										 |  |  |  |   这比组织成少量大文件要整洁得多,但如果你不得不通过`<script>`标签在HTML页面中加载所有这些文件,那就不好玩了。 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   尤其是当你不得不按正确的顺序维护这些标签时更是如此。 | 
					
						
							|  |  |  |  |   这就是为什么开始使用*模块加载器*是一个好主意了。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Using a module loader such as [SystemJS](https://github.com/systemjs/systemjs), | 
					
						
							|  |  |  |  |   [Webpack](http://webpack.github.io/), or [Browserify](http://browserify.org/) | 
					
						
							|  |  |  |  |   allows us to use the built-in module systems of the TypeScript or ES2015 languages in our apps. | 
					
						
							|  |  |  |  |   We can use the `import` and `export` features that explicitly specify what code can | 
					
						
							|  |  |  |  |   and will be shared between different parts of the application. For ES5 applications | 
					
						
							|  |  |  |  |   we can use CommonJS style `require` and `module.exports` features. In both cases, | 
					
						
							|  |  |  |  |   the module loader will then take care of loading all the code the application needs | 
					
						
							|  |  |  |  |   in the correct order. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   使用模块加载器,比如[SystemJS](https://github.com/systemjs/systemjs)、 | 
					
						
							|  |  |  |  |   [Webpack](http://webpack.github.io/)或[Browserify](http://browserify.org/), | 
					
						
							|  |  |  |  |   可以让我们在程序中使用TypeScript或ES2015语言内置的模块系统。 | 
					
						
							|  |  |  |  |   我们可以使用`import`和`export`特性来明确指定哪些代码应该以及将会被在程序的不同部分之间共享。 | 
					
						
							|  |  |  |  |   对于ES5程序来说,我们可以改用CommonJS风格的`require`和`module.exports`特性代替。 | 
					
						
							|  |  |  |  |   无是论哪种情况,模块加载器都会按正确的顺序加载程序中用到的所有代码。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   When we then take our applications into production, module loaders also make it easier | 
					
						
							|  |  |  |  |   to package them all up into production bundles with batteries included. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   当我们的应用程序投入生产环境时,模块加载器也会让把所有这些文件打成完整的产品包变得更容易。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Migrating to TypeScript | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   ## 迁移到TypeScript | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   If part of our Angular 2 upgrade plan is to also take TypeScript into use, it makes | 
					
						
							|  |  |  |  |   sense to bring in the TypeScript compiler even before the upgrade itself begins. | 
					
						
							|  |  |  |  |   This means there's one less thing to learn and think about during the actual upgrade. | 
					
						
							|  |  |  |  |   It also means we can start using TypeScript features in our Angular 1 code. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   Angular 2升级计划的一部分是引入TypeScript,即使在开始升级之前,引入TypeScript编译器也是有意义的。 | 
					
						
							|  |  |  |  |   这意味着等真正升级的时候需要学习和思考的东西更少。 | 
					
						
							|  |  |  |  |   它还意味着我们可以在Angular 1代码中开始使用TypeScript的特性。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Since TypeScript is a superset of ECMAScript 2015, which in turn is a superset | 
					
						
							|  |  |  |  |   of ECMAScript 5, "switching" to TypeScript doesn't necessarily require anything | 
					
						
							|  |  |  |  |   more than installing the TypeScript compiler and switching renaming files from | 
					
						
							|  |  |  |  |   `*.js` to `*.ts`. But just doing that is not hugely useful or exciting, of course. | 
					
						
							|  |  |  |  |   Additional steps like the following can give us much more bang for the buck: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   因为TypeScript是ECMAScript 2015的一个超集,而ES2015又是ECMAScript 5的一个超集。 | 
					
						
							|  |  |  |  |   这意味着除了安装一个TypeScript编译器,并把文件名都从`*.js`改成`*.ts`之外,其实什么都不用做。 | 
					
						
							|  |  |  |  |   当然,如果仅仅这样做也没什么大用,也没什么令人兴奋之处。 | 
					
						
							| 
									
										
										
										
											2016-06-07 17:10:02 +01:00
										 |  |  |  |   下面这些额外步骤可以让我们精神抖擞起来: | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * For applications that use a module loader, TypeScript imports and exports | 
					
						
							|  |  |  |  |     (which are really ECMAScript 2015 imports and exports) can be used to organize | 
					
						
							|  |  |  |  |     code into modules. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * 对那些使用了模块加载器的程序,TypeScript的导入和导出(这实际上是ECMAScript 2015导入和导出)可以把代码组织到模块中。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * Type annotations can be gradually added to existing functions and variables | 
					
						
							|  |  |  |  |     to pin down their types and get benefits like build-time error checking, | 
					
						
							|  |  |  |  |     great autocompletion support and inline documentation. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * 类型注解可以逐步添加到已存在的函数和变量上,以固定它们的类型,并获得其优点:比如编译期错误检查、更好的支持自动完成,以及内联式文档等。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   * 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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   * 那些ES2015中新增的特性,比如箭头函数、`let`、`const`、默认函数参数、解构赋值等也能逐渐添加进来,让代码更有表现力。 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * Services and controllers can be turned into *classes*. That way they'll be a step | 
					
						
							|  |  |  |  |     closer to becoming Angular 2 service and component classes, which will make our | 
					
						
							|  |  |  |  |     life easier once we do the upgrade. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   * 服务和控制器可以转成*类*。这样我们就能一步步接近Angular 2的服务和组件类了,这样等到我们开始升级时,也会更简单。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   ## Using Component Directives | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   ## 使用组件型指令 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   In Angular 2, components are the main primitive from which user interfaces | 
					
						
							|  |  |  |  |   are built. We define the different parts of our UIs as components, and then | 
					
						
							|  |  |  |  |   compose the UI by using components in our templates. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   在Angular 2中,组件是用来构建用户界面的主要元素。我们把UI中的不同部分定义成组件,然后通过在模板中使用这些组件最终合成为UI。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   You can also do this in Angular 1, using *component directives*. These are | 
					
						
							|  |  |  |  |   directives that define their own templates, controllers, and input/output bindings - | 
					
						
							|  |  |  |  |   the same things that Angular 2 components define. Applications built with | 
					
						
							|  |  |  |  |   component directives are much easier to migrate to Angular 2 than applications | 
					
						
							|  |  |  |  |   built with lower-level features like `ng-controller`,  `ng-include`, and scope | 
					
						
							|  |  |  |  |   inheritance. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   我们在Angular 1中也能这么做。那就是一种定义了自己的模板、控制器和输入/输出绑定的指令 —— 跟Angular 2中对组件的定义是一样的。 | 
					
						
							|  |  |  |  |   要迁移到Angular 2,通过组件型指令构建的应用程序会比直接用`ng-controller`、`ng-include`和作用域继承等底层特性构建的要容易得多。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   To be Angular 2 compatible, an Angular 1 component directive should configure | 
					
						
							|  |  |  |  |   these attributes: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 17:10:02 +01:00
										 |  |  |  |   要与Angular 2兼容,Angular 1的组件型指令应该配置下列属性: | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * `restrict: 'E'`. Components are usually used as elements. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * `restrict: 'E'`。组件通常会以元素的方式使用。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * `scope: {}` - an isolate scope. In Angular 2, components are always isolated | 
					
						
							|  |  |  |  |     from their surroundings, and we should do this in Angular 1 too. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * `scope: {}` - 一个独立作用域。在Angular 2中,组件永远是从它们的环境中被隔离出来的,在Angular 1中,我们也应该这么做。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * `bindToController: {}`. Component inputs and outputs should be bound | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |     to the controller instead of using the `$scope`. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * `bindToController: {}`。组件的输入和输出应该绑定到控制器,而不是`$scope`。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * `controller` and `controllerAs`. Components have their own controllers. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * `controller`和`controllerAs`。组件有它们自己的控制器。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * `template` or `templateUrl`. Components have their own templates. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   * `template`或`templateUrl`。组件有它们自己的模板。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Component directives may also use the following attributes: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   组件型指令还可能使用下列属性: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * `transclude: true`, if the component needs to transclude content from elsewhere. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * `transclude: true`:如果组件需要从其它地方透传内容,就设置它。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * `require`, if the component needs to communicate with some parent component's | 
					
						
							|  |  |  |  |     controller. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   * `require`:如果组件需要和父组件的控制器通讯,就设置它。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Component directives **may not** use the following attributes: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   组件型指令**不能**使用下列属性: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * `compile`. This will not be supported in Angular 2. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * `compile`。它在Angular 2中将不再被支持。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * `replace: true`. Angular 2 never replaces a component element with the | 
					
						
							|  |  |  |  |     component template. This attribute is also deprecated in Angular 1. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * `replace: true`。Angular永远不会用组件模板替换一个组件元素。这个特性在Angular 1中也同样不建议使用了。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * `priority` and `terminal`. While Angular 1 components may use these, | 
					
						
							|  |  |  |  |     they are not used in Angular 2 and it is better not to write code | 
					
						
							|  |  |  |  |     that relies on them. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   * `priority`和`terminal`。虽然Angular 1的组件可能使用这些,但它们在Angular 2中已经没用了,并且最好不要再写依赖它们的代码。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   An Angular 1 component directive that is fully aligned with the Angular 2 | 
					
						
							|  |  |  |  |   architecture may look something like this: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   Angular 1中一个完全向Angular 2架构看齐过的组件型指令看起来有点像这样: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/hero-detail.directive.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   Angular 1.5 introduces the [component API](https://docs.angularjs.org/api/ng/type/angular.Module) | 
					
						
							|  |  |  |  |   that makes it easier to define directives like these. It is a good idea to use | 
					
						
							|  |  |  |  |   this API for component directives for several reasons: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   Angular 1.5引入了[组件API](https://docs.angularjs.org/api/ng/type/angular.Module),它让像这样定义指令变得更简单了。 | 
					
						
							|  |  |  |  |   为组件型指令使用这个API是一个好主意,因为: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * It requires less boilerplate code. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * 它需要更少的样板代码。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * It enforces the use of component best practices like `controllerAs`. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * 它强制使用组件的最佳实践,比如`controllerAs`。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   * It has good default values for directive attributes like `scope` and `restrict`. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   * 对于指令中像`scope`和`restrict`这样的属性,它有良好的默认值。 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   The component directive example from above looks like this when expressed | 
					
						
							|  |  |  |  |   using the component API: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   如果使用这个组件API进行快捷定义,那么上面看到的组件型指令就变成了这样: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/upgrade-io/hero-detail.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   Controller lifecycle hook methods `$onInit()`, `$onDestroy()`, and `$onChanges()` | 
					
						
							|  |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   控制器的生命周期钩子`$onInit()`、`$onDestroy()`和`$onChanges()`是Angular 1.5引入的另一些便利特性。 | 
					
						
							|  |  |  |  |   它们都很接近于[Angular 2中的等价物](lifecycle-hooks.html),所以,围绕它们组织组件生命周期的逻辑会更容易升级。 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | .l-main-section | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   # Upgrading with The Upgrade Adapter | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   # 使用升级适配器进行升级 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-19 17:13:38 +00:00
										 |  |  |  |   The `upgrade` module in Angular 2 is a very useful tool for upgrading | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   anything but the smallest of applications. With it we can mix and match | 
					
						
							|  |  |  |  |   Angular 1 and 2 components in the same application and have them interoperate | 
					
						
							|  |  |  |  |   seamlessly. That means we don't have to do the upgrade work all at once, | 
					
						
							|  |  |  |  |   since there's a natural coexistence between the two frameworks during the | 
					
						
							|  |  |  |  |   transition period. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   不管要升级什么,Angular 2中的`upgrade`模块都会是一个非常有用的工具 —— 除非是小到没功能的应用。 | 
					
						
							|  |  |  |  |   借助它,我们可以在同一个应用程序中混用并匹配Angular 1和2的组件,并让它们实现无缝的互操作。 | 
					
						
							|  |  |  |  |   这意味着我们不用必须一次性做完所有升级工作,因为在整个演进过程中,这两个框架可以很自然的和睦相处。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   ## How The Upgrade Adapter Works | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   ## 升级适配器如何工作 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   The primary tool provided by the upgrade module is called the `UpgradeAdapter`. | 
					
						
							|  |  |  |  |   This is a service that can bootstrap and manage hybrid applications that support | 
					
						
							|  |  |  |  |   both Angular 2 and Angular 1 code. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   `upgrade`模块提供的主要工具叫做`UpgradeAdapter`。这是一个服务,它可以引导并管理同时支持Angular 2和Angular 1的混合式应用程序。 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   When we use `UpgradeAdapter`, what we're really doing is *running both versions | 
					
						
							|  |  |  |  |   of Angular at the same time*. All Angular 2 code is running in the Angular 2 | 
					
						
							|  |  |  |  |   framework, and Angular 1 code in the Angular 1 framework. Both of these are the | 
					
						
							|  |  |  |  |   actual, fully featured versions of the frameworks. There is no emulation going on, | 
					
						
							|  |  |  |  |   so we can expect to have all the features and natural behavior of both frameworks. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   当使用`UpgradeAdapter`时,我们实际做的是*同时运行两个版本的Angular*。所有Angular 2的代码运行在Angular 2框架中, | 
					
						
							|  |  |  |  |   而Angular 1的代码运行在Angular 1框架中。所有这些都是真实的、全功能的框架版本。 | 
					
						
							|  |  |  |  |   没有进行任何仿真,所以我们可以期待同时存在这两个框架的所有特性和天生的行为。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   What happens on top of this is that components and services managed by one | 
					
						
							|  |  |  |  |   framework can interoperate with those from the other framework. This happens | 
					
						
							|  |  |  |  |   in three main areas: Dependency injection, the DOM, and change detection. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   所有这些事情的背后,本质上是一个框架中管理的组件和服务能和来自另一个中的进行互操作。 | 
					
						
							|  |  |  |  |   这发生在三个主要的领域:依赖注入、DOM和变更检测。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   ### Dependency Injection | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   ### 依赖注入 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   Dependency injection is front and center in both Angular 1 and | 
					
						
							|  |  |  |  |   Angular 2, but there are some key differences between the two | 
					
						
							|  |  |  |  |   frameworks in how it actually works. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   无论是在Angular 1中还是在Angular 2中,依赖注入都处于前沿和中心的位置,但在两个框架的工作原理上,却存在着一些关键的不同之处。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | table | 
					
						
							|  |  |  |  |   tr | 
					
						
							|  |  |  |  |     th Angular 1 | 
					
						
							|  |  |  |  |     th Angular 2 | 
					
						
							|  |  |  |  |   tr | 
					
						
							|  |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         Dependency injection tokens are always strings | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         依赖注入的令牌(Token)永远是字符串(译注:指服务名称)。 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         Tokens [can have different types](../guide/dependency-injection.html). | 
					
						
							|  |  |  |  |         They are often classes. They may also be strings. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         令牌[可能有不同的类型](../guide/dependency-injection.html)。 | 
					
						
							|  |  |  |  |         通常是类,也可能是字符串。 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   tr | 
					
						
							|  |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         There is exactly one injector. Even in multi-module applications, | 
					
						
							|  |  |  |  |         everything is poured into one big namespace. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         只有一个注入器。即使在多模块的应用程序中,每样东西也都被装入一个巨大的命名空间中。 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         There is a [tree hierarchy of injectors](../guide/hierarchical-dependency-injection.html), | 
					
						
							|  |  |  |  |         with a root injector and an additional injector for each component. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |         有一组[树状多层注入器](../guide/hierarchical-dependency-injection.html),有一个根注入器,每个组件也有一个额外的注入器。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   Even accounting for these differences we can still have dependency injection | 
					
						
							|  |  |  |  |   interoperability. The `UpgradeAdapter` resolves the differences and makes | 
					
						
							|  |  |  |  |   everything work seamlessly: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   就算有这么多不同点,也并不妨碍我们在依赖注入时进行互操作。`UpgradeAdapter`解决了这些差异,并让它们无缝的对接: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * We can make Angular 1 services available for injection to Angular 2 code | 
					
						
							|  |  |  |  |     by *upgrading* them. The same singleton instance of each service is shared | 
					
						
							|  |  |  |  |     between the frameworks. In Angular 2 these services will always be in the | 
					
						
							|  |  |  |  |     *root injector* and available to all components. They will always have | 
					
						
							|  |  |  |  |     *string tokens* - the same tokens that they have in Angular 1. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * 通过升级它们,我们就能让那些在Angular 1中能被注入的服务在Angular 2的代码中可用。 | 
					
						
							|  |  |  |  |     在框架之间共享的是服务的同一个单例对象。在Angular 2中,这些外来服务总是被放在*根注入器*中,并可用于所有组件。 | 
					
						
							|  |  |  |  |     它们总是具有*字符串令牌* —— 跟它们在Angular 1中的令牌相同。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * We can also make Angular 2 services available for injection to Angular 1 code | 
					
						
							|  |  |  |  |     by *downgrading* them. Only services from the Angular 2 root injector can | 
					
						
							|  |  |  |  |     be downgraded. Again, the same singleton instances are shared between the frameworks. | 
					
						
							|  |  |  |  |     When we register a downgrade, we explicitly specify a *string token* that we want to | 
					
						
							|  |  |  |  |     use in Angular 1. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   * 通过降级它们,我们也能让那些在Angular 2中能被注入的服务在Angular 1的代码中可用。 | 
					
						
							|  |  |  |  |     只有那些来自Angular 2根注入器的服务才能被降级。同样的,在框架之间共享的是同一个单例对象。 | 
					
						
							|  |  |  |  |     当我们注册一个要降级的服务时,要明确指定一个打算在Angular 1中使用的*字符串令牌*。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | figure.image-display | 
					
						
							|  |  |  |  |   img(src="/resources/images/devguide/upgrade/injectors.png" alt="The two injectors in a hybrid application" width="700") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ### Components and the DOM | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   ### 组件与DOM | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   What we'll find in the DOM of a hybrid application are components and | 
					
						
							|  |  |  |  |   directives from both Angular 1 and Angular 2. These components | 
					
						
							|  |  |  |  |   communicate with each other by using the input and output bindings | 
					
						
							|  |  |  |  |   of their respective frameworks, which the `UpgradeAdapter` bridges | 
					
						
							|  |  |  |  |   together. They may also communicate through shared injected dependencies, | 
					
						
							|  |  |  |  |   as described above. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   在混合式应用中,我们能同时发现那些来自Angular 1和Angular 2中组件和指令的DOM。 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   这些组件通过它们各自框架中的输入和输出绑定来互相通讯,它们由`UpgradeAdapter`桥接在一起。 | 
					
						
							|  |  |  |  |   它们也能通过共享被注入的依赖彼此通讯,就像前面所说的那样。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   There are two key things to understand about what happens in the DOM | 
					
						
							|  |  |  |  |   of a hybrid application: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   要弄明白在一个混合式应用的DOM中发生了什么,有两点很关键: | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   1. Every element in the DOM is owned by exactly one of the two | 
					
						
							|  |  |  |  |      frameworks. The other framework ignores it. If an element is | 
					
						
							|  |  |  |  |      owned by Angular 1, Angular 2 treats it as if it didn't exist, | 
					
						
							|  |  |  |  |      and vice versa. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   1. DOM中的每个元素都只能被两个框架之一拥有。另一个框架会忽略它。 | 
					
						
							|  |  |  |  |      如果一个元素被Angular 1拥有,Angular 2就会当它不存在。反之亦然。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   2. The root of the application *is always an Angular 1 template*. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   2. 应用的根节点*总是来自Angular 1中的模板*。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   So a hybrid application begins life as an Angular 1 application, | 
					
						
							|  |  |  |  |   and it is Angular 1 that processes its root template. Angular 2 then steps | 
					
						
							|  |  |  |  |   into the picture when an Angular 2 component is used somewhere in | 
					
						
							|  |  |  |  |   the application templates. That component's view will then be managed | 
					
						
							|  |  |  |  |   by Angular 2, and it may use any number of Angular 2 components and | 
					
						
							|  |  |  |  |   directives. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   所以,混合式应用总是像Angular 1程序那样启动,处理根模板的也是Angular 1. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   然后,当这个应用的模板中使用到了Angular 2的组件时,Angular 2才开始参与。 | 
					
						
							|  |  |  |  |   这个组件的视图由Angular 2进行管理,而且它还可以使用一系列的Angular 2组件和指令。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Beyond that, we may interleave the two frameworks as much as we need to. | 
					
						
							|  |  |  |  |   We always cross the boundary between the two frameworks by one of two | 
					
						
							|  |  |  |  |   ways: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   更进一步说,我们可以按照需要,任意穿插使用这两个框架。 | 
					
						
							|  |  |  |  |   使用下面的两种方式之一,我们可以自由穿梭于这两个框架的边界: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   1. By using a component from the other framework: An Angular 1 template | 
					
						
							|  |  |  |  |      using an Angular 2 component, or an Angular 2 template using an | 
					
						
							|  |  |  |  |      Angular 1 component. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   1. 通过使用来自另一个框架的组件:Angular 1的模板中用到了Angular 2的组件,或者Angular 2的模板中使用了Angular 1的组件。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   2. By transcluding or projecting content from the other framework. The | 
					
						
							|  |  |  |  |     `UpgradeAdapter` bridges the related concepts of  Angular 1 transclusion | 
					
						
							|  |  |  |  |      and Angular 2 content projection together. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   2. 通过透传(transclude)或投影(project)来自另一个框架的内容。`UpgradeAdapter`牵线搭桥,把Angular 1的透传概念和Angular 2的内容投影概念关联起来。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | figure.image-display | 
					
						
							|  |  |  |  |  img(src="/resources/images/devguide/upgrade/dom.png" alt="DOM element ownership in a hybrid application" width="500") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   Whenever we use a component that belongs to the other framework, a | 
					
						
							|  |  |  |  |   switch between framework boundaries occurs. However, that switch only | 
					
						
							|  |  |  |  |   happens to the *children* of the component element. Consider a situation | 
					
						
							|  |  |  |  |   where we use an Angular 2 component from Angular 1 like this: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   无论什么时候,只要我们用到了来自另一个框架的组件,就会发生框架边界的切换。然而,这种切换只会发生在组件元素的*子节点*上。 | 
					
						
							|  |  |  |  |   考虑一个场景,我们从Angular 1中像这样使用Angular 2的组件: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   ``` | 
					
						
							|  |  |  |  |   <ng2-component></ng2-component> | 
					
						
							|  |  |  |  |   ``` | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   The DOM element `<ng2-component>` will remain to be an Angular 1 managed | 
					
						
							|  |  |  |  |   element, because it's defined in an Angular 1 template. That also | 
					
						
							|  |  |  |  |   means you can apply additional Angular 1 directives to it, but *not* | 
					
						
							|  |  |  |  |   Angular 2 directives. It is only in the template of the `Ng2Component` | 
					
						
							|  |  |  |  |   component where Angular 2 steps in. This same rule also applies when you | 
					
						
							|  |  |  |  |   use Angular 1 component directives from Angular 2. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   此时,`<ng2-component>`这个DOM元素仍然由Angular 1管理,因为它是在Angular 1的模板中定义的。 | 
					
						
							|  |  |  |  |   这也意味着你可以往它上面添加额外的Angular 1指令,却*不能*添加Angular 2的指令。 | 
					
						
							|  |  |  |  |   只有在`Ng2Component`组件的模板中才是Angular 2的天下。同样的规则也适用于在Angular 2中使用Angular 1组件型指令的情况。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   ### Change Detection | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   ### 变更检测 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   Change detection in Angular 1 is all about `scope.$apply()`. After every | 
					
						
							|  |  |  |  |   event that occurs, `scope.$apply()` gets called. This is done either | 
					
						
							|  |  |  |  |   automatically by the framework, or in some cases manually by our own | 
					
						
							|  |  |  |  |   code. It is the point in time when change detection occurs and data | 
					
						
							|  |  |  |  |   bindings get updated. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   Angular 1中的变更检测全是关于`scope.$apply()`的。在每个事件发生之后,`scope.$apply()`就会被调用。 | 
					
						
							|  |  |  |  |   这或者由框架自动调用,或者在某些情况下由我们自己的代码手动调用。它是发生变更检测以及更新数据绑定的时间点。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   In Angular 2 things are different. While change detection still | 
					
						
							|  |  |  |  |   occurs after every event, no one needs to call `scope.$apply()` for | 
					
						
							|  |  |  |  |   that to happen. This is because all Angular 2 code runs inside something | 
					
						
							| 
									
										
										
										
											2016-06-21 22:22:38 +08:00
										 |  |  |  |   called the [Angular zone](../api/core/index/NgZone-class.html). Angular always | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   knows when the code finishes, so it also knows when it should kick off | 
					
						
							|  |  |  |  |   change detection. The code itself doesn't have to call `scope.$apply()` | 
					
						
							|  |  |  |  |   or anything like it. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   在Angular 2中,事情有点不一样。虽然变更检测仍然会在每一个事件之后发生,却不再需要每次调用`scope.$apply()`了。 | 
					
						
							| 
									
										
										
										
											2016-06-10 14:45:12 +08:00
										 |  |  |  |   这是因为所有Angular 2代码都运行在一个叫做[Angular zone](../api/core/index/NgZone-class.html)的地方。 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   Angular总是知道什么时候代码执行完了,也就知道了它什么时候应该触发变更检测。代码本身并不需要调用`scope.$apply()`或其它类似的东西。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   In the case of hybrid applications, the `UpgradeAdapter` bridges the | 
					
						
							|  |  |  |  |   Angular 1 and Angular 2 approaches. Here's what happens: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   在这种混合式应用的案例中,`UpgradeAdapter`在Angular 1的方法和Angular 2的方法之间建立了桥梁。发生了什么呢? | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * Everything that happens in the application runs inside the Angular 2 zone. | 
					
						
							|  |  |  |  |     This is true whether the event originated in Angular 1 or Angular 2 code. | 
					
						
							|  |  |  |  |     The zone triggers Angular 2 change detection after every event. | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * 应用中发生的每件事都运行在Angular 2的zone里。 | 
					
						
							|  |  |  |  |     无论事件发生在Angular 1还是Angular 2的代码中,都是如此。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   * The `UpgradeAdapter` will invoke the Angular 1 `$rootScope.$apply()` after | 
					
						
							|  |  |  |  |     every turn of the Angular zone. This also triggers Angular 1 change | 
					
						
							|  |  |  |  |     detection after every event. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   * `UpgradeAdapter`将在每一次离开Angular zone时调用Angular 1的`$rootScope.$apply()`。这样也就同样会在每个事件之后触发Angular 1的变更检测。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | figure.image-display | 
					
						
							|  |  |  |  |   img(src="/resources/images/devguide/upgrade/change_detection.png" alt="Change detection in a hybrid application" width="600") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   What this means in practice is that we do not need to call `$apply()` in | 
					
						
							|  |  |  |  |   our code, regardless of whether it is in Angular 1 on Angular 2. The | 
					
						
							|  |  |  |  |   `UpgradeAdapter` does it for us. We *can* still call `$apply()` so there | 
					
						
							|  |  |  |  |   is no need to remove such calls from existing code. Those calls just don't | 
					
						
							|  |  |  |  |   have any effect in a hybrid application. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   在实践中,这意味着我们不用在自己的代码中调用`$apply()`,而不用管这段代码是在Angular 1还是Angular 2中。 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   `UpgradeAdapter`都替我们做了。我们仍然*可以*调用`$apply()`,也就是说我们不必从现有代码中移除此调用。 | 
					
						
							|  |  |  |  |   但是在混合式应用中,那些调用没有任何效果。 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   When we downgrade an Angular 2 component and then use it from Angular 1, | 
					
						
							|  |  |  |  |   the component's inputs will be watched using Angular 1 change detection. | 
					
						
							|  |  |  |  |   When those inputs change, the corresponding properties in the component | 
					
						
							|  |  |  |  |   are set. We can also hook into the changes by implementing the | 
					
						
							| 
									
										
										
										
											2016-06-21 22:22:38 +08:00
										 |  |  |  |   [OnChanges](../api/core/index/OnChanges-class.html) interface in the component, | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   just like we could if it hadn't been downgraded. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   当我们降级一个Angular 2组件,然后把它用于Angular 1中时,组件的输入属性就会被Angular 1的变更检测体系监视起来。 | 
					
						
							| 
									
										
										
										
											2016-06-10 14:45:12 +08:00
										 |  |  |  |   当那些输入属性发生变化时,组件中相应的属性就会被设置。我们也能通过实现[OnChanges](../api/core/index/OnChanges-interface.html) | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   接口来挂钩到这些更改,就像它未被降级时一样。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Correspondingly, when we upgrade an Angular 1 component and use it from Angular 2, | 
					
						
							|  |  |  |  |   all the bindings defined for the component directive's `scope` (or `bindToController`) | 
					
						
							|  |  |  |  |   will be hooked into Angular 2 change detection. They will be treated | 
					
						
							|  |  |  |  |   as regular Angular 2 inputs and set onto the scope (or controller) when | 
					
						
							|  |  |  |  |   they change. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   相应的,当我们把Angular 1的组件升级给Angular 2使用时,在这个组件型指令的`scope`(或`bindToController`)中定义的所有绑定, | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   都将被挂钩到Angular 2的变更检测体系中。它们将和标准的Angular 2输入属性被同等对待,并当它们发生变化时设置回scope(或控制器)上。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   ## Bootstrapping Hybrid Angular 1+2 Applications | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   ## 引导Angular 1+2的混合式应用程序 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   The first step to upgrading an application using the `UpgradeAdapter` is | 
					
						
							|  |  |  |  |   always to bootstrap it as a hybrid that supports both Angular 1 and | 
					
						
							|  |  |  |  |   Angular 2. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   使用`UpgradeAdapter`升级应用的第一步总是把它引导成一个同时支持Angular 1和Angular 2的混合式应用。 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Pure Angular 1 applications can be bootstrapped in two ways: By using an `ng-app` | 
					
						
							|  |  |  |  |   directive somewhere on the HTML page, or by calling | 
					
						
							|  |  |  |  |   [angular.bootstrap](https://docs.angularjs.org/api/ng/function/angular.bootstrap) | 
					
						
							|  |  |  |  |   from JavaScript. In Angular 2, only the second method is possible - there is | 
					
						
							|  |  |  |  |   no `ng-app` in Angular 2. This is also the case for hybrid applications. | 
					
						
							|  |  |  |  |   Therefore, it is a good preliminary step to switch Angular 1 applications to use the | 
					
						
							|  |  |  |  |   JavaScript bootstrap method even before switching them to hybrid mode. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   纯粹的Angular 1应用可以用两种方式引导:在HTML页面中的某处使用`ng-app`指令,或者从JavaScript中调用 | 
					
						
							|  |  |  |  |   [angular.bootstrap](https://docs.angularjs.org/api/ng/function/angular.bootstrap)。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   在Angular 2中,只有第二种方法是可行的,因为它没有`ng-app`指令。在混合式应用中也同样只能用第二种方法。 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   所以,在将Angular 1应用切换到混合模式之前,把它改为用JavaScript引导的方式是一个不错的起点。 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Say we have an `ng-app` driven bootstrap such as this one: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   比如说我们有个由`ng-app`驱动的引导过程,就像这个: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/index-ng-app.html', null, null, {otl: /(ng-app.*ng-strict-di)/}) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   We can remove the `ng-app` and `ng-strict-di` directives from the HTML | 
					
						
							|  |  |  |  |   and instead switch to calling `angular.bootstrap` from JavaScript, which | 
					
						
							|  |  |  |  |   will result in the same thing: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   我们可以从HTML中移除`ng-app`和`ng-strict-di`指令,改为从JavaScript中调用`angular.bootstrap`,它能达到同样效果: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/1-bootstrap/app.module.ts', 'bootstrap') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   To then switch the application into hybrid mode, we must first | 
					
						
							|  |  |  |  |   install Angular 2 to the project. Follow the instructions in | 
					
						
							|  |  |  |  |   [the QuickStart](../quickstart.html) for some pointers on this. | 
					
						
							|  |  |  |  |   When we have Angular 2 installed, we can import and instantiate | 
					
						
							|  |  |  |  |   the `UpgradeAdapter`, and then call its `bootstrap` method. It | 
					
						
							|  |  |  |  |   is designed to take the exact same arguments as | 
					
						
							|  |  |  |  |   [angular.bootstrap](https://docs.angularjs.org/api/ng/function/angular.bootstrap) | 
					
						
							|  |  |  |  |   so that it is easy to make the switch: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   要把这个应用切换到混合模式,我们得先把Angular 2安装到项目中。遵循[“快速起步”](../quickstart.html)中给出的步骤完成它。 | 
					
						
							|  |  |  |  |   安装完Angular 2之后,我们可以导入和实例化`UpgradeAdapter`类,然后调用它的`bootstrap`方法。 | 
					
						
							|  |  |  |  |   它被设计成接受与[angular.bootstrap](https://docs.angularjs.org/api/ng/function/angular.bootstrap)完全相同的参数。 | 
					
						
							|  |  |  |  |   所以,做这种切换很简单: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/1-2-hybrid-bootstrap/app.module.ts', 'bootstrap') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   At this point we'll be running a hybrid Angular 1+2 application! All the | 
					
						
							|  |  |  |  |   existing Angular 1 code will work as it always did, but we are now ready | 
					
						
							|  |  |  |  |   to run Angular 2 code as well. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   这时,我们就要开始运行Angular 1+2的混合式应用程序了!所有现存的Angular 1代码会像以前一样正常工作,但是我们现在也同样可以运行Angular 2代码了。 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | .alert.is-helpful | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     One notable difference between `angular.bootstrap` and | 
					
						
							|  |  |  |  |     `upgradeAdapter.bootstrap` is that the latter works *asynchronously*. | 
					
						
							|  |  |  |  |     This means that we cannot assume that the application has been instantiated | 
					
						
							|  |  |  |  |     immediately after the bootstrap call returns. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |     在`angular.bootstrap`和`upgradeAdapter.bootstrap`之间一个显著的不同点是:后者是*异步*工作的。 | 
					
						
							|  |  |  |  |     这意味着当这次`bootstrap`调用刚刚返回时,我们不能假设应用程序已经被初始化过了。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   As we begin to migrate components to Angular 2, we'll be using the | 
					
						
							|  |  |  |  |   `UpgradeAdapter` for more than just bootstrapping. It'll be important | 
					
						
							|  |  |  |  |   to use the **same** instance of the adapter across the whole application, | 
					
						
							|  |  |  |  |   because it stores internal information about what's going on in the application. | 
					
						
							|  |  |  |  |   It'll be useful to have a module for a shared `UpgradeAdapter` instance in | 
					
						
							|  |  |  |  |   the project: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   当我们开始把组件移植到Angular 2时,我们还将使用`UpgradeAdapter` —— 不止是进行引导。 | 
					
						
							|  |  |  |  |   在整个应用程序中使用此适配器的**同一个**实例是非常重要的,因为它保存了关于该应用程序当前状态的内部信息: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/1-2-hybrid-shared-adapter-bootstrap/upgrade_adapter.ts', null, 'upgrade_adapter.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   This shared instance can then be pulled in to all the modules that need it: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   然后这个共享的实例就能被所有需要它的模块获取到: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/1-2-hybrid-shared-adapter-bootstrap/app.module.ts', 'bootstrap') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Using Angular 2 Components from Angular 1 Code | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   ## 在Angular 1的代码中使用Angular 2的组件 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | figure | 
					
						
							|  |  |  |  |   img(src="/resources/images/devguide/upgrade/a1-to-a2.png" alt="Using an Angular 2 component from Angular 1 code" align="left" style="width:250px; margin-left:-40px;margin-right:10px" ) | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   Once we're running a hybrid app, we can start the gradual process of upgrading | 
					
						
							|  |  |  |  |   code. One of the more common patterns for doing that is to use an Angular 2 component | 
					
						
							|  |  |  |  |   in an Angular 1 context. This could be a completely new component or one that was | 
					
						
							|  |  |  |  |   previously Angular 1 but has been rewritten for Angular 2. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   一旦我们开始运行混合式应用,我们就可以开始逐渐升级代码了。做这件事的一种更常见的模式就是在Angular 1的上下文中使用Angular 2的组件。 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   该组件可能是全新的,也可能是把原本Angular 1的组件用Angular 2重写而成的。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Say we have a simple Angular 2 component that shows information about a hero: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 20:54:33 +08:00
										 |  |  |  |   假设我们有一个简单的用来显示英雄信息的Angular 2组件: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/downgrade-static/hero-detail.component.ts', null, 'hero-detail.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   If we want to use this component from Angular 1, we need to *downgrade* it | 
					
						
							|  |  |  |  |   using the upgrade adapter. What we get when we do that is an Angular 1 | 
					
						
							|  |  |  |  |   *directive*, which we can then register into our Angular 1 module: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   如果我们想在Angular 1中使用这个组件,我们就得用“升级适配器”把它*降级*。如果我们这么做,就会得到一个Angular 1的*指令*, | 
					
						
							|  |  |  |  |   我们可以把它注册到Angular 1的模块中: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/downgrade-static/app.module.ts', 'downgradecomponent') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   What we have here is an Angular 1 directive called `heroDetail`, which we can | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |   use like any other directive in our Angular 1 templates. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   这里我们得到的是一个叫做`heroDetail`的Angular 1指令,我们可以像用其它指令一样把它用在Angular 1模板中。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/index-downgrade-static.html', 'usecomponent') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | .alert.is-helpful | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     Note that since Angular 1 directives are matched based on their name, | 
					
						
							|  |  |  |  |     *the selector metadata of the Angular 2 component is not used in Angular 1*. | 
					
						
							|  |  |  |  |     It is matched as an element directive (`restrict: 'E'`) called `heroDetail`. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |     注意,由于Angular 1的指令是基于它们的名字进行匹配的,*Angular 2组件元数据中的`selector`不会被用在Angular 1中*。 | 
					
						
							|  |  |  |  |     它会像一个名叫`heroDetail`的元素型指令(`restrict: 'E'`)一样被匹配。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   Most components are not quite this simple, of course. Many of them | 
					
						
							|  |  |  |  |   have *inputs and outputs* that connect them to the outside world. An | 
					
						
							|  |  |  |  |   Angular 2 hero detail component with inputs and outputs might look | 
					
						
							|  |  |  |  |   like this: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   当然,大多数组件都不像这个这么简单。它们中很多都有*输入属性和输出属性*,来把它们连接到外部世界。 | 
					
						
							|  |  |  |  |   Angular 2的英雄详情组件带有像这样的输入属性与输出属性: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/downgrade-io/hero-detail.component.ts', null, 'hero-detail.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   These inputs and outputs can be supplied from the Angular 1 template, and the | 
					
						
							|  |  |  |  |   `UpgradeAdapter` takes care of bridging them over: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   这些输入属性和输出属性的值来自于Angular 1的模板,而`UpgradeAdapter`负责桥接它们: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/index-downgrade-io.html', 'usecomponent') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   注意,虽然我们正在Angular 1的模板中,**但却在使用Angular 2的属性(Attribute)语法来绑定到输入属性与输出属性**。 | 
					
						
							|  |  |  |  |   这是降级的组件本身要求的。而表达式本身仍然是标准的Angular 1表达式。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | .callout.is-important | 
					
						
							|  |  |  |  |   header Use kebab-case for downgraded component attributes | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   header 在降级过的组件属性中使用中线命名法 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   :marked | 
					
						
							|  |  |  |  |     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: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-17 11:45:56 +08:00
										 |  |  |  |     为降级过的组件使用Angular 2的属性(Attribute)语法规则时有一个值得注意的例外。 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |     它适用于由多个单词组成的输入或输出属性。在Angular 2中,我们要使用小驼峰命名法绑定这些属性: | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   code-example(format=""). | 
					
						
							|  |  |  |  |     [myHero]="hero" | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     But when using them from Angular 1 templates, we need to use kebab-case: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |     但是从Angular 1的模板中使用它们时,我们得使用中线命名法: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   code-example(format=""). | 
					
						
							|  |  |  |  |     [my-hero]="hero" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   The `$event` variable can be used in outputs to gain access to the | 
					
						
							|  |  |  |  |   object that was emitted. In this case it will be the `Hero` object, because | 
					
						
							|  |  |  |  |   that is what was passed to `this.deleted.emit()`. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   `$event`变量能被用在输出属性里,以访问这个事件所发出的对象。这个案例中它是`Hero`对象,因为`this.deleted.emit()`函数曾把它传了出来。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Since this is an Angular 1 template, we can still use other Angular 1 | 
					
						
							|  |  |  |  |   directives on the element, even though it has Angular 2 binding attributes on it. | 
					
						
							|  |  |  |  |   For  example, we can easily make multiple copies of the component using `ng-repeat`: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   由于这是一个Angular 1模板,虽然它已经有了Angular 2中绑定的属性(Attribute),我们仍可以在这个元素上使用其它Angular 1指令。 | 
					
						
							|  |  |  |  |   例如,我们可以用`ng-repeat`简单的制作该组件的多份拷贝: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/index-downgrade-io.html', 'userepeatedcomponent') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Using Angular 1 Component Directives from Angular 2 Code | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   ## 从Angular 2代码中使用Angular 1组件型指令 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | figure | 
					
						
							|  |  |  |  |   img(src="/resources/images/devguide/upgrade/a2-to-a1.png" alt="Using an Angular 1 component from Angular 2 code" align="left" style="width:250px; margin-left:-40px;margin-right:10px" ) | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   So, we can write an Angular 2 component and then use it from Angular 1 | 
					
						
							|  |  |  |  |   code. This is very useful when we start our migration from lower-level | 
					
						
							|  |  |  |  |   components and work our way up. But in some cases it is more convenient | 
					
						
							|  |  |  |  |   to do things in the opposite order: To start with higher-level components | 
					
						
							|  |  |  |  |   and work our way down. This too can be done using the `UpgradeAdapter`. | 
					
						
							|  |  |  |  |   We can *upgrade* Angular 1 component directives and then use them from | 
					
						
							|  |  |  |  |   Angular 2. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   现在,我们已经能在Angular 2中写一个组件,并把它用于Angular 1代码中了。 | 
					
						
							|  |  |  |  |   当我们从低级组件开始移植,并往上走时,这非常有用。但在另外一些情况下,从相反的方向进行移植会更加方便: | 
					
						
							|  |  |  |  |   从高级组件开始,然后往下走。这也同样能用`UpgradeAdapter`完成。 | 
					
						
							|  |  |  |  |   我们可以*升级*Angular 1组件型指令,然后从Angular 2中用它们。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Not all kinds of Angular 1 directives can be upgraded. The directive | 
					
						
							|  |  |  |  |   really has to be a *component directive*, with the characteristics | 
					
						
							|  |  |  |  |   [described in the preparation guide above](#using-component-directives). | 
					
						
							|  |  |  |  |   Our safest bet for ensuring compatibility is using the | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |   [component API](https://docs.angularjs.org/api/ng/type/angular.Module) | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   introduced in Angular 1.5. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   不是所有种类的Angular 1指令都能升级。该指令必须是一个严格的*组件型指令*,具有[上面的准备指南中描述的](#using-component-directives)那些特征。 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   确保兼容性的最安全的方式是Angular 1.5中引入的[组件API](https://docs.angularjs.org/api/ng/type/angular.Module)。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   A simple example of an upgradable component is one that just has a template | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |   and a controller: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   可升级组件的简单例子是只有一个模板和一个控制器的指令: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/upgrade-static/hero-detail.component.ts', null, 'hero-detail.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   We can *upgrade* this component to Angular 2 using the `UpgradeAdapter`'s | 
					
						
							|  |  |  |  |   `upgradeNg1Component` method. It takes the name of an Angular 1 component | 
					
						
							|  |  |  |  |   directive and returns an Angular 2 **component class**. When we then | 
					
						
							|  |  |  |  |   want to use it from an Angular 2 component, we list it the in the `directives` | 
					
						
							|  |  |  |  |   metadata of the component and then just use it in the Angular 2 template: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   我们可以使用`UpgradeAdapter`的`upgradeNg1Component`方法来把这个组件*升级*到Angular 2。 | 
					
						
							|  |  |  |  |   它接受Angular 1组件型指令的名字,并返回一个Angular 2**组件类**。 | 
					
						
							|  |  |  |  |   当我们以后想从Angular 2组件中用它时,只要把它列在组件的`directives`元数据中,然后直接在Angular 2模板中用它就可以了: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/upgrade-static/container.component.ts', null, 'container.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | .alert.is-helpful | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     Upgraded components always have an element selector, which is based | 
					
						
							|  |  |  |  |     on the original name of the original Angular 1 component directive. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |     升级后的组件总会有一个元素选择器,它就是原Angular 1组件型指令的原始名字。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   An upgraded component may also have inputs and outputs, as defined by | 
					
						
							|  |  |  |  |   the scope/controller bindings of the original Angular 1 component | 
					
						
							|  |  |  |  |   directive. When we use the component from an Angular 2 template, | 
					
						
							|  |  |  |  |   we provide the inputs and outputs using **Angular 2 template syntax**, | 
					
						
							|  |  |  |  |   with the following rules: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   升级后的组件也可能有输入属性和输出属性,它们是在原Angular 1组件型指令的scope/controller绑定中定义的。 | 
					
						
							|  |  |  |  |   当我们从Angular 2模板中使用该组件时,我们要使用**Angular 2模板语法**来提供这些输入属性和输出属性,但要遵循下列规则: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | table | 
					
						
							|  |  |  |  |   tr | 
					
						
							|  |  |  |  |     th | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |     th | 
					
						
							|  |  |  |  |       p Binding definition | 
					
						
							|  |  |  |  |       p 绑定定义 | 
					
						
							|  |  |  |  |     th | 
					
						
							|  |  |  |  |       p Template syntax | 
					
						
							|  |  |  |  |       p 模板语法 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   tr | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |     th | 
					
						
							|  |  |  |  |       p Attribute binding | 
					
						
							|  |  |  |  |       p 属性(Attribute)绑定 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         `myAttribute: '@myAttribute'` | 
					
						
							|  |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         `<my-component myAttribute="value">` | 
					
						
							|  |  |  |  |   tr | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |     th | 
					
						
							|  |  |  |  |       p Expression binding | 
					
						
							|  |  |  |  |       p 表达式绑定 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         `myOutput: '&myOutput'` | 
					
						
							|  |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         `<my-component (myOutput)="action()">` | 
					
						
							|  |  |  |  |   tr | 
					
						
							| 
									
										
										
										
											2016-07-26 17:45:25 +08:00
										 |  |  |  |     th  | 
					
						
							|  |  |  |  |       p One-way binding | 
					
						
							|  |  |  |  |       p 单向绑定 | 
					
						
							| 
									
										
										
										
											2016-04-25 12:09:37 +03:00
										 |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         `myValue: '<myValue'` | 
					
						
							|  |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         `<my-component [myValue]="anExpression">` | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   tr | 
					
						
							|  |  |  |  |     th Two-way binding | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |     th | 
					
						
							|  |  |  |  |       p Two-way binding | 
					
						
							|  |  |  |  |       p 双向绑定 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         `myValue: '=myValue'` | 
					
						
							|  |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							| 
									
										
										
										
											2016-04-25 12:09:37 +03:00
										 |  |  |  |         As a two-way binding: `<my-component [(myValue)]="anExpression">`. | 
					
						
							|  |  |  |  |         Since most Angular 1 two-way bindings actually only need a one-way binding | 
					
						
							|  |  |  |  |         in practice, `<my-component [myValue]="anExpression">` is often enough. | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |         用作输入:`<my-component [myValue]="anExpression">` 或 | 
					
						
							|  |  |  |  |         用作双向绑定:`<my-component [(myValue)]="anExpression"` | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   As an example, say we have a hero detail Angular 1 component directive | 
					
						
							|  |  |  |  |   with one input and one output: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   举个例子,假设我们在Angular 1中有一个表示“英雄详情”的组件型指令,它带有一个输入属性和一个输出属性: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/upgrade-io/hero-detail.component.ts', null, 'hero-detail.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   We can upgrade this component to Angular 2, and then provide the input | 
					
						
							|  |  |  |  |   and output using Angular 2 template syntax: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   我们可以把这个组件升级到Angular 2,然后使用Angular 2的模板语法提供这个输入属性和输出属性: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/upgrade-io/container.component.ts', null, 'container.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Projecting Angular 1 Content into Angular 2 Components | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   ## 把Angular 1的内容投影到Angular 2组件中 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | figure | 
					
						
							|  |  |  |  |   img(src="/resources/images/devguide/upgrade/a1-to-a2-with-projection.png" alt="Projecting Angular 1 content into Angular 2" align="left" style="width:250px; margin-left:-40px;margin-right:10px" ) | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   When we are using a downgraded Angular 2 component from an Angular 1 | 
					
						
							|  |  |  |  |   template, the need may arise to *transclude* some content into it. This | 
					
						
							|  |  |  |  |   is also possible. While there is no such thing as transclusion in Angular 2, | 
					
						
							|  |  |  |  |   there is a very similar concept called *content projection*. The `UpgradeAdapter` | 
					
						
							|  |  |  |  |   is able to make these two features interoperate. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   如果我们在Angular 1模板中使用降级后的Angular 2组件时,可能会需要把模板中的一些内容投影进那个组件。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   这也是可能的,虽然在Angular 2中并没有透传(transclude)这样的东西,但它有一个非常相似的概念,叫做*内容投影*。 | 
					
						
							|  |  |  |  |   `UpgradeAdapter`也能让这两个特性实现互操作。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Angular 2 components that support content projection make use of an `<ng-content>` | 
					
						
							|  |  |  |  |   tag within them. Here's an example of such a component: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   Angular 2的组件通过使用`<ng-content>`标签来支持内容投影。下面是这类组件的一个例子: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/1-to-2-projection/hero-detail.component.ts', null, 'hero-detail.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   When using the component from Angular 1, we can supply contents for it. Just | 
					
						
							|  |  |  |  |   like they would be transcluded in Angular 1, they get projected to the location | 
					
						
							|  |  |  |  |   of the `<ng-content>` tag in Angular 2: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   当从Angular 1中使用该组件时,我们可以为它提供内容。正如它们将在Angular 1中被透传一样, | 
					
						
							|  |  |  |  |   它们也在Angular 2中被投影到了`<ng-content>`标签所在的位置: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/index-1-to-2-projection.html', 'usecomponent') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | .alert.is-helpful | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     When Angular 1 content gets projected inside an Angular 2 component, it still | 
					
						
							|  |  |  |  |     remains in "Angular 1 land" and is managed by the Angular 1 framework. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |     当Angular 1的内容被投影到Angular 2组件中时,它仍然留在“Angular 1王国”中,并被Angular 1框架管理着。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Transcluding Angular 2 Content into Angular 1 Component Directives | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   ## 把Angular 2的内容透传进Angular 1的组件型指令 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | figure | 
					
						
							|  |  |  |  |   img(src="/resources/images/devguide/upgrade/a2-to-a1-with-transclusion.png" alt="Projecting Angular 2 content into Angular 1" align="left" style="width:250px; margin-left:-40px;margin-right:10px" ) | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   Just like we can project Angular 1 content into Angular 2 components, | 
					
						
							|  |  |  |  |   we can *transclude* Angular 2 content into Angular 1 components, whenever | 
					
						
							|  |  |  |  |   we are using upgraded versions from them. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   就像我们能把Angular 1的内容投影进Angular 2组件一样,我们也能把Angular 2的内容*透传*进Angular 1的组件, | 
					
						
							|  |  |  |  |   但不管怎样,我们都要使用它们升级过的版本。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   When an Angular 1 component directive supports transclusion, it may use | 
					
						
							|  |  |  |  |   the `ng-transclude` directive in its template to mark the transclusion | 
					
						
							|  |  |  |  |   point: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   如果一个Angular 1组件型指令支持透传,它就会在自己的模板中使用`ng-transclude`指令标记出透传到的位置: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/2-to-1-transclusion/hero-detail.component.ts', null, 'hero-detail.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | .alert.is-helpful | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     The directive also needs to have the `transclude: true` option enabled. | 
					
						
							|  |  |  |  |     It is on by default for component directives defined with the | 
					
						
							|  |  |  |  |     1.5 component API. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |     该指令还需要启用一个`transclude: true`选项。当用Angular 1.5中的组件API定义组件型指令时,该选项默认是开启的。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   If we upgrade this component and use it from Angular 2, we can populate | 
					
						
							|  |  |  |  |   the component tag with contents that will then get transcluded: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   如果我们升级这个组件,并把它用在Angular 2中,我们就能把准备透传的内容放进这个组件的标签中。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/2-to-1-transclusion/container.component.ts', null, 'container.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Making Angular 1 Dependencies Injectable to Angular 2 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   ## 让Angular 1中的依赖可被注入到Angular 2 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   When running a hybrid app, we may bump into situations where we need to have | 
					
						
							|  |  |  |  |   some Angular 1 dependencies to be injected to Angular 2 code. This may be | 
					
						
							|  |  |  |  |   because we have some business logic still in Angular 1 services, or because | 
					
						
							|  |  |  |  |   we need some of Angular 1's built-in services like `$location` or `$timeout`. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   当运行一个混合式应用时,我们可能会遇到这种情况:我们需要把某些Angular 1的依赖注入到Angular 2代码中。 | 
					
						
							| 
									
										
										
										
											2016-09-17 11:46:17 +08:00
										 |  |  |  |   这可能是因为某些业务逻辑仍然在Angular 1服务中,或者需要某些Angular 1的内置服务,比如`$location`或`$timeout`。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   In these situations, it is possible to *upgrade* an Angular 1 provider to | 
					
						
							|  |  |  |  |   Angular 2. This makes it possible to then inject it somewhere in Angular 2 | 
					
						
							|  |  |  |  |   code. For example, we might have a service called `HeroesService` in Angular 1: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-07 08:22:36 +08:00
										 |  |  |  |   在这些情况下,把一个Angular 1提供商*升级到*Angular 2也是有可能的。这就让它将来有可能被注入到Angular 2代码中的某些地方。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   比如,我们可能在Angular 1中有一个名叫`HeroesService`的服务: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/1-to-2-providers/heroes.service.ts', null, 'heroes.service.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-01-15 10:46:14 -08:00
										 |  |  |  |   We can upgrade the service using the `UpgradeAdapter`'s `upgradeNg1Provider` method | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   by giving it the name of the service. This adds the service into Angular 2's root injector. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   我们可以用`UpgradeAdapter`的`upgradeNg1Provider`方法来升级该服务,只要给它传入服务的名字就行了。 | 
					
						
							|  |  |  |  |   这会把该服务加到Angular 2的根注入器中。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/1-to-2-providers/app.module.ts', 'register', 'app.module.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   We can then inject it in Angular 2 using a string token that matches | 
					
						
							|  |  |  |  |   its original name in Angular 1: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   然后我们可以使用与它在Angular 1中的原始名字相同的字符串型令牌,把它注入到Angular 2中: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/1-to-2-providers/hero-detail.component.ts', null, 'hero-detail.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | .alert.is-helpful | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     In this example we upgraded a service class, which has the added benefit that | 
					
						
							|  |  |  |  |     we can use a TypeScript type annotation when we inject it. While it doesn't | 
					
						
							|  |  |  |  |     affect how the dependency is handled, it enables the benefits of static type | 
					
						
							|  |  |  |  |     checking. This is not required though, and any Angular 1 service, factory, or | 
					
						
							|  |  |  |  |     provider can be upgraded. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |     在这个例子中,我们升级了服务类。当我们注入它时,我们可以使用TypeScript类型注解来获得这些额外的好处。 | 
					
						
							|  |  |  |  |     它没有影响该依赖的处理过程,同时还得到了启用静态类型检查的好处。 | 
					
						
							| 
									
										
										
										
											2016-07-07 08:22:36 +08:00
										 |  |  |  |     任何Angular 1中的服务、工厂和提供商都能被升级 —— 尽管这不是必须的。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Making Angular 2 Dependencies Injectable to Angular 1 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   ## 让Angular 2的依赖能被注入到Angular 1中 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |   In addition to upgrading Angular 1 dependencies, we can also *downgrade* | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Angular 2 dependencies, so that we can use them from Angular 1. This can be | 
					
						
							|  |  |  |  |   useful when we start migrating services to Angular 2 or creating new services | 
					
						
							|  |  |  |  |   in Angular 2 while we still have components written in Angular 1. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   除了能升级Angular 1依赖之外,我们还能*降级*Angular 2的依赖,以便我们能在Angular 1中使用它们。 | 
					
						
							|  |  |  |  |   当我们已经开始把服务移植到Angular 2或在Angular 2中创建新服务,但同时还有一些用Angular 1写成的组件时,这会非常有用。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   For example, we might have an Angular 2 service called `Heroes`: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   例如,我们可能有一个Angular 2的`Heroes`服务: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/2-to-1-providers/heroes.ts', null, 'heroes.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   We can again use the `UpgradeAdapter` for this, but first we need to register `Heroes` | 
					
						
							|  |  |  |  |   to the Angular 2 injector itself. In a pure Angular 2 application we would do this | 
					
						
							|  |  |  |  |   when we bootstrap the app, as described in the [dependency injection guide](dependency-injection.html#!#providers). | 
					
						
							|  |  |  |  |   But since hybrid applications are bootstrapped using the `UpgradeAdapter`, we also | 
					
						
							|  |  |  |  |   need to register our Angular 2 providers using `UpgradeAdapter`. It has a method | 
					
						
							|  |  |  |  |   called `addProvider` for this purpose. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   我们又能使用`UpgradeAdapter`处理它了,但首先我们需要把`Heroes`服务注册到Angular 2自身的注入器。 | 
					
						
							|  |  |  |  |   在纯Angular 2应用中,我们会在引导应用时这么做,就像[依赖注入指南](dependency-injection.html#!#providers)中描述的那样。 | 
					
						
							| 
									
										
										
										
											2016-07-07 08:22:36 +08:00
										 |  |  |  |   但是因为混合式应用是使用`UpgradeAdapter`引导的,所以我们还得用`UpgradeAdapter`注册Angular 2的提供商。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   它有一个`addProvider`方法就是用来做这个的。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Once we've registered the Angular 2 provider, we can turn `Heroes` into an *Angular 1 | 
					
						
							|  |  |  |  |   factory function* using `upgradeAdapter.downgradeNg2Provider()`. We can | 
					
						
							|  |  |  |  |   then plug the factory into an Angular 1 module, at which point we also choose what the | 
					
						
							|  |  |  |  |   name of the dependency will be in Angular 1: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-07 08:22:36 +08:00
										 |  |  |  |   一旦我们注册了Angular 2的提供商,就能用`upgradeAdapter.downgradeNg2Provider()`把`Heroes`转变成一个*Angular 1的工厂函数*。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   然后我们就能把这个工厂插入到Angular 1模块中,那时,我们可以选择该依赖要在Angular 1中用的名字: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/2-to-1-providers/app.module.ts', 'register', 'app.module.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   After this, the service is injectable anywhere in our Angular 1 code: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   此后,该服务就能被注入到Angular 1代码中的任何地方了: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-adapter/ts/app/2-to-1-providers/hero-detail.component.ts', null, 'hero-detail.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | .l-main-section | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   # PhoneCat Upgrade Tutorial | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   # PhoneCat升级教程 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   In this section and we will look at a complete example of | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   preparing and upgrading an application using the `upgrade` module. The app | 
					
						
							|  |  |  |  |   we're going to work on is [Angular PhoneCat](https://github.com/angular/angular-phonecat) | 
					
						
							|  |  |  |  |   from [the original Angular 1 tutorial](https://docs.angularjs.org/tutorial), | 
					
						
							|  |  |  |  |   which is where many of us began our Angular adventures. Now we'll see how to | 
					
						
							|  |  |  |  |   bring that application to the brave new world of Angular 2. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   在本节和下节中,我们将看一个完整的例子,它使用`upgrade`模块准备和升级了一个应用程序。 | 
					
						
							|  |  |  |  |   该应用就是来自[原Angular 1教程](https://docs.angularjs.org/tutorial)中的[Angular PhoneCat](https://github.com/angular/angular-phonecat)。 | 
					
						
							|  |  |  |  |   那是我们很多人当初开始Angular探险之旅的起点。 | 
					
						
							|  |  |  |  |   现在,我们来看看如何把该应用带入Angular 2的美丽新世界。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |   During the process we'll learn how to apply the steps outlined in the | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   [preparation guide](#preparation) in practice: We'll align the application | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   with Angular 2 and also take TypeScript into use. | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   这期间,我们将学到如何在实践中应用[准备指南](#preparation)中列出的那些重点步骤: | 
					
						
							|  |  |  |  |   我们先让该应用向Angular 2看齐,然后为它引入SystemJS模块加载器和TypeScript。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   To follow along with the tutorial, clone the | 
					
						
							|  |  |  |  |   [angular-phonecat](https://github.com/angular/angular-phonecat) repository | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   and apply the steps as we go. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   要跟随本教程,请先把[angular-phonecat](https://github.com/angular/angular-phonecat)仓库克隆到本地,并跟我们一起应用这些步骤。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   In terms of project structure, this is where our work begins: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   在项目结构方面,我们工作的起点是这样的: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 14:36:37 +02:00
										 |  |  |  | .filetree | 
					
						
							|  |  |  |  |   .file angular-phonecat | 
					
						
							|  |  |  |  |   .children | 
					
						
							|  |  |  |  |     .file bower.json | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |     .file karma.conf.js | 
					
						
							| 
									
										
										
										
											2015-12-15 14:36:37 +02:00
										 |  |  |  |     .file package.json | 
					
						
							|  |  |  |  |     .file app | 
					
						
							|  |  |  |  |     .children | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |       .file core | 
					
						
							| 
									
										
										
										
											2015-12-15 14:36:37 +02:00
										 |  |  |  |       .children | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |         .file checkmark | 
					
						
							| 
									
										
										
										
											2015-12-15 14:36:37 +02:00
										 |  |  |  |         .children | 
					
						
							|  |  |  |  |           .file checkmark.filter.js | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |           .file checkmark.filter.spec.js | 
					
						
							|  |  |  |  |         .file phone | 
					
						
							| 
									
										
										
										
											2015-12-15 14:36:37 +02:00
										 |  |  |  |         .children | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |           .file phone.module.js | 
					
						
							|  |  |  |  |           .file phone.service.js | 
					
						
							|  |  |  |  |           .file phone.service.spec.js | 
					
						
							|  |  |  |  |         .file core.module.js | 
					
						
							|  |  |  |  |       .file phone-detail | 
					
						
							| 
									
										
										
										
											2015-12-15 14:36:37 +02:00
										 |  |  |  |       .children | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |         .file phone-detail.component.js | 
					
						
							|  |  |  |  |         .file phone-detail.component.spec.js | 
					
						
							|  |  |  |  |         .file phone-detail.module.js | 
					
						
							|  |  |  |  |         .file phone-detail.template.html | 
					
						
							|  |  |  |  |       .file phone-list | 
					
						
							| 
									
										
										
										
											2015-12-15 14:36:37 +02:00
										 |  |  |  |       .children | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |         .file phone-list.component.js | 
					
						
							|  |  |  |  |         .file phone-list.component.spec.js | 
					
						
							|  |  |  |  |         .file phone-list.module.js | 
					
						
							|  |  |  |  |         .file phone-list.template.html | 
					
						
							| 
									
										
										
										
											2015-12-15 14:36:37 +02:00
										 |  |  |  |       .file img | 
					
						
							|  |  |  |  |       .children | 
					
						
							|  |  |  |  |         .file  ... | 
					
						
							|  |  |  |  |       .file phones | 
					
						
							|  |  |  |  |       .children | 
					
						
							|  |  |  |  |         .file  ... | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |       .file app.animations.js | 
					
						
							|  |  |  |  |       .file app.config.js | 
					
						
							|  |  |  |  |       .file app.css | 
					
						
							|  |  |  |  |       .file app.module.js | 
					
						
							| 
									
										
										
										
											2015-12-15 14:36:37 +02:00
										 |  |  |  |       .file index.html | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |     .file e2e-tests | 
					
						
							| 
									
										
										
										
											2015-12-15 14:36:37 +02:00
										 |  |  |  |     .children | 
					
						
							|  |  |  |  |       .file protractor-conf.js | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |       .file scenarios.js | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 14:36:37 +02:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   This is actually a pretty good starting point. The code uses the Angular 1.5 | 
					
						
							|  |  |  |  |   component API and the organization follows the | 
					
						
							|  |  |  |  |   [Angular 1 Style Guide](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md), | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   which is an important [preparation step](#following-the-angular-style-guide) before | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |   a successful upgrade. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   这确实是一个很好地起点。特别是,该结构遵循了[Angular 1 风格指南](https://github.com/johnpapa/angular-styleguide), | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   要想成功升级,这是一个很重要的[准备步骤](#following-the-angular-style-guide)。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   * Each component, service, and filter is in its own source file, as per the | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   [Rule of 1](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#single-responsibility). | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   * 每个组件、服务和过滤器都在它自己的源文件中 —— 就像[单一规则](https://github.com/johnpapa/angular-styleguide#single-responsibility)所要求的。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   * The `core`, `phone-detail`, and `phone-list` modules are each in their | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |     own subdirectory. Those subdirectories contain the JavaScript code as well as | 
					
						
							|  |  |  |  |     the HTML templates that go with each particular feature. This is in line with the | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |     [Folders-by-Feature Structure](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#style-y152) | 
					
						
							|  |  |  |  |     and [Modularity](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#modularity) | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |     rules. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   * `core`、`phone-detail`和`phone-list`模块都在它们自己的子目录中。那些子目录除了包含HTML模板之外,还包含JavaScript代码,它们共同完成一个特性。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |     这是[按特性分目录的结构](https://github.com/johnpapa/angular-styleguide#style-y152) | 
					
						
							|  |  |  |  |     和[模块化](https://github.com/johnpapa/angular-styleguide#modularity)规则所要求的。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   * 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). | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   * 单元测试都和应用代码在一起,它们很容易找到。就像规则 | 
					
						
							|  |  |  |  |     [组织测试文件](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#style-y197)中要求的那样。 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   ## Switching to TypeScript | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   ## 切换到TypeScript | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   Since we're going to be writing our Angular 2 code in TypeScript, it makes sense to | 
					
						
							|  |  |  |  |   bring in the TypeScript compiler even before we begin upgrading. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   因为我们将使用TypeScript编写Angular 2的代码,所以在开始升级之前,我们把TypeScript的编译器设置好是很合理的。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   We will also start to gradually phase out the Bower package manager in favor | 
					
						
							|  |  |  |  |   of NPM. We'll install all new dependencies using NPM, and will eventually be | 
					
						
							|  |  |  |  |   able to remove Bower from the project. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   我们还将开始逐步淘汰Bower包管理器,换成我们更喜欢的NPM。后面我们将使用NPM来安装新的依赖包,并最终从项目中移除Bower。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Let's begin by installing TypeScript to the project. While we're at it, let's also | 
					
						
							|  |  |  |  |   install the [Typings type definition manager](https://github.com/typings/typings). | 
					
						
							| 
									
										
										
										
											2016-02-05 17:23:35 +02:00
										 |  |  |  |   It will allow us to install type definitions for libraries that don't come with | 
					
						
							|  |  |  |  |   prepackaged types. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   让我们先把TypeScript包安装到项目中。同时我们还将安装[typings类型定义管理器](https://github.com/typings/typings)。 | 
					
						
							|  |  |  |  |   它将允许我们为那些没有提供内置类型信息库的包安装类型定义。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 17:23:35 +02:00
										 |  |  |  | code-example(format=""). | 
					
						
							|  |  |  |  |   npm i typescript typings --save-dev | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   Let's also add run scripts for the `tsc` TypeScript compiler and the `typings` | 
					
						
							|  |  |  |  |   tool to `package.json`: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   我们还要把用来运行TypeScript编译器`tsc`和`typings`工具的脚本添加到`package.json`中: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeJson('upgrade-phonecat-1-typescript/ts/package.json', {paths: 'scripts.tsc, scripts.tsc:w, scripts.typings'}, 'package.json') | 
					
						
							| 
									
										
										
										
											2016-02-05 17:23:35 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   We can now use Typings to install type definitions for the existing libraries that | 
					
						
							|  |  |  |  |   we're using: Angular 1 and the Jasmine unit test framework. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   现在我们可以使用typings工具来安装Angular 1和Jasmine单元测试框架的类型定义文件。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 17:23:35 +02:00
										 |  |  |  | code-example(format=""). | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   npm run typings install dt~jquery dt~angular dt~angular-route \ | 
					
						
							|  |  |  |  |     dt~angular-resource dt~angular-mocks dt~angular-animate \ | 
					
						
							|  |  |  |  |     dt~jasmine -- --save --global | 
					
						
							| 
									
										
										
										
											2016-04-27 11:28:22 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   This will add these typings into a `typings.json` configuration file as well as | 
					
						
							|  |  |  |  |   download them into the `typings directory`. | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   这会把这些类型定义文件加到配置文件`typings.json`中,并把它们下载到`typings`目录下。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   We should also configure the TypeScript compiler so that it can understand our | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   project. We'll add a `tsconfig.json` file to the project directory, just like we do | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   in the [Quickstart](../quickstart.html). It instructs the TypeScript compiler how | 
					
						
							|  |  |  |  |   to interpret our source files. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   我们还应该配置TypeScript编译器,以便它能理解我们的项目结构。我们要往项目目录下添加一个`tsconfig.json`文件, | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   就像在[“快速起步”](../quickstart.html)中做过的那样。它将告诉TypeScript编译器,该如何编译我们的源文件。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeJson('upgrade-phonecat-1-typescript/ts/tsconfig.ng1.json', null, 'tsconfig.json') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   We are telling the TypeScript compiler to turn our TypeScript files to ES5 code | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   bundled into CommonJS modules. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   我们告诉TypeScript编译器,把TypeScript文件转换成ES5代码,并打包进CommonJS模块中。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   We can now launch the TypeScript compiler from the command line. It will watch | 
					
						
							|  |  |  |  |   our `.ts` source files and compile them to JavaScript on the fly. Those compiled | 
					
						
							|  |  |  |  |   `.js` files are then loaded into the browser by SystemJS. This is a process we'll | 
					
						
							|  |  |  |  |   want to have continuously running in the background as we go along. | 
					
						
							| 
									
										
										
										
											2016-02-05 17:23:35 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   我们现在可以从命令行启动TypeScript编译器。它将监控`.ts`源码文件,并随时把它们编译成JavaScript。 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   然后这些编译出的`.js`文件被SystemJS加载到浏览器中。当我们继续往前走的时候,这个过程将在后台持续运行。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 17:23:35 +02:00
										 |  |  |  | code-example(format=""). | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   npm run tsc:w | 
					
						
							| 
									
										
										
										
											2016-02-05 17:23:35 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   The next thing we'll do is convert our JavaScript files to TypeScript. Since | 
					
						
							|  |  |  |  |   TypeScript is a superset of ECMAScript 2015, which in turn is a superset | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   of ECMAScript 5, we can simply switch the file extensions from `.js` to `.ts` | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   and everything will work just like it did before. As the TypeScript compiler | 
					
						
							|  |  |  |  |   runs, it emits the corresponding `.js` file for every `.ts` file and the | 
					
						
							|  |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   我们要做的下一件事是把JavaScript文件转换成TypeScript文件。 | 
					
						
							|  |  |  |  |   由于TypeScript是ECMAScript 2015的一个超集,而ES2015又是ECMAScript 5的超集,所以我们可以简单的把文件的扩展名从`.js`换成`.ts`, | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   它们还是会像以前一样工作。由于TypeScript编译器仍在运行,它会为每一个`.ts`文件生成对应的`.js`文件,而真正运行的是编译后的`.js`文件。 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   如果你用`npm start`开启了本项目的HTTP服务器,你会在浏览器中看到一个功能完好的应用。 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   有了TypeScript,我们就可以从它的一些特性中获益了。此语言可以为Angular 1应用提供很多价值。 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   For one thing, TypeScript is a superset of ES2015. Any app that has previously | 
					
						
							|  |  |  |  |   been written in ES5 - like the PhoneCat example has - can with TypeScript | 
					
						
							|  |  |  |  |   start incorporating all of the JavaScript features that are new to ES2015. | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   These include things like `let`s and `const`s, arrow functions, default function | 
					
						
							|  |  |  |  |   parameters, and destructuring assignments. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 09:26:54 +08:00
										 |  |  |  |   首先,TypeScript是一个ES2015的超集。任何以前用ES5写的程序(就像PhoneCat范例)都可以开始通过TypeScript | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   纳入那些添加到ES2015中的新特性。 | 
					
						
							|  |  |  |  |   这包括`let`、`const`、箭头函数、函数默认参数以及解构(destructure)赋值。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Another thing we can do is start adding *type safety* to our code. This has | 
					
						
							|  |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   我们能做的另一件事就是把*类型安全*添加到代码中。这实际上已经部分完成了,因为我们已经安装了Angular 1的类型定义。 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   当我们正确调用Angular 1的API时,TypeScript会帮我们检查它 —— 比如往Angular模块中注册组件。 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   But we can also start adding *type annotations* for our own code to get even more | 
					
						
							|  |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   我们还能开始把*类型注解*添加到自己的代码中,来从TypeScript的类型系统中获得更多帮助。 | 
					
						
							|  |  |  |  |   比如,我们可以给`checkmark`过滤器加上注解,表明它期待一个`boolean`类型的参数。 | 
					
						
							|  |  |  |  |   这可以更清楚的表明此过滤器打算做什么 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-1-typescript/ts/app/core/checkmark/checkmark.filter.ts', null, 'app/core/checkmark/checkmark.filter.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   在`Phone`服务中,我们可以明确的把`$resource`服务声明为`angular.resource.IResourceService`,一个Angular 1类型定义提供的类型。 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-1-typescript/ts/app/core/phone/phone.service.ts', null, 'app/core/phone/phone.service.ts') | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   我们可以在应用的路由配置中使用同样的技巧,那里我们用到了location和route服务。 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   一旦给它们提供了类型信息,TypeScript就能检查我们是否在用类型的正确参数来调用它们了。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-1-typescript/ts/app/app.config.ts', null, 'app/app.config.ts') | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | .l-sub-section | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     The [Angular 1.x type definitions](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/angularjs) | 
					
						
							| 
									
										
										
										
											2016-02-05 17:23:35 +02:00
										 |  |  |  |     we installed with Typings are not officially maintained by the Angular team, | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |     but are quite comprehensive. It is possible to make an Angular 1.x application | 
					
						
							|  |  |  |  |     fully type-annotated with the help of these definitions. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |     我们用typings工具安装的这个[Angular 1.x类型定义文件](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/angularjs) | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |     并不是由Angular开发组维护的,但它也已经足够全面了。借助这些类型定义的帮助,它可以为Angular 1.x程序加上全面的类型注解。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |     If this is something we wanted to do, it would be a good idea to enable | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |     the `noImplicitAny` configuration option in `tsconfig.json`. This would | 
					
						
							|  |  |  |  |     cause the TypeScript compiler to display a warning when there's any code that | 
					
						
							|  |  |  |  |     does not yet have type annotations. We could use it as a guide to inform | 
					
						
							|  |  |  |  |     us about how close we are to having a fully annotated project. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |     如果我们想这么做,那么在`tsconfig.json`中启用`noImplicitAny`配置项就是一个好主意。 | 
					
						
							|  |  |  |  |     这样,如果遇到什么还没有类型注解的代码,TypeScript编译器就会显示一个警告。 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |     我们可以用它作为指南,告诉我们现在与一个完全类型化的项目距离还有多远。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   Another TypeScript feature we can make use of is *classes*. In particular, we | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   can turn our component controllers into classes. That way they'll be a step | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   closer to becoming Angular 2 component classes, which will make our life | 
					
						
							|  |  |  |  |   easier once we do the upgrade. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   我们能用的另一个TypeScript特性是*类*。具体来讲,我们可以把控制器转换成类。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   这种方式下,我们离成为Angular 2组件类就又近了一步,它会令我们的升级之路变得更简单。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Angular 1 expects controllers to be constructor functions. That's exactly what | 
					
						
							|  |  |  |  |   ES2015/TypeScript classes are under the hood, so that means we can just plug in a | 
					
						
							|  |  |  |  |   class as a component controller and Angular 1 will happily use it. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   Angular 1期望控制器是一个构造函数。这实际上就是ES2015/TypeScript中的类, | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   这也就意味着只要我们把一个类注册为组件控制器,Angular 1就会愉快的使用它。 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Here's what our new class for the phone list component controller looks like: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   新的“电话列表(phone list)”组件控制器类看起来是这样的: | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-11 15:36:53 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat/ts/classes/app/js/phone_list/phone_list.controller.ts', null, 'app/js/phone_list/phone_list.controller.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   What was previously done in the controller function is now done in the class | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   constructor function. The dependency injection annotations are attached | 
					
						
							|  |  |  |  |   to the class using a static property `$inject`. At runtime this becomes the | 
					
						
							|  |  |  |  |   `PhoneListController.$inject` property. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:38 +01:00
										 |  |  |  |   以前在控制器函数中实现的一切,现在都改由类的构造函数来实现了。类型注入注解通过静态属性`$inject` | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   被附加到了类上。在运行时,它们变成了`PhoneListController.$inject`。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   The class additionally declares three members: The array of phones, the name of | 
					
						
							|  |  |  |  |   the current sort key, and the search query. These are all things we have already | 
					
						
							|  |  |  |  |   been attaching to the controller but that weren't explicitly declared anywhere. | 
					
						
							|  |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   该类额外声明了三个成员:电话列表、当前排序键的名字和搜索条件。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   这些东西我们以前就加到了控制器上,只是从来没有在任何地方显式定义过它们。最后一个成员从未真正在TypeScript代码中用过, | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   因为它只是在模板中被引用过。但为了清晰起见,我们还是应该定义出此控制器应有的所有成员。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   In the Phone detail controller we'll have two members: One for the phone | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   that the user is looking at and another for the URL of the currently displayed image: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   在电话详情控制器中,我们有两个成员:一个是用户正在查看的电话,另一个是正在显示的图像: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.component.ts', null, 'app/phone-detail/phone-detail.component.ts') | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   This makes our controller code look a lot more like Angular 2 already. We're | 
					
						
							|  |  |  |  |   all set to actually introduce Angular 2 into the project. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   这已经让我们的控制器代码看起来更像Angular 2了。我们的准备工作做好了,可以引进Angular 2到项目中了。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   If we had any Angular 1 services in the project, those would also be | 
					
						
							|  |  |  |  |   a good candidate for converting to classes, since like controllers, | 
					
						
							|  |  |  |  |   they're also constructor functions. But we only have the `Phone` factory | 
					
						
							|  |  |  |  |   in this project, and that's a bit special since it's an `ngResource` | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   factory. So we won't be doing anything to it in the preparation stage. | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   We'll instead turn it directly into an Angular 2 service. | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   如果项目中有任何Angular 1的服务,它们也是转换成类的优秀候选人,像控制器一样,它们也是构造函数。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   但是在本项目中,我们只有一个`Phone`工厂,这有点特别,因为它是一个`ngResource`工厂。 | 
					
						
							|  |  |  |  |   所以我们不会在准备阶段中处理它,而是在下一节中直接把它转换成Angular 2服务。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   ## Installing Angular 2 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   ## 安装Angular 2 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   Having completed our preparation work, let's get going with the Angular 2 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   upgrade of PhoneCat. We'll do this incrementally with the help of the | 
					
						
							|  |  |  |  |   [upgrade module](#upgrading-with-the-upgrade-adapter) that comes with Angular 2. | 
					
						
							|  |  |  |  |   By the time we're done, we'll be able to remove Angular 1 from the project | 
					
						
							|  |  |  |  |   completely, but the key is to do this piece by piece without breaking the application. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   我们已经完成了准备工作,接下来就开始把PhoneCat升级到Angular 2。 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   我们将在Angular 2[升级模块](#upgrading-with-the-upgrade-adapter)的帮助下增量式的完成此项工作。 | 
					
						
							| 
									
										
										
										
											2016-09-12 08:35:02 +08:00
										 |  |  |  |   等我们完成的那一刻,就能把Angular 1从项目中完全移除了,但其中的关键是在不破坏此程序的前提下一小块一小块的完成它。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  | .alert.is-important  | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     The project also contains some animations, which we are not yet upgrading in this version of the guide. This will change in a later release. | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     该项目还包含一些动画,在此指南的当前版本我们先不升级它,等到后面的发行版再改。 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Let's install Angular 2 into the project, along with the SystemJS module loader. Take a look into the | 
					
						
							|  |  |  |  |   [Quickstart](../quickstart.html) guide and get the following configurations from there: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   我们来使用SystemJS模块加载器把Angular 2安装到项目中。 | 
					
						
							|  |  |  |  |   看看[“快速起步”](../quickstart.html)中的指南,并从那里获得如下配置: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   * Add Angular 2 and the other new dependencies to `package.json` | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   * 把Angular 2和其它新依赖添加到`package.json`中 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   * Add the new typings into `typings.json` | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   * 把新的类型定义添加到`typings.json`中 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   * The SystemJS configuration file `systemjs.config.js` to the project root directory. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   * 把SystemJS的配置文件`systemjs.config.js`添加到项目的根目录。 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   Once these are done, run: | 
					
						
							| 
									
										
										
										
											2016-02-05 17:23:35 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   这些完成之后,就运行: | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 17:23:35 +02:00
										 |  |  |  | code-example(format=""). | 
					
						
							|  |  |  |  |   npm install | 
					
						
							|  |  |  |  |   npm run typings install | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 17:23:35 +02:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   We can soon load Angular 2 dependencies into the application via `index.html`, | 
					
						
							|  |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   我们可以通过`index.html`来把Angular 2的依赖快速加载到应用中, | 
					
						
							|  |  |  |  |   但首先,我们得做一些目录结构调整。这是因为我们正准备从`node_modules`中加载文件,然而目前项目中的每一个文件都是从`/app`目录下加载的。 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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`: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   把`app/index.html`移入项目的根目录,然后把`package.json`中的开发服务器根目录也指向项目的根目录,而不再是`app`目录: | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeJson('upgrade-phonecat-2-hybrid/ts/package.ng1.json', {paths: 'scripts.start'}, 'package.json') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Now we're able to serve everything from the project root to the web browser. But we do *not* | 
					
						
							|  |  |  |  |   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: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   现在,我们能把项目根目录下的每一样东西发给浏览器了。但我们不想为了适应开发环境中的设置,被迫修改应用代码中用到的所有图片和数据的路径。因此,我们往`index.html`中添加一个`<base>`标签,它将导致各种相对路径被解析回`/app`目录: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/index.html', 'base', 'index.html') | 
					
						
							| 
									
										
										
										
											2016-04-27 11:28:22 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   现在我们可以通过SystemJS加载Angular 2了。我们将把Angular 2的填充库(polyfills) | 
					
						
							|  |  |  |  |   和SystemJS的配置加到`<head>`区的末尾,然后,我们就用`System.import`来加载实际的应用: | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/index.html', 'ng2', 'index.html') | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-27 11:28:22 -07:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   在我们从“快速起步”中拿来的`systemjs.config.js`文件中,我们还需要做一些调整,以适应我们的项目结构。 | 
					
						
							|  |  |  |  |   在使用SystemJS而不是`<base>` URL加载时,我们需要把浏览器指向项目的根目录。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js', 'paths', 'systemjs.config.js') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   ## Bootstrapping A Hybrid 1+2 PhoneCat | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   ## 引导PhoneCat的1+2混合式应用 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   接下来,我们把该应用程序引导改装为一个同时支持Angular 1和Angular 2的*混合式应用*。 | 
					
						
							| 
									
										
										
										
											2016-09-12 08:35:02 +08:00
										 |  |  |  |   然后,就能开始把这些不可分割的小块转换到Angular 2了。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   To bootstrap a hybrid application, we first need to initialize an `UpgradeAdapter`, | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   which [provides the glue](#upgrading-with-the-upgrade-adapter) that joins the two | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 22:22:48 +01:00
										 |  |  |  |   要引导一个混合式应用程序,我们首先得初始化一个`UpgradeAdapter`,它[提供了胶水](#upgrading-with-the-upgrade-adapter), | 
					
						
							|  |  |  |  |   用来把框架的两个不同版本粘在一起。我们在一个新文件`app/main.ts`中导入`UpgradeAdapter`类。 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   这个文件已经在`systemjs.config.js`文件中被配置成了应用的入口点,所以它已经被浏览器加载了。 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'import-adapter', 'app/main.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   We can then make an adapter by instantiating the class: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   然后我们可以制作一个适配器来实例化这个类: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'init-adapter') | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Our application is currently bootstrapped using the Angular 1 `ng-app` directive | 
					
						
							|  |  |  |  |   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`: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   我们的应用现在是使用宿主页面中附加到`<html>`元素上的`ng-app`指令引导的。 | 
					
						
							|  |  |  |  |   但在Angular 2中,它不再工作了。我们得切换成JavaScript驱动的引导方式。 | 
					
						
							|  |  |  |  |   所以,从`index.html`中移除`ng-app`属性,并把这些加载`main.ts`中: | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'bootstrap') | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   The arguments used here are the root element of the application (which is | 
					
						
							|  |  |  |  |   the same element we had `ng-app` on earlier), and the Angular 1.x modules | 
					
						
							|  |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   这里使用的参数是应用的根元素(也就是以前我们放`ng-app`的元素),和我们准备加载的Angular 1.x模块。 | 
					
						
							|  |  |  |  |   由于我们是通过`UpgradeAdapter`引导应用的,所以实际在运行的应用实际上是一个Angular 1+2的混合体。 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   This means we are now running both Angular 1 and 2 at the same time. That's pretty | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   exciting! We're not running any actual Angular 2 components yet though, | 
					
						
							|  |  |  |  |   so let's do that next. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:38 +01:00
										 |  |  |  |   我们现在同时运行着Angular 1和Angular 2。漂亮!不过我们还没有运行什么实际的Angular 2组件,接下来我们就做这件事。 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   ## Upgrading the Phone service | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   ## 升级`Phone`服务 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   The first piece we'll port over to Angular 2 is the `Phone` service, which | 
					
						
							|  |  |  |  |   resides in `app/core/phone/phone.service.ts` and makes it possible for components | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   to load phone information from the server. Right now it's implemented with | 
					
						
							|  |  |  |  |   ngResource and we're using it for two things: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-12 08:35:02 +08:00
										 |  |  |  |   我们要移植到Angular 2的第一块是`Phone`工厂(位于`app/js/core/phones.factory.ts`), | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   并且让它能帮助控制器从服务器上加载电话信息。目前,它是用`ngResource`实现的,我们用它做两件事: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   * For loading the list of all phones into the phone list component | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   * 把所有电话的列表加载到电话列表组件中。 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   * For loading the details of a single phone into the phone detail component. | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   * 把一台电话的详情加载到电话详情组件中。 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   We can replace this implementation with an Angular 2 service class, while | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   keeping our controllers in Angular 1 land. In the new version we'll just use | 
					
						
							| 
									
										
										
										
											2016-04-11 17:37:11 -06:00
										 |  |  |  |   the `Http` service from Angular 2 instead of ngResource. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   我们可以用Angular 2的服务类来替换这个实现,而把控制器继续留在Angular 1的地盘上。 | 
					
						
							|  |  |  |  |   在新版本中,我们将用来自Angular 2的`Http`服务代替`ngResource`。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-27 11:28:22 -07:00
										 |  |  |  |   Before the `Http` service is available for injection, we need to register | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   it into our application's dependency injector. We should import the `HTTP_PROVIDERS` | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   constant in `main.ts`: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   要让`Http`服务在注入时可用,我们得先把它注册进我们应用程序的依赖注入器中。我们要把`HTTP_PROVIDERS`常量导入到`app.module.ts`中: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'import-http') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   In a regular Angular 2 application we would now pass `HTTP_PROVIDERS` into | 
					
						
							|  |  |  |  |   the application bootstrap function. But we can't do that in a hybrid | 
					
						
							|  |  |  |  |   application such as the one we're working on. That's because the `bootstrap` | 
					
						
							|  |  |  |  |   method of  `UpgradeAdapter` expects Angular 1 modules as dependencies, | 
					
						
							|  |  |  |  |   not Angular 2 providers. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   在标准的Angular 2应用中,我们可以把`HTTP_PROVIDERS`传给应用程序的`bootstrap`函数。 | 
					
						
							|  |  |  |  |   但是在混合式应用中我们不能这么做 —— 比如现在这个。这是因为`UpgradeAdapter`的`bootstrap`方法 | 
					
						
							| 
									
										
										
										
											2016-07-07 08:22:36 +08:00
										 |  |  |  |   希望以Angular 1模块作为依赖,而不是Angular 2提供商。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   What we must do instead is register `HTTP_PROVIDERS` into the `UpgradeAdapter` | 
					
						
							|  |  |  |  |   separately. It has a method called `addProvider` for that purpose: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   这就是为什么我们必须单独把`HTTP_PROVIDERS`注册进`UpgradeAdapter`。为此,它提供了一个叫做`addProvider`的方法: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'add-http') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Now we're ready to upgrade the Phone service itself. We replace the ngResource-based | 
					
						
							|  |  |  |  |   service in `phone.service.ts` with a TypeScript class decorated as `@Injectable`: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   现在,我们已经准备好了升级`Phones`服务本身。我们将为`phone.service.ts`文件中基于ngResource的服务加上`@Injectable`装饰器: | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts', 'classdef', 'app/core/phone/phone.service.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   The `@Injectable` decorator will attach some dependency injection metadata | 
					
						
							|  |  |  |  |   to the class, letting Angular 2 know about its dependencies. As described | 
					
						
							|  |  |  |  |   by our [Dependency Injection Guide](../guide/dependency-injection.html), | 
					
						
							|  |  |  |  |   this is a marker decorator we need to use for classes that have no other | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |   Angular 2 decorators but still need to have their dependencies injected. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   `@Injectable`装饰器将把一些依赖注入相关的元数据附加到该类上,让Angular 2知道它的依赖信息。 | 
					
						
							|  |  |  |  |   就像在[依赖注入指南](../guide/dependency-injection.html)中描述过的那样, | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:38 +01:00
										 |  |  |  |   这是一个标记装饰器,我们要把它用在那些没有其它Angular 2装饰器,并且自己有依赖注入的类上。 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   In its constructor the class expects to get the `Http` service. It will | 
					
						
							|  |  |  |  |   be injected to it and it is stored as a private field. The service is then | 
					
						
							|  |  |  |  |   used in the two instance methods, one of which loads the list of all phones, | 
					
						
							|  |  |  |  |   and the other the details of a particular phone: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   在它的构造函数中,该类期待一个`Http`服务。`Http`服务将被注入进来并存入一个私有字段。 | 
					
						
							|  |  |  |  |   然后该服务在两个实例方法中被使用到,一个加载所有电话的列表,另一个加载一台指定电话的详情: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts', 'fullclass') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   The methods now return Observables of type `PhoneData` and `PhoneData[]`. This is | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   a type we don't have yet, so let's add a simple interface for it: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   该方法现在返回一个`Phone`类型或`Phone[]`类型的可观察对象(Observable)。 | 
					
						
							|  |  |  |  |   这是一个我们从未用过的类型,因此我们得为它新增一个简单的接口: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts', 'phonedata-interface', 'app/core/phone/phone.service.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   Here's the full, final code for the service: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   最终,该类的全部代码如下: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts', null, 'app/core/phone/phone.service.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   Notice that we're importing the `map` operator of the RxJS `Observable` separately. | 
					
						
							|  |  |  |  |   We need to do this for all RxJS operators that we want to use, since Angular 2 | 
					
						
							| 
									
										
										
										
											2015-12-15 14:36:37 +02:00
										 |  |  |  |   does not load all of them by default. | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:23:53 +08:00
										 |  |  |  |   注意,我们单独导入了RxJS `Observable`中的`map`操作符。 | 
					
						
							|  |  |  |  |   我们需要对想用的所有RxJS操作符这么做,因为Angular 2默认不会加载所有RxJS操作符。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   The new `Phone` service now has the same features that the original, ngResource based | 
					
						
							|  |  |  |  |   service did. Now we just need to register the new service into the application, so that | 
					
						
							|  |  |  |  |   our Angular 1 components will be able to use it. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   这个新的`Phones`服务现在有了和原来基于`ngResource`的服务相同的特性。 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   现在只要把这个新服务注册进应用程序,我们的Angular 1控制器就能使用它了。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   `UpgradeAdapter` has a `downgradeNg2Provider` method for the purpose of making | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Angular 2 services available to Angular 1 code. We can use it to plug in our | 
					
						
							|  |  |  |  |   `Phone` service: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   `UpgradeAdapter`有个`downgradeNg2Provider`方法就是用来让Angular 2的服务在Angular 1的代码中可用的。 | 
					
						
							|  |  |  |  |   我们可以使用它来插入我们的`Phone`服务: | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'phone-service', 'app/main.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   Note that we actually needed to do two registrations here: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   注意,我们实际上做了两次注册: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   1. Register `Phone` as an **Angular 2 provider** with the `addProvider` | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |      method. That's the same method that we used earlier for `HTTP_PROVIDERS`. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-07 08:22:36 +08:00
										 |  |  |  |   1. 用`addProvider`方法注册了一个名叫`Phone`的**Angular 2提供商**。这和我们以前使用`HTTP_PROVIDERS`的方法一样。 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   2. Register an **Angular 1 factory** called `phone`, which will be a *downgraded* | 
					
						
							|  |  |  |  |      version of the `Phone` Angular 2 service. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   2. 注册了一个名叫`phone`的**Angular 1工厂**,它是一个`Phones`服务的*降级*版。 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Now that we are loading `phone.service.ts` through an import that is resolved | 
					
						
							| 
									
										
										
										
											2016-06-02 01:54:54 +02:00
										 |  |  |  |   by SystemJS, we should **remove the <script> tag** for the service from `index.html`. | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   现在,我们正在用SystemJS加载`phone.service.ts`,我们应该从`index.html`中**移除该服务的`<script>`标签**。 | 
					
						
							|  |  |  |  |   这也是我们在升级所有组件时将会做的事。在从Angular 1向2升级的同时,我们也把代码从脚本移植为模块。 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   At this point we can switch our two components to use the new service | 
					
						
							|  |  |  |  |   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 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   accordingly: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   这时,我们可以把两个控制器从使用老的服务切换成使用新的。我们像降级过的`phones`工厂一样`$inject`它, | 
					
						
							|  |  |  |  |   但它实际上是一个`Phones`类的实例,并且我们可以据此注解它的类型: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ng1.ts', null, 'app/phone-list/phone-list.component.ts') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ng1.ts', null, 'app/phone-detail/phone-detail.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   What we have here are two Angular 1 components using an Angular 2 service! | 
					
						
							|  |  |  |  |   The components don't need to be aware of this, though the fact that the | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   service returns Observables and not Promises is a bit of a giveaway. | 
					
						
							|  |  |  |  |   In any case, what we've achieved is a migration of a service to Angular 2 | 
					
						
							|  |  |  |  |   without having to yet migrate the controllers that use it. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   这里的两个Angular 1控制器在使用Angular 2的服务!控制器不需要关心这一点,尽管实际上该服务返回的是可观察对象(Observable),而不是承诺(Promise)。 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   无论如何,我们达到的效果都是把服务移植到Angular 2,而不用被迫移植组件来使用它。 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  | .alert.is-helpful | 
					
						
							|  |  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |     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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |     我们也能使用`Observable`的`toPromise`方法来在服务中把这些可观察对象转变成承诺,以进一步减小组件控制器中需要修改的代码量。 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   ## Upgrading Components | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   ## 升级组件 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Next, let's upgrade our Angular 1 components to Angular 2 components. We'll | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   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*. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   接下来,我们把Angular 1的控制器升级成Angular 2的组件。我们每次升级一个,同时仍然保持应用运行在混合模式下。 | 
					
						
							|  |  |  |  |   在做转换的同时,我们还将自定义首个Angular 2*管道*。 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:38 +01:00
										 |  |  |  |   让我们先看看电话列表组件。它目前包含一个TypeScript控制器类和一个组件定义对象。重命名控制器类, | 
					
						
							|  |  |  |  |   并把Angular 1的组件定义对象更换为Angular 2 `@Component`装饰器,这样我们就把它变形为Angular 2 | 
					
						
							|  |  |  |  |   的组件了。然后,我们还从类中移除静态`$inject`属性。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ts', 'initialclass', 'app/phone-list/phone-list.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   The `selector` attribute is a CSS selector that defines where on the page the component | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-12 08:35:02 +08:00
										 |  |  |  |   `selector`属性是一个CSS选择器,用来定义组件应该被放在页面的哪。在Angular 1,我们基于组件名字来匹配, | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:38 +01:00
										 |  |  |  |   但是在Angular 2中,我们要有一个专门指定的选择器。本组件将会对应元素名字`phone-list`,和Angular 1版本一样。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   We now also need to convert the template of this component into Angular 2 syntax. | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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: | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:38 +01:00
										 |  |  |  |   现在,我们同时需要将组件的模版也转换为Angular 2语法。在搜索控制中,我们需要为两个`ngModel`使用Angular 2语法。 | 
					
						
							|  |  |  |  |   我们应该不需要再在表达式中使用`$ctrl`前缀: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.template.html', 'controls', 'app/phone-list/phone-list.template.html') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   In the list we need to replace the `ng-repeat` with an `*ngFor` and the | 
					
						
							|  |  |  |  |   `let var of iterable` syntax, which is [described in our | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   Template Syntax guide](../guide/template-syntax.html#directives). | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   For the images, we can replace `ng-src` with a binding to the standard `src` property. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   在列表中,我们需要把`ng-repeat`替换为`*ngFor`以及它的`let var of iterable`语法, | 
					
						
							|  |  |  |  |   该语法在[模板语法指南中讲过](../guide/template-syntax.html#directives)。 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   对于图片,我们可以把`ng-src`替换为一个标准的`src`属性(property)绑定。 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.template.html', 'list', 'app/phone-list/phone-list.template.html') | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Another thing that we've done here is that we've removed the use of `filter` and `orderBy` filters, | 
					
						
							|  |  |  |  |   and replaced them with a call to the `getPhones()` controller method. | 
					
						
							|  |  |  |  |   The built-in Angular filters `filter` and `orderBy` do not exist in Angular 2, | 
					
						
							|  |  |  |  |   so we need to do the filtering and sorting ourselves. We could define our own Angular 2 | 
					
						
							|  |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   我们在这里做的另一件事就是移除了`filter`和`orderBy`过滤器的使用,并把它们换成对控制器中`getPhones()`方法的调用。 | 
					
						
							| 
									
										
										
										
											2016-09-17 11:46:17 +08:00
										 |  |  |  |   内置的`filter`和`orderBy`在Angular 2中已经不存在了,所以我们得自己进行过滤和排序。 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   我们可以为此定义自己的Angular 2管道,但是在这个案例中,在组件本身实现过滤和排序逻辑反倒更方便。 | 
					
						
							|  |  |  |  |   我们希望`getPhones()`方法直接返回一个应用过当前过滤和排序规则的集合。 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ts', 'getphones', 'app/phone-list/phone-list.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   In the entrypoint file `main.ts` we're going to plug this component into our application. Instead | 
					
						
							|  |  |  |  |   of registering a component, we register a `phoneList` *directive*. | 
					
						
							|  |  |  |  |   The directive is a downgraded version of our Angular 2 component, and the `UpgradeAdapter` | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   handles the bridging between the two: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   在模块文件中,我们将把这个组件插入到程序中。我们不再注册控制器,而是注册一个`pcPhoneList`指令。 | 
					
						
							|  |  |  |  |   该指令是我们那个组件的降级版本,`UpgradeAdapter`负责桥接它们: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'phone-list', 'app/main.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   The `<angular.IDirectiveFactory>` type annotation here is to let the TypeScript compiler | 
					
						
							|  |  |  |  |   know that the return value of the downgrade method call will be something that can be | 
					
						
							|  |  |  |  |   used as a directive factory. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   这里的`<angular.IDirectiveFactory>`类型注解是为了让TypeScript编译器知道这个 | 
					
						
							|  |  |  |  |   降级方法(`downgradeNg2Component`)的返回值能作为指令工厂使用。 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 01:54:54 +02:00
										 |  |  |  |   At this point, also remove the <script> tag for the phone list component from `index.html`. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   这时,也从`index.html`中移除电话列表组件的`<script>`标签。 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   现在我们可以开始看看另一个组件,那就是电话详情。把`phone-detail.component.ts`的内容设置为这样: | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ts', 'initialclass', 'app/phone-detail/phone-detail.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   This is pretty similar to what we did with the phone list. The one new change | 
					
						
							|  |  |  |  |   here is the use of `@Inject` for the `$routeParams` dependency. It tells the | 
					
						
							|  |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   这和我们对电话列表所做的很相似。这里的一个新的更改是使用`@Inject`来获取`$routeParams`依赖。 | 
					
						
							|  |  |  |  |   它告诉Angular 2的注入器这个依赖该被映射成什么。我们在Angular 1的注入器中有一个名叫`$routeParams`的依赖, | 
					
						
							|  |  |  |  |   它是由Angular 1路由器提供的。 | 
					
						
							|  |  |  |  |   它也是当`PhoneDetails`还是Angular 1控制器的时候我们用过的那个。 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   The things is though, Angular 1 dependencies are not made automatically available to | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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`: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   问题是,Angular 1的依赖不会自动对Angular 2的组件可用,所以如果我们现在运行它,它将无法工作。 | 
					
						
							|  |  |  |  |   我们得显式的告诉`UpgradeAdapter`去升级`$routeParams`,以便它能被注入到Angular 2中。 | 
					
						
							|  |  |  |  |   我们可以在`main.ts`中这么做: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'routeparams', 'app/main.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   We now also need to convert the template of this component into Angular 2 syntax. | 
					
						
							|  |  |  |  |   Here is the new template in its entirety: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   我们现在也要把该组件的模板转变成Angular 2的语法。 | 
					
						
							|  |  |  |  |   这里是它完整的新模板: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.template.html', null, 'app/phone-detail/phone-detail.template.html') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   There are several notable changes here: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   这里有几个值得注意的改动: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   * We've removed the `$ctrl.` prefix from all expressions. | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   * 我们从所有表达式中移除了`$ctrl.`前缀。 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   * Just like we did in the phone list, we've replaced `ng-src` with property | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   bindings for the standard `src` property. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   * 正如我们在电话列表中做过的那样,我们把`ng-src`替换成了标准的`src`属性绑定。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   * We're using the property binding syntax around `ng-class`. Though Angular 2 | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |     does have [a very similar `ngClass`](../guide/template-syntax.html#directives) | 
					
						
							|  |  |  |  |     as Angular 1 does, its value is not magically evaluated as an expression. | 
					
						
							|  |  |  |  |     In Angular 2 we always specify  in the template when an attribute's value is | 
					
						
							|  |  |  |  |     a property expression, as opposed to a literal string. | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * 我们在`ng-class`周围使用了属性绑定语法。虽然Angular 2中有一个 | 
					
						
							|  |  |  |  |     和Angular 1中[非常相似的`ngClass`](../guide/template-syntax.html#directives)指令, | 
					
						
							|  |  |  |  |     但是它的值不会神奇的作为表达式进行计算。在Angular 2中,模板中的属性(Attribute)值总是被作为 | 
					
						
							|  |  |  |  |     属性(Property)表达式计算,而不是作为字符串字面量。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   * We've replaced `ng-repeat`s with `*ngFor`s. | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * 我们把`ng-repeat`替换成了`*ngFor`。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 20:17:56 +02:00
										 |  |  |  |   * We've replaced `ng-click` with an event binding for the standard `click`. | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * 我们把`ng-click`替换成了一个到标准`click`事件的绑定。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   * We've wrapped the whole template in an `ngIf` that causes it only to be | 
					
						
							|  |  |  |  |     rendered when there is a phone present. We need this because when the component | 
					
						
							|  |  |  |  |     first loads, we don't have `phone` yet and the expressions will refer to a | 
					
						
							|  |  |  |  |     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 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |     about cases where this is expected. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   * 我们把整个模板都包裹进了一个`ngIf`中,这导致只有当存在一个电话时它才会渲染。我们必须这么做, | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |     是因为组件首次加载时我们还没有`phone`变量,这些表达式就会引用到一个不存在的值。 | 
					
						
							|  |  |  |  |     和Angular 1不同,当我们尝试引用未定义对象上的属性时,Angular 2中的表达式不会默默失败。 | 
					
						
							|  |  |  |  |     我们必须明确指出这种情况是我们所期望的。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   在`main.ts`中,我们现在会注册一个`pcPhoneDetail`指令,而不再是组件。该指令是`PhoneDetail`组件的一个降级版。 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/main.ts', 'phone-detail', 'app/main.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-06-02 01:54:54 +02:00
										 |  |  |  |   We should now also remove the phone detail component <script> tag from `index.html`. | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:38 +01:00
										 |  |  |  |   我们现在应该从`index.html`中移除电话详情组件的<script>。 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   There's one additional step we need to take, which is to upgrade the | 
					
						
							|  |  |  |  |   `checkmark` filter that the template is using. We need an Angular 2 | 
					
						
							|  |  |  |  |   pipe instead of an Angular 1 filter. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   我们还有一个额外的步骤要做,那就是升级模板中用到的那个`checkmark`过滤器。我们需要用一个Angular 2管道替换Angular 1过滤器。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   While there is no upgrade method in the upgrade adapter for filters, we | 
					
						
							| 
									
										
										
										
											2015-12-31 08:46:32 +02:00
										 |  |  |  |   can just turn the filter function into a class that fulfills | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   the contract for Angular 2 Pipes. The implementation is the same as before. | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   It just comes in a different kind of packaging. While changing it, also | 
					
						
							| 
									
										
										
										
											2016-02-26 18:21:31 +02:00
										 |  |  |  |   rename the file to `checkmark.pipe.ts`: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   在升级适配器中并没有哪个方法可用于升级过滤器,但我们只要把过滤器函数转变成一个能满足Angular 2管道契约的类就可以了。 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:38 +01:00
										 |  |  |  |   它的实现方式和前面一样。它从一个不同类型的包而来。修改它的同时,也把它的文件名改为`checkmark.pipe.ts`: | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/core/checkmark/checkmark.pipe.ts', null, 'app/core/checkmark/checkmark.pipe.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   In the component we should now import and declare our newly created pipe (as well as | 
					
						
							| 
									
										
										
										
											2016-06-02 01:54:54 +02:00
										 |  |  |  |   remove the filter <script> tag from `index.html`): | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   当我们做这个修改时,也要同时从`core`模块文件中移除对该过滤器的注册。该模块的内容变成了: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ts', 'checkmark-pipe', 'app/phone-detail/phone-detail.component.ts') | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Switching To The Angular 2 Router And Bootstrap | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   ## 切换到Angular 2路由器和引导程序 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   At this point we've replaced all our Angular 1 application components with | 
					
						
							|  |  |  |  |   their Angular 2 counterparts. The application is still bootstrapped as a hybrid, | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |   but there isn't really any need for that anymore, and we can begin to | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   pull out the last remnants of Angular 1. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 19:23:17 +08:00
										 |  |  |  |   此时,我们已经把所有的Angular 1程序的各部件替换成了它们在Angular 2中的对应物。该应用仍然是作为混合应用进行引导的, | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   但实际上我们已经不需要它了,我们这就彻底移除Angular 1的残余势力。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   There are just two more things to do: We need to switch the router to | 
					
						
							|  |  |  |  |   the Angular 2 one, and then bootstrap the app as a pure Angular 2 app. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   接下来只有两件事要做:我们要把路由器切换成Angular 2的,然后把该程序作为纯粹的Angular 2应用进行引导。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Let's do the routing part first. Angular 2 comes with an [all-new router](router.html) | 
					
						
							| 
									
										
										
										
											2016-04-27 11:28:22 -07:00
										 |  |  |  |   that we can use for this. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   我们先来处理路由部分。Angular 2自带了一个[全新的路由](router.html)可以用来做这件事。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-27 11:28:22 -07:00
										 |  |  |  |   Angular 2 applications all have a *root component*, which, among other | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   things, is where we should plug in the router. We don't yet have such a root | 
					
						
							|  |  |  |  |   component, because our app is still managed as an Angular 1 app. | 
					
						
							| 
									
										
										
										
											2016-02-26 18:21:31 +02:00
										 |  |  |  |   Let's change this now and add an `AppComponent` class into a new file | 
					
						
							|  |  |  |  |   `app.component.ts`: | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   Angular 2应用全都有一个*根组件*,除具有其它功能外,它还是我们插入路由器的地方。 | 
					
						
							|  |  |  |  |   我们现在还不需要根组件,因为我们的程序还是被当做Angular 1的应用进行管理的。 | 
					
						
							|  |  |  |  |   我们这就改变这一点,并且把`AppComponent`类填加到一个叫`app.component.ts`的新文件中: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-3-final/ts/app/app.component.ts', null, 'app/app.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   This is a component that plugs in to an `<phonecat-app>` element on the page, | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   and has a simple template that only includes the router outlet component | 
					
						
							|  |  |  |  |   of the Angular router. This means that the component just renders the contents | 
					
						
							|  |  |  |  |   of the current route and nothing else. The `@RouteConfig` decorator defines | 
					
						
							|  |  |  |  |   the Angular 2 counterparts of our two routes. They refer directly to the | 
					
						
							|  |  |  |  |   two components. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:38 +01:00
										 |  |  |  |   这个组件将被插入到页面中一个`<phonecat-app>`元素中,并且其模板是只包含一个“路由器出口(router outlet)”组件。 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   这意味着该组件将只会渲染当前路由的内容,没别的。`@RouteConfig`装饰器定义了两个原有路由在Angular 2中的对应物。 | 
					
						
							|  |  |  |  |   它们直接引用了这两个组件。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   We should put this `<phonecat-app>` element in the HTML so that the root component | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   has something to attach to. It replaces the old Angular 1 `ng-view` directive: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:38 +01:00
										 |  |  |  |   我们还要把这个`<phonecat-app>`元素放进HTML中,以便这个根组件可以附加上去。它代替了Angular 1中原来的`ng-view`指令: | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-3-final/ts/index.html', 'appcomponent', 'index.html') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   In the `PhoneDetail` component we now need to change how the phone id parameter | 
					
						
							|  |  |  |  |   is received. There will be no more `$routeParams` injection available, because | 
					
						
							|  |  |  |  |   that comes from the Angular 1 router. Instead, what we have is a `RouteParams` | 
					
						
							|  |  |  |  |   object provided by the Angular 2 router. We use it to obtain the `phoneId` from | 
					
						
							|  |  |  |  |   the params: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   在`PhoneDetail`组件中,我们现在需要修改电话id参数的接收方式。再也没有`$routeParams`可被注入了, | 
					
						
							|  |  |  |  |   因为它来自Angular 1路由器。Angular 2路由器提供了一个`RouteParams`对象。我们使用它来从参数中获得`phoneId`。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-3-final/ts/app/phone-detail/phone-detail.component.ts', null, 'app/phone-detail/phone-detail.component.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   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 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   with the router, the new app component, and everything else in `main.ts` | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   使用它,我们就可以把来自`UpgradeAdapter`中的`bootstrap`方法切换到Angular 2自己的`bootstrap`了。 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   通过路由器和`main.ts`中新的应用组件,我们把它们导入到一起: | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-3-final/ts/app/main.ts', 'imports') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |   We'll now use the regular Angular 2 `bootstrap` function to bootstrap the app | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   instead of using `UpgradeAdapter`. The first argument to `bootstrap` is the | 
					
						
							|  |  |  |  |   application's root component `AppComponent`, and the second | 
					
						
							|  |  |  |  |   is an array of the Angular 2 providers that we want to make available for | 
					
						
							|  |  |  |  |   injection. In that array we include all the things we have been registering | 
					
						
							|  |  |  |  |   with  `upgradeAdapter.addProvider` until now, as well as the providers and | 
					
						
							|  |  |  |  |   directives of the router: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   我们现在就改用Angular 2中标准的`bootstrap`函数来引导本应用,而不再用`UpgradeAdapter`。 | 
					
						
							|  |  |  |  |   `bootstrap`的第一个参数是应用程序的根组件`AppComponent`,第二个参数是一个由Angular 2中希望被注入的 | 
					
						
							| 
									
										
										
										
											2016-07-07 08:22:36 +08:00
										 |  |  |  |   提供商构成的数组。这个数组中,我们包含了至今用`upgradeAdapter.addProvider`注册过的所有东西, | 
					
						
							|  |  |  |  |   比如各种提供商以及路由器中的指令: | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-3-final/ts/app/main.ts', 'bootstrap') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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`. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   这里我们还为路由器配置了一组东西,以便应用的URL路径和我们在Angular 1应用中用过的完全匹配: | 
					
						
							|  |  |  |  |   我们希望hash地址策略使用`!`前缀:`#!/phones`。 | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   At this point we are running a pure Angular 2 application! | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   此时,我们就在运行一个纯Angular 2应用了。 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   But there's actually one more cool thing we can do with the new router. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  |   We no longer have to hardcode the links to phone details from the phone | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   list, because the Angular 2 router is able to generate them for us with | 
					
						
							|  |  |  |  |   its `routerLink` directive. We just need to refer to the route names we | 
					
						
							|  |  |  |  |   used in the `@RouteConfig`: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   但是,基于新的路由,我们还能做一些更酷的事情。 | 
					
						
							|  |  |  |  |   在电话列表页中,我们不需要再把到电话详情页的链接硬编码进去,因为Angular 2可以通过`routerLink`指令帮我们生成它。 | 
					
						
							|  |  |  |  |   我们只需要引用`@RouteConfig`中用过的路由名称: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-3-final/ts/app/phone-list/phone-list.template.html', 'list', 'app/phone-list/phone-list.template.html') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   For this to work the directive just needs to be declared in the component: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  |   要让该指令能够工作,我们只需要把它在组件中声明一下: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-3-final/ts/app/phone-list/phone-list.component.ts', 'top') | 
					
						
							| 
									
										
										
										
											2016-02-26 18:21:31 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   ## Saying Goodbye to Angular 1 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   ## 再见,Angular 1 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   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 | 
					
						
							|  |  |  |  |   do with removing code - which of course is every programmer's favorite task! | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 07:26:29 +08:00
										 |  |  |  |   是时候把辅助训练的轮子摘下来了!让我们的应用作为一个纯粹、闪亮的Angular 2程序开始它的新生命吧。 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   剩下的所有任务就是移除代码 —— 这当然是每个程序员最喜欢的任务! | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   If you haven't already, remove all references to the `UpgradeAdapter` from `main.ts`. | 
					
						
							|  |  |  |  |   Also remove the Angular 1 bootstrap code. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   请从`main.ts`中移除所有到`UpgradeAdapter`的引用,并移除Angular 1的引导代码。 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   When you're done, this is what `main.ts` should look like: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   都完成了之后,`main.ts`看起来应该像这样: | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExample('upgrade-phonecat-3-final/ts/app/main.ts', null, 'app/main.ts') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   You may also completely remove the following files. They are Angular 1 | 
					
						
							|  |  |  |  |   module configuration files and not needed in Angular 2: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   我们还要完全移除了下列文件。它们是Angular 1的模块配置文件和类型定义文件,在Angular 2中不需要了: | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   * `app/app.module.ts` | 
					
						
							|  |  |  |  |   * `app/app.config.ts` | 
					
						
							|  |  |  |  |   * `app/core/core.module.ts` | 
					
						
							|  |  |  |  |   * `app/core/phone/phone.module.ts` | 
					
						
							|  |  |  |  |   * `app/phone-detail/phone-detail.module.ts` | 
					
						
							|  |  |  |  |   * `app/phone-list/phone-list.module.ts` | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   The external typings for Angular 1 may be uninstalled as well. The only ones | 
					
						
							|  |  |  |  |   we still need are for Jasmine and Angular 2 polyfills. | 
					
						
							| 
									
										
										
										
											2016-02-26 18:21:31 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   Angular 1的外部类型定义文件还需要被反安装。我们现在只需要Jasmine的那些。 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | code-example(format=""). | 
					
						
							|  |  |  |  |   npm run typings uninstall jquery -- --save --global | 
					
						
							|  |  |  |  |   npm run typings uninstall angular -- --save --global | 
					
						
							|  |  |  |  |   npm run typings uninstall angular-route -- --save --global | 
					
						
							|  |  |  |  |   npm run typings uninstall angular-resource -- --save --global | 
					
						
							|  |  |  |  |   npm run typings uninstall angular-mocks -- --save --global | 
					
						
							|  |  |  |  |   npm run typings uninstall angular-animate -- --save --global | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   最后,从`index.html`和`karma.conf.js`中,移除所有到Angular 1脚本的引用,比如jQuery。 | 
					
						
							|  |  |  |  |   当这些全部做完时,`index.html`看起来应该是这样的: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-3-final/ts/index.html', 'full', 'index.html') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   That is the last we'll see of Angular 1! It has served us well but now | 
					
						
							|  |  |  |  |   it's time to say goodbye. | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   这是我们最后一次看到Angular 1了!它曾经带给我们很多帮助,不过现在,是时候说再见了。 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | .l-main-section | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   # Appendix: Upgrading PhoneCat Tests | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:58:59 +08:00
										 |  |  |  |   # 附录:升级PhoneCat的测试 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   测试不仅要在升级过程中被保留,它还是确保应用在升级过程中不会被破坏的一个安全指示器。 | 
					
						
							|  |  |  |  |   要达到这个目的,E2E测试尤其有用。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   ## E2E Tests | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   ## E2E测试 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   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, | 
					
						
							|  |  |  |  |   E2E tests access our application from the *outside* by interacting with | 
					
						
							|  |  |  |  |   the various UI elements the app puts on the screen. E2E tests aren't really that | 
					
						
							|  |  |  |  |   concerned with the internal structure of the application components. That | 
					
						
							|  |  |  |  |   also means that although we modify our project quite a bit during the upgrade, the E2E | 
					
						
							|  |  |  |  |   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. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   PhoneCat项目中同时有基于Protractor的E2E测试和一些基于Karma的单元测试。 | 
					
						
							|  |  |  |  |   对这两者来说,E2E测试的转换要容易得多:根据定义,E2E测试通过与应用中显示的这些UI元素互动,从*外部*访问我们的应用来进行测试。 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:38 +01:00
										 |  |  |  |   E2E测试实际上并不关心这些应用中各部件的内部结构。这也意味着,虽然我们已经修改了此应用程序, | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   但是E2E测试套件仍然应该能像以前一样全部通过。因为从用户的角度来说,我们并没有改变应用的行为。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   在转成TypeScript期间,我们不用做什么就能让E2E测试正常工作。 | 
					
						
							|  |  |  |  |   只有当我们想做些修改而把组件及其模板升级到Angular 2时才需要做些处理。 | 
					
						
							|  |  |  |  |   这是因为E2E测试有一些匹配器是Angular 1中特有的。对于PhoneCat来说,为了让它能在Angular 2下工作,我们得做下列修改: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | table | 
					
						
							|  |  |  |  |   tr | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |     th | 
					
						
							|  |  |  |  |       p Previous code | 
					
						
							|  |  |  |  |       p 老代码 | 
					
						
							|  |  |  |  |     th | 
					
						
							|  |  |  |  |       p New code | 
					
						
							|  |  |  |  |       p 新代码 | 
					
						
							|  |  |  |  |     th | 
					
						
							|  |  |  |  |       p Notes | 
					
						
							|  |  |  |  |       p 说明 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   tr | 
					
						
							|  |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |         `by.repeater('phone in $ctrl.phones').column('phone.name')` | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         `by.css('.phones .name')` | 
					
						
							|  |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         The repeater matcher relies on Angular 1 `ng-repeat` | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         repeater匹配器依赖于Angular 1中的`ng-repeat` | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   tr | 
					
						
							|  |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |         `by.repeater('phone in $ctrl.phones')` | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         `by.css('.phones li')` | 
					
						
							|  |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         The repeater matcher relies on Angular 1 `ng-repeat` | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         repeater匹配器依赖于Angular 1中的`ng-repeat` | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   tr | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |     td | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |       :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |         `by.model('$ctrl.query')` | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         `by.css('input')` | 
					
						
							|  |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         The model matcher relies on Angular 1 `ng-model` | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         model匹配器依赖于Angular 1中的`ng-model` | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   tr | 
					
						
							|  |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |         `by.model('$ctrl.orderProp')` | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         `by.css('select')` | 
					
						
							|  |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         The model matcher relies on Angular 1 `ng-model` | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         model匹配器依赖于Angular 1中的`ng-model` | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   tr | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |         `by.binding('$ctrl.phone.name')` | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         `by.css('h1')` | 
					
						
							|  |  |  |  |     td | 
					
						
							|  |  |  |  |       :marked | 
					
						
							|  |  |  |  |         The binding matcher relies on Angular 1 data binding | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |         binding匹配器依赖于Angular 1的数据绑定 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   When the bootstrap method is switched from that of `UpgradeAdapter` to | 
					
						
							|  |  |  |  |   pure Angular 2, Angular 1 ceases to exist on the page completely. | 
					
						
							|  |  |  |  |   At this point we need to tell Protractor that it should not be looking for | 
					
						
							|  |  |  |  |   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`: | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   当引导方式从`UpgradeAdapter`切换到纯Angular 2的时,Angular 1就从页面中完全消失了。 | 
					
						
							|  |  |  |  |   此时,我们需要告诉Protractor,它不用再找Angular 1应用了,而是从页面中查找*Angular 2*应用。 | 
					
						
							|  |  |  |  |   于是在`protractor-conf.js`中做下列修改: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | code-example(format=""). | 
					
						
							|  |  |  |  |   useAllAngular2AppRoots: true, | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Also, there are a couple of Protractor API calls in the PhoneCat test code that | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   are using the Angular 1 `$location` service under the hood. As that | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   service is no longer there after the upgrade, we need to replace those calls with ones | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  |   that use WebDriver's generic URL APIs instead. The first of these is | 
					
						
							|  |  |  |  |   the redirection spec: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   同样,我们的测试代码中有两个Protractor API调用内部使用了`$location`。该服务没有了, | 
					
						
							|  |  |  |  |   我们就得把这些调用用一个WebDriver的通用URL API代替。第一个API是“重定向(redirect)”规约: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 13:58:01 -07:00
										 |  |  |  | +makeExample('upgrade-phonecat-3-final/e2e-spec.ts', 'redirect', 'e2e-tests/scenarios.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   And the second is the phone links spec: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   第二个是“电话链接(phone links)”规约: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 13:58:01 -07:00
										 |  |  |  | +makeExample('upgrade-phonecat-3-final/e2e-spec.ts', 'links', 'e2e-tests/scenarios.ts') | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   ## Unit Tests | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   ## 单元测试 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   For unit tests, on the other hand, more conversion work is needed. Effectively | 
					
						
							|  |  |  |  |   they need to be *upgraded* along with the production code. | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   另一方面,对于单元测试来说,需要更多的转化工作。实际上,它们需要随着产品代码一起升级。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   在转成TypeScript期间,严格来讲没有什么改动是必须的。但把单元测试代码转成TypeScript仍然是个好主意, | 
					
						
							|  |  |  |  |   产品代码从TypeScript中获得的那些增益也同样适用于测试代码。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   比如,在这个电话详情组件的规约中,我们不仅用到了ES2015中的箭头函数和块作用域变量这些特性,还为所用的一些 | 
					
						
							|  |  |  |  |   Angular 1服务提供了类型定义。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.component.spec.ts', null, 'app/phone-detail/phone-detail.component.spec.ts') | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-26 18:21:31 +02:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Once we start the upgrade process and bring in SystemJS, configuration changes | 
					
						
							|  |  |  |  |   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: | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   一旦我们开始了升级过程并引入了SystemJS,还需要对Karma进行配置修改。 | 
					
						
							|  |  |  |  |   我们需要让SystemJS加载所有的Angular 2新代码, | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/karma-test-shim.1.js', null, 'karma-test-shim.js') | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   The shim first loads the SystemJS configuration, then Angular 2's test support libraries, | 
					
						
							|  |  |  |  |   and then the application's spec files themselves. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   这个shim文件首先加载了SystemJS的配置,然后是Angular 2的测试支持库,然后是应用本身的规约文件。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Karma configuration should then be changed so that it uses the application root dir | 
					
						
							|  |  |  |  |   as the base directory, instead of `app`. | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   然后需要修改Karma配置,来让它使用本应用的根目录作为基础目录(base directory),而不是`app`。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/karma.conf.ng1.js', 'basepath', 'karma.conf.js') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Once this is done, we can load SystemJS and other dependencies, and also switch the configuration | 
					
						
							|  |  |  |  |   for loading application files so that they are *not* included to the page by Karma. We'll let | 
					
						
							|  |  |  |  |   the shim and SystemJS load them. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   一旦这些完成了,我们就能加载SystemJS和其它依赖,并切换配置文件来加载那些应用文件,而*不用*在Karma页面中包含它们。 | 
					
						
							|  |  |  |  |   我们要让这个shim文件和SystemJS去加载它们。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/karma.conf.ng1.js', 'files', 'karma.conf.js') | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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: | 
					
						
							| 
									
										
										
										
											2016-02-04 18:30:36 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   由于Angular 2组件中的HTML模板也同样要被加载,所以我们得帮Karma一把,帮它在正确的路径下找到这些模板: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/karma.conf.ng1.js', 'html', 'karma.conf.js') | 
					
						
							| 
									
										
										
										
											2016-02-05 17:23:35 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   The unit test files themselves also need to be switched to Angular 2 when their production | 
					
						
							|  |  |  |  |   counterparts are switched. The specs for the checkmark pipe are probably the most straightforward, | 
					
						
							|  |  |  |  |   as the pipe has no dependencies: | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-12 08:35:02 +08:00
										 |  |  |  |   如果产品代码被切换到了Angular 2,单元测试文件本身也需要切换过来。对勾(checkmark)管道的规约可能是最简单的,因为它没有任何依赖: | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/core/checkmark/checkmark.pipe.spec.ts', null, 'app/core/checkmark/checkmark.pipe.spec.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 17:23:35 +02:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   `Phone`服务的测试会牵扯到一点别的。我们需要把模拟版的Angular 1 `$httpBackend`服务切换到模拟板的Angular 2 Http后端。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.spec.ts', null, 'app/core/phone/phone.service.spec.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-02-04 18:30:36 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   对于组件的规约,我们可以模拟出`Phone`服务本身,并且让它提供电话的数据。我们可以对这些组件使用Angular的组件单元测试API。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.spec.ts', null, 'app/phone-detail/phone-detail.component.spec.ts') | 
					
						
							| 
									
										
										
										
											2016-05-28 15:52:07 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.spec.ts', null, 'app/phone-list/phone-list.component.spec.ts') | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   Finally, we need to revisit both of the component tests when we switch to the Angular 2 | 
					
						
							|  |  |  |  |   router. For the details component we need to provide an Angular 2 `RouteParams` object | 
					
						
							|  |  |  |  |   instead of using the Angular 1 `$routeParams`. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   最后,当我们切换到Angular 2路由时,我们需要重新过一遍这些组件测试。对详情组件来说,我们需要提供一个Angular 2的 | 
					
						
							|  |  |  |  |   `RouteParams`对象,而不再用Angular 1的`$routeParams`。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-3-final/ts/app/phone-detail/phone-detail.component.spec.ts', 'routeparams', 'app/phone-detail/phone-detail.component.spec.ts') | 
					
						
							| 
									
										
										
										
											2015-12-15 08:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-05-29 17:20:36 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:35:37 +08:00
										 |  |  |  |   对于电话列表组件来说,我们需要为路由器本身略作设置,以便它的路由链接(`routerLink`)指令能够正常工作。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 17:17:21 +03:00
										 |  |  |  | +makeExample('upgrade-phonecat-3-final/ts/app/phone-list/phone-list.component.spec.ts', 'routestuff', 'app/phone-list/phone-list.component.spec.ts') |