版本:v4.0.0+2
在教程的这一部分,你将修改启动程序来显示一个英雄的信息。然后你间添加编辑英雄数据的能力。完成后,应用看起来这样——在线示例 (查看源码)。
回顾上一章
在开始编写代码之前,让我们验证你是否有如下的文件结构。如果没有,回到前一章,查看详细介绍。
如果应用不运行了,启动应用。当你做出修改时,通过刷新浏览器保持继续运行。
显示英雄
为AppComponent
添加两个属性:一个表示应用名字的title
属性,和一个表示名为 “Windstorm” 的英雄的hero
属性。
// lib/app_component.dart (AppComponent class)
class AppComponent {
final title = 'Tour of Heroes';
var hero = 'Windstorm';
}
现在,使用数据绑定到这些新属性,更新@Component
注解中的模板。
// lib/app_component.dart (@Component)
template: '<h1>{{title}}</h1><h2>{{hero}} details!</h2>',
刷新浏览器,页面将显示标题和英雄名字。
双大括号是 Angular 的插值表达式语法。这些插值绑定组件的title
和hero
属性值,作为字符串,插入到 HTML 的标题标签中。
更多关于插值表达式的内容请看显示数据章节。
创建 Hero 类
英雄需要更多属性。把hero
从一个字符串字面量转换成一个类。
创建一个具有 id
和 name
属性的Hero
类。把这些属性添加到 app_component.dart
文件的顶部附近,仅在 import 语句下面。
// lib/app_component.dart (Hero class)
class Hero {
final int id;
String name;
Hero(this.id, this.name);
}
在AppComponent
类,重构组件的 hero
属性为 Hero
类型,然后以id
为1
、以name
为 “Windstorm”,初始化它。
// lib/app_component.dart (hero property)
Hero hero = new Hero(1, 'Windstorm');
因为我们把 hero 从一个字符串换成了对象,所以更新模板中的绑定,来引用 hero 的name
属性。
template: '<h1>{{title}}</h1><h2>{{hero.name}} details!</h2>',
刷新浏览器,页面将继续显示英雄的名字。
添加多行 HTML 模板
为了显示英雄的所有属性,添加一个<div>
来显示英雄的id
属性,另一个<div>
来显示英雄的name
属性。为了使模板保持可读性,每个div
独自占一行。
// lib/app_component.dart (multi-line strings)
template: '''
<h1>{{title}}</h1>
<h2>{{hero.name}} details!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div><label>name: </label>{{hero.name}}</div>
''',
使应用名字可编辑
用户应该能够在一个<input>
文本框中编辑英雄名字。文本框应该既能显示 应用的name
属性,又能根据用户的输入更新 属性。
你需要在<input>
表单元素和hero.name
属性之间双向数据绑定。
使用双向绑定
重构模板中的英雄名字使其看起来如下:
<div>
<label>name: </label>
<input [(ngModel)]="hero.name" placeholder="name">
</div>
[(ngModel)]
是 Angular 语法,绑定hero.name
属性到文本框。数据在两个方向流动:从属性到文本框,从文本框又回到属性。
声明非核心指令
不幸的是,这样改变之后,程序立即崩溃了!
模板解析错误
如果你刷新浏览器,应用不会加载。要知道原因,查看pub serve
输出。模板解析器不能识别ngModel
,AppComponent
解析错误:
Error running TemplateGenerator for forms|lib/src/hero_form_component.dart.
Error: Template parse errors:
Can't bind to 'ngModel' since it isn't a known native property or known directive. Please fix typo or add to directives list.
[(ngModel)]="hero.name"
^^^^^^^^^^^^^^^^^^^^^^^
更新 pubspec
angular_forms
库包含在它自己的包里。在 pubsepc dependencies中添加包:
// {toh-0 → toh-1}/pubspec.yaml
dependencies:
angular: ^4.0.0
+ angular_forms: ^1.0.0
更新 @Component(directives:...)
尽管NgModel
在angular_forms库中是一个有效的 Angular 指令,但默认它不是可用的。
在模板中使用任意 Angular 指令之前,需要在组件的@Component
注解的directives
参数中列出它们。你可以单独的添加指令,或为了方便添加formDirectives列表(注意新的导入语句):
// lib/app_component.dart (directives)
import 'package:angular_forms/angular_forms.dart';
@Component(
selector: 'my-app',
// ···
directives: const [formDirectives],
)
刷新浏览器,应用应该可用再次运行了。你可以编辑英雄名字并且在文本框上方的<h2>
中立刻看到变化的反应。
你已走过的路
来盘点一下都构建了哪些内容。
- 英雄指南应用使用双大括号插值表达式(单向数据绑定的一种形式)来显示应用的标题和
Hero
对象的属性。 - 使用 Dart 模板字符串写了一个多行模板,使模板更有可读性。
- 使用内置的
ngModel
指令为<input>
元素添加双向数据绑定。这种绑定既可以显示英雄的名字又允许用户修改它。 - 添加formDirectives到应用的
@Component
注解的directives
参数,以使 Angular 知道ngModel
是在哪里定义i的。
完整的app_component.dart
是这样的:
// lib/app_component.dart
import 'package:angular/angular.dart';
import 'package:angular_forms/angular_forms.dart';
@Component(
selector: 'my-app',
template: '''
<h1>{{title}}</h1>
<h2>{{hero.name}} details!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div>
<label>name: </label>
<input [(ngModel)]="hero.name" placeholder="name">
</div>
''',
directives: const [formDirectives],
)
class AppComponent {
final title = 'Tour of Heroes';
Hero hero = new Hero(1, 'Windstorm');
}
class Hero {
final int id;
String name;
Hero(this.id, this.name);
}
下一步