作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
Joaquin是一名全栈和混合移动应用程序开发人员,在WebMD和Getty Images等公司工作了13年以上.
俗话说,“每年互联网都会崩溃”,而开发者通常不得不去修复它. 与期待已久的 Angular version 9, 有人可能认为这是适用的, 在早期版本上开发的应用程序需要经历一个重大的迁移过程.
但事实并非如此! Angular团队完全重新设计了它的编译器, 导致更快的构建, faster test runs, 更小的包装尺寸, 最重要的是, 与旧版本的向后兼容性. 有了Angular 9,开发人员基本上可以获得所有的特权,而没有任何麻烦.
在这篇Angular 9教程中,我们将从头开始构建一个Angular应用程序. 我们将使用Angular 9的一些最新特性,并在此过程中介绍其他改进.
让我们开始我们的Angular项目示例. 首先,让我们安装最新版本的Angular CLI:
NPM install -g @angular/cli
我们可以通过运行来验证Angular CLI的版本 ng version
.
接下来,让我们创建一个Angular应用:
Ng new ng9-app——create-application=false——strict
我们使用了两个参数 ng new
command:
——创建应用程序= false
会告诉CLI只生成工作空间文件吗. 当我们需要一个以上的应用程序和多个库时,这将帮助我们更好地组织代码.--strict
会添加更严格的规则来强制TypeScript类型和代码清洁度吗.因此,我们有了一个基本的工作空间文件夹和文件.
现在,让我们添加一个新的应用程序. 为此,我们将运行:
生成应用程序tv-show-rating
我们会被提示:
? 你是否愿意与Angular团队分享这个项目的匿名使用数据
谷歌根据谷歌的隐私政策在http://policies.google.com/privacy? For more
详细信息以及如何更改此设置,请参见http://angular.io/analytics. No
? 你想添加Angular路由吗? Yes
? 您希望使用哪种样式表格式? SCSS
Now, if we run ng serve
,我们将看到应用程序在初始框架下运行.
If we run ng build --prod
,我们可以看到生成的文件列表.
每个文件都有两个版本. 一种是与传统浏览器兼容, 另一个是针对ES2015编译的, 它使用较新的api,需要更少的填充运行在浏览器上.
Angular 9的一大改进是包的大小. 根据Angular团队的说法,对于大型应用程序,你可以看到高达40%的下降.
对于新创建的应用程序, bundle的大小与Angular 8非常相似, 但随着应用的发展, 你会看到包的大小比. previous versions.
Angular 9中引入的另一个特性是,如果有任何错误,它会向我们发出警告 component 样式CSS文件大于定义的阈值.
这将帮助我们捕获错误的样式导入或庞大的组件样式文件.
接下来,我们将添加一个表单来对电视节目进行评级. 为此,首先,我们将安装 bootstrap
and ng-bootstrap
:
NPM install bootstrap @ng-bootstrap/ng-bootstrap
Angular 9的另一个改进是i18n(国际化). 以前,开发人员需要为应用程序中的每个地区运行完整的构建. 相反,Angular 9让我们只构建一次应用,然后在构建后的过程中生成所有的i18n文件, 显著减少构建时间. Since ng-bootstrap
有一个依赖于i18n的包,我们将把新包添加到我们的项目中:
添加@angular/ localalize
接下来,我们将添加Bootstrap主题到我们的应用程序 styles.scss
:
@ import " ~引导/ scss引导”;
我们会包括 NgbModule
and ReactiveFormsModule
in our AppModule
on app.module.ts
:
// ...
从“@angular/forms”中导入{ReactiveFormsModule};
从“@ng-bootstrap/ng-bootstrap”中导入{NgbModule};
@NgModule({
imports: [
// ...
ReactiveFormsModule,
NgbModule
],
})
接下来,我们将进行更新 app.component.html
我们的表单有一个基本的网格:
并生成表单组件:
TvRatingForm
Let’s update tv-rating-form.component.html
并添加表单来对电视节目进行评级.
And tv-rating-form.component.ts
看起来像这样:
// ...
导出类TvRatingFormComponent实现OnInit {
tvShows = [
{name: '最好打电话给Saul!' },
{name: 'Breaking Bad'},
{ name: 'Lost' },
{name: 'Mad men'}
];
form = new FormGroup({
new FormControl(", Validators . ".required),
评级:new FormControl(”,Validators.required),
});
submit() {
alert(JSON.stringify(this.form.value));
this.form.reset();
}
}
最后,我们将表单添加到 app.component.html
:
至此,我们有了一些基本的UI功能. Now, if we run ng serve
再一次,我们可以看到它在运行.
Before we move on, 让我们快速浏览一下Angular 9为帮助调试而添加的一些有趣的新特性. 因为这是我们日常工作中很常见的任务, 知道是什么改变让我们的生活变得更容易一点是值得的.
Angular 9和Angular Ivy中引入的另一个重大改进是调试体验. 编译器现在可以检测到更多的错误,并以更“可读”的方式抛出它们.
让我们看看实际情况. 首先,我们将激活模板检入 tsconfig.json
:
{
// ...
" angularCompilerOptions ": {
“fullTemplateTypeCheck”:没错,
“strictInjectionParameters”:没错,
“strictTemplates”:真的
}
}
Now, if we update tvShows
array and rename name
to title
:
tvShows = [
{title: '最好打电话给扫罗!' },
{title: 'Breaking Bad'},
{title: 'Lost'},
{标题:《欧博体育app下载》}
];
我们将从编译器得到一个错误.
这种类型检查将允许我们防止打字错误和错误地使用TypeScript类型.
@Input()
我们得到的另一个好的验证是 @Input()
. 例如,我们可以把这个加到 tv-rating-form.component.ts
:
@Input() title: string;
…and bind it in app.component.html
:
…and then change app.component.ts
like so:
// ...
导出类AppComponent {
title = null;
}
如果我们做了这三个更改,我们将从编译器获得另一种类型的错误.
如果我们想绕过它,我们 can use $any()
将值强制转换为的模板 any
并修复错误:
解决这个问题的正确方法是 title
关于nullable表单:
@Input() title: string | null;
ExpressionChangedAfterItHasBeenCheckedError
in Angular 9 IvyAngular开发中最可怕的错误之一就是 ExpressionChangedAfterItHasBeenCheckedError
. Thankfully, Ivy以更清晰的方式输出错误, 这样更容易找到问题的来源.
那么,让我们来介绍一个 ExpressionChangedAfterItHasBeenCheckedError
error. 要做到这一点,首先,我们将生成一个服务:
ng g s Title
接下来,我们将添加a BehaviorSubject
,以及访问 Observable
并发出一个新的值.
导出类TitleService {
private bs = new BehaviorSubject < string > ('');
constructor() {}
get title$() {
return this.bs.asObservable();
}
更新(标题:字符串){
this.bs.next(title);
}
}
之后,我们把这个加到 app.component.html
:
{{title$ | async}}
And in app.component.ts
,我们将注射 TitleService
:
导出类AppComponent实现OnInit {
// ...
title$: Observable < string > ;
constructor(
private titleSvc: TitleService
) {}
ngOnInit() {
this.title$ = this.titleSvc.title$;
}
// ...
}
Finally, in tv-rating-form.component.ts
, we’ll inject TitleService
更新的标题 AppComponent
,这将抛出一个 ExpressionChangedAfterItHasBeenCheckedError
error.
// ...
constructor(
private titleSvc: TitleService
) {
}
ngOnInit() {
this.titleSvc.update('new title!');
}
现在我们可以在浏览器的开发控制台中看到详细的错误,并单击 app.component.html
会告诉我们错误在哪里.
我们可以通过将服务调用包装为 setTimeout
:
setTimeout(() => {
this.titleSvc.update('new title!');
});
要理解为什么 ExpressionChangedAfterItHasBeenCheckedError
错误发生,探索其他可能性, Maxim Koretskyi的帖子 关于这个话题值得一读.
Angular Ivy允许我们以更清晰的方式呈现错误,并帮助我们在代码中强制使用TypeScript类型. 在下一节中, 我们将介绍一些利用Ivy和调试的常见场景.
在Angular 9中,引入了一个新的测试API 组件利用. 其背后的思想是消除与DOM交互所需的所有繁琐工作, 使它更容易使用和更稳定的运行.
组件线束API包含在 @angular/cdk
所以让我们首先在我们的项目中安装它:
NPM install @angular/cdk
现在我们可以编写一个测试并利用组件控制. In tv-rating-form.component.spec.ts
,让我们设置测试:
从“@ng-bootstrap/ng-bootstrap”中导入{NgbModule};
从“@angular/forms”中导入{ReactiveFormsModule};
describe('TvRatingFormComponent', () => {
let component: TvRatingFormComponent;
let fixture: ComponentFixture < TvRatingFormComponent > ;
beforeEach(async (() => {
TestBed.configureTestingModule ({
imports: [
NgbModule,
ReactiveFormsModule
],
声明(TvRatingFormComponent):
}).compileComponents ();
}));
// ...
});
接下来,让我们实现a ComponentHarness
for our component. 我们将创建两个束带:一个用于 TvRatingForm
,另一个是 NgbRating
. ComponentHarness
requires a static
field, hostSelector
,它应该取组件的选择器的值.
// ...
从“@angular/cdk/testing”中导入{ComponentHarness, HarnessLoader};
从“@angular/cdk/testing/testbed”中导入{TestbedHarnessEnvironment};
类TvRatingFormHarness扩展ComponentHarness {
static hostSelector = 'app-tv-rating-form';
}
类NgbRatingHarness扩展ComponentHarness {
static hostSelector = 'ngb-rating';
}
// ...
For our TvRatingFormHarness
,我们将为提交按钮创建一个选择器,并创建一个函数来触发 click
. 您可以看到实现它变得多么容易.
类TvRatingFormHarness扩展ComponentHarness {
// ...
protected getButton = this.locatorFor(“按钮”);
async submit() {
Const button =等待这个.getButton();
await button.click();
}
}
接下来,我们将添加方法来设置评级. Here we use locatorForAll
去寻找所有的 代表用户可以点击的星星的元素. The
rate
函数只是获得所有可能的评级的星星,并点击一个对应的值发送.
类NgbRatingHarness扩展ComponentHarness {
// ...
protected getRatings =这个.locatorForAll(跨度:不.sr-only)');
异步速率(值:number) {
Const ratings =等待这个.getRatings();
返回等级[value - 1].click();
}
}
最后缺少的是连接 TvRatingFormHarness
to NgbRatingHarness
. 要做到这一点,我们只需在 TvRatingFormHarness
class.
类TvRatingFormHarness扩展ComponentHarness {
// ...
getRating = this.locatorFor (NgbRatingHarness);
// ...
}
现在,让我们编写测试:
describe('TvRatingFormComponent', () => {
// ...
it('should pop an alert on submit', async () => {
spyOn(窗口,“警报”);
Const select = fixture.debugElement.query(By.css('select')).nativeElement;
select.value = 'Lost';
select.dispatchEvent(新事件('改变'));
fixture.detectChanges();
const harness = await TestbedHarnessEnvironment.harnessForFixture(夹具,TvRatingFormHarness);
Const评级=等待控制.getRating();
await rating.rate(1);
await harness.submit();
expect(window.alert).toHaveBeenCalledWith('{“tvShow”:“失去”,“等级”:1}”);
});
});
注意,对于 select
在表单中,我们没有实现通过线束来设置它的值. 这是因为API仍然不支持选择选项. 但是这给了我们一个比较在组件控制之前与元素交互的机会.
做测试前还有最后一件事. We need to fix app.component.spec.ts
since we updated title
to be null
.
describe('AppComponent', () => {
// ...
it(`should have as title 'tv-show-rating'`, () => {
const fixture = TestBed.createComponent (AppComponent);
Const app = fixture.componentInstance;
expect(app.title).toEqual(null);
});
});
Now, when we run ng test
, our test passes.
让我们通过添加到Firestore的连接并在数据库中保存评级来结束我们的Angular 9教程.
要做到这一点,我们需要 创建Firebase项目. 然后,我们将安装所需的依赖项.
NPM install @angular/fire firebase
在Firebase Console的项目设置中,我们将获取其配置并将其添加到 environment.ts
and environment.prod.ts
:
导出const环境= {
// ...
firebase: {
apiKey: {your-api-key},
authDomain:“{your-project-id}.firebaseapp.com',
databaseURL: http:// {your-project-id}.firebaseio.com',
projectId: {your-project-id},
storageBucket:“{your-project-id}.appspot.com',
messagingSenderId: {your-messaging-id},
appId:“{你的应用id}”
}
};
之后,我们将导入必要的模块 app.module.ts
:
从“@angular/fire”中导入{AngularFireModule};
从“@angular/fire/firestore”中导入{AngularFirestoreModule};
从“导入{环境}”../环境/环境”;
@NgModule({
// ...
imports: [
// ...
AngularFireModule.initializeApp(环境.firebase),
AngularFirestoreModule,
],
// ...
})
Next, in tv-rating-form.component.ts
,我们将注射 AngularFirestore
在表单提交时提供服务并保存新评级:
从“@angular/fire/firestore”中导入{AngularFirestore};
导出类TvRatingFormComponent实现OnInit {
constructor(
// ...
private at: AngularFirestore
) { }
异步提交(event: any) {
this.form.disable();
await this.af.收集(“评级”).add(this.form.value);
this.form.enable();
this.form.reset();
}
}
现在,当我们转到Firebase控制台时,我们将看到新创建的项目.
最后,让我们列出所有的评级 AppComponent
. To do that, in app.component.ts
,我们将从集合中获取数据:
从“@angular/fire/firestore”中导入{AngularFirestore};
导出类AppComponent实现OnInit {
// ...
ratings$: Observable;
constructor(
// ...
private: AngularFirestore
) { }
ngOnInit() {
// ...
this.ratings$ = this.af.收集(“评级”).valueChanges();
}
}
…and in app.component.html
,我们将添加一个评级列表:
// ...
{{rating.tvShow}}({{评级.rating}})
这就是我们的Angular 9教程应用程序组合在一起时的样子.
在这个Angular 9教程中, 我们已经介绍了构建一个基本表单, 将数据保存到Firebase, 并从中检索项目.
一路上,我们看到了Angular 9和Angular Ivy中包含了哪些改进和新特性. 要了解完整的列表,你可以查看Angular官方博客 最新发布帖子.
作为谷歌云合作伙伴,Toptal的谷歌认证专家可以为公司服务 on demand 为了他们最重要的项目.
Angular是一个JavaScript框架,可以帮助开发人员轻松构建快速的web和移动应用程序. 它带有预构建的功能,可以帮助开发人员快速启动和运行.
Angular的最新版本是Angular 10, 除了框架之外,它还更新了CLI和Angular Material. (在此之前,Angular 9是第一个默认启用Angular Ivy编译器的版本.)
Angular创建于2013年,并作为一个全功能框架而广受欢迎, 它附带了许多web开发人员最常用的组件.
Yes. Angular是三大最流行的框架之一,拥有一个庞大而活跃的社区. b谷歌的支持使它很可能在未来的许多年里与我们在一起.
Angular Ivy是新的Angular编译器. 这是Angular团队花了两年时间进行重大重构的结果. 它为许多改进奠定了基础, 让Angular能够跟上web开发的最新创新.
在Angular 9中,Ivy是默认启用的. 在Angular 8中也可以启用Ivy, 但是如果你还没有使用Angular 9的话, 建议升级到版本9以启用Ivy.
Joaquin是一名全栈和混合移动应用程序开发人员,在WebMD和Getty Images等公司工作了13年以上.
世界级的文章,每周发一次.
世界级的文章,每周发一次.
Join the Toptal® community.