【Angular4】基础(五):创建服务
服务一般用来放置可复用的代码。如何创建 Angular 服务在 Angular 中我们通过以下方式创建一个简单的服务:export class BookService {getBooks() {return ['Angular', 'React', 'Vue'];}}组件中注入服务我们来创建一个新的组件 BookCompone...
服务一般用来放置可复用的代码。
如何创建 Angular 服务
在 Angular 中我们通过以下方式创建一个简单的服务:
export class BookService {
getBooks() {
return ['Angular', 'React', 'Vue'];
}
}
组件中注入服务
我们来创建一个新的组件 BookComponent
,它用来显示书籍的信息:
// book.component.ts
export class BookComponent implements OnInit {
books: Array<{ id: number; name: string }>;
ngOnInit() {
this.books = [
{ id: 11, name: 'Angular' },
{ id: 12, name: 'React' },
{ id: 13, name: 'Vue' }
];
}
}
// book.component.html
<ul>
<li *ngFor="let book of books">
ID: {{ book.id }} - Name: {{ book.name }}
</li>
</ul>
在 BookComponent
组件中,我们在 ngOnInit
钩子中进行数据初始化,然后利用 ngFor
指令来显示书籍列表的信息。创建完 BookComponent
组件,我们来验证一下该组件的功能。
因为我是用 Angular CLI 脚手架创建的组件,所以已自动导入 AppModule
,只需要记得在 app.component.html
中将内容更改为 <app-book></app-book>
即可。不出意外的话,访问 http://localhost:4200/
将会看到
- ID: 11 - Name: Angualr
- ID: 12 - Name: React
- ID: 13 - Name: Vue
目前我们实现的书籍信息是固定的,别忘了,在实际的开发场景中,一般需要从远程服务器获取相应的信息。但我们暂不考虑这个问题,假设另外一个组件也需要利用同样的书籍信息,那我们要怎么办,总不可能用复制粘贴~
接下来我们创建一个 BookService
服务,从而实现数据共享。
// book.service.ts
export class BookService {
books: Array<{ id: number; name: string}> = [
{ id: 11, name: "Angular" },
{ id: 12, name: "React" },
{ id: 13, name: "Vue" }
];
getBooks() {
return this.books;
}
}
在 BookService
服务中,我们定义了一个 books
属性和一个 getBooks()
方法:
- books - 用于保存书籍的信息
- getBooks() - 用于获取书籍的信息
创建完 BookService
服务后,就要使用它了!
组件中使用服务
主要分为三个步骤:
1)导入服务
// book.component.ts
import { BookService } from '../book.service';
2)声明服务
方式一:
// book.component.ts
@Component({
selector: 'app-book',
...
providers: [BookService]
})
方式二:
// app.module.ts
@NgModule({
...
providers: [BookService],
...
})
注意:不管哪种方式,记得一定要在文件头 import 进服务。
3)注入服务
// book.component.ts
export class BookComponent implements OnInit {
constructor(private bookService: BookService) {}
}
问题1:可能会有人疑惑为什么去掉 private
会报错?
这里解释下,这是 TypeScript 的用法,跟 Java 类似,分别是 public、private、protected。
上述例子可以等价为:
// book.component.ts
export class BookComponent implements OnInit {
private bookService: BookService;
constructor(bookService: BookService) {
this.bookService = bookService;
}
}
问题2:为什么配置完 BookService
,在 BookComponent
组件类中构造函数中还得进行类型声明?
因为在 @NgModule({...})
或 @Component({...})
的元数据中我们只是配置了 Provider
的相关信息,即告诉 Angular DI(依赖注入)系统,如何创建根据配置的 provider
信息,创建相应的依赖对象。而在 BookComponent
组件类中,我们通过构造注入的方式去告诉 Angular DI 系统,我们需要的依赖对象**类型。
|| 至此,我们只是勉强完成了服务,这样就OK了?当然不行!
下面来解决实际开发中遇到处理数据时如玩服务~
在这里模拟一个书籍列表,创建 book.json
并放置在 /assets/json/book.json
中:
{
"books": [
{
"name": "Angular"
},
{
"name": "React"
},
{
"name": "Vue"
}
]
}
修改 book.service.ts
:
// book.service.ts
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/toPromise';
@Injectable()
export class BookService {
constructor(private http: Http) {}
private handleError(error: any): Promise<any> {
console.error('An error occurred' + error);
}
getBooks() {
const url = '/assets/json/book.json';
return this.http.get(url).toPromise().then(res => res.json()).catch(this.handleError);
}
}
注:默认情况下,Angular 的Http服务返回一个 RxJS 的Observable对象。 我们可以通过 toPromise()
方法将其转为便捷的承诺Promise。 使用 toPromise()
方法时要引入:
import 'rxjs/add/operator/toPromise';
接下来使用这个 BookService
服务:
// book.component.ts
import { Component, OnInit } from '@angular/core';
import { BookService } from '../book.service';
@Component({
selector: 'app-book',
templateUrl: './book.component.html',
styleUrls: ['./book.component.css'],
providers: [BookService]
})
export class BookComponent implements OnInit {
constructor(private bookService: BookService) {
};
books: any[];
ngOnInit() {
this.bookService.getBooks().then(res => {this.books = res.books};
}
}
常用服务
获取(get)数据:
get() {
return this.http.get(url)
.toPromise()
.then(response => response.json() )
.catch(this.handleError);
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error);
}
新建(post)数据:
private headers = new Headers({'Content-type': 'application/json'});
create() {
return this.http
.post(url, JSON.stringify(hero), {headers: this.headers})
.toPromise()
.then(response => response.json())
.catch(this.handleError);
}
更新(update)数据:
private headers = new Headers({'Content-type': 'application/json'});
update() {
return this.http
.put(url, JSON.stringify(hero), {headers: this.headers})
.toPromise()
.then(response => response.json())
.catch(this.handleError);
}
删除(delete)数据:
private headers = new Headers({'Content-type': 'application/json'});
delete() {
return this.http
.delete(url, {headers: this.headers})
.toPromise()
.then(() => null)
.catch(this.handleError);
}
注入服务方式
1)Type 类型的参数有两种方式:
第一种
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../core/auth.service.ts';
constructor(private authService: AuthService) {}
第二种
import { Component, OnInit, Inject } from '@angular/core';
import { AuthService } from '../core/auth.service.ts';
@Component({
...
providers: [AuthService]
})
...
constructor(@Inject(AuthService) private authService) {}
...
同第二种
import { Component, OnInit, Inject } from '@angular/core';
import { AuthService } from '../core/auth.service.ts';
@Component({
...
providers: [{provide: 'auth', useClass: AuthService}]
})
constructor(@Inject('auth') private authService) {}
...
2)非 Type 类型的参数只能 @Inject(Type)
注入
因为在构造函数中,只有是 Type 类型的对象,才会被 TypeScript 编译器编译。
非 Type 类型 Token:字符串、OpaqueToken对象、InjectionToken对象等
app.module.ts 中配置服务踩坑记
// app.module.ts
...
@NgModule({
...
providers: [
[{provide: 'auth', useClass: AuthService}] // 注意:这个对象外面有个[]包裹。少了会报错
]
...
})
分析 @NgModule({}) 中 providers
里面有两个属性,provide
和 useClass
,provide
定义了这个服务的名称,有需要注入这个服务的就用这个名称就好。useClass
指明这个名称对应的服务是一个类,本例中就是 AuthService 了。这样定义好之后,我们就可以在任意组件中注入这个依赖了。
更多推荐
所有评论(0)