- angular中的服务:多个组件可以共享同一数据,服务可从远程服务器中异步获取数据。
- 在组件中使用服务的步骤:1. 导入服务; 2. 声明服务; 3. 注入服务
- @Injectable({provideIn: 'root'})是每个angular服务定义中的基本元素。
- 你可以在三种位置之一设置元数据,以便在应用的不同层级使用提供商来配置注入器:1. 服务本身的@Injectable()装饰器【provideIn】; 2. NgModule的@NgModule()装饰器 【provides】; 3. 组件的@component装饰器中 【provides】
- [{ provide: Logger, useClass: Logger }],第一个Logger是令牌,第二个属性是类提供商定义对象
- 依赖对象的创建方式为: useClass, useValue, useExisting, useFactory
- Provider:(classProvider, valueProvider, existingProvider, FactoryProvider)
- 在
Angular
中,Provider
描述了注入器(Injector)如何初始化令牌(Token)所对应的依赖服务。Provider
一个运行时的依赖,注入器依靠它来创建服务对象的实例。 - 接口,方法,字符串不能被当做一个类来处理,所以引入了new InjectionToken()对象注册依赖的提供商,然后我们在
@Inject()
的帮助下,我们把这个配置对象注入到需要它的构造函数中,最后我们就可以使用最初的那个对象了.
以下是一个测试,关于useClass, useValue, new InjectionToken
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class CarService {
color: string = 'test-CarService';
constructor() {}
}
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class AnimalService {
emoji: string = 'test--AnimalService';
constructor() {}
}
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class FlowerService {
emoji: string = 'test--FlowerService';
constructor() {}
}
import { InjectionToken } from '@angular/core';
export interface StudentType {
name: string;
age: number;
}
export const student: StudentType = {
name: 'lee si',
age: 12
};
export const StudentToken = new InjectionToken<StudentType>('student go');
// 非类提供商
以上4个全部注入下面这个组件:
const CarServiceConst = { color: 'in const type' }; // 也可在此处修改
providers: [
{ provide: FlowerService, useValue: { emoji: 'useValue works' } },
{ provide: CarService, useValue: CarServiceConst },
{ provide: AnimalService, useClass: FlowerService }, // useClass里的service无需在构造函数里注入
// { provide: AnimalService, useClass: CarService } 这样animal.emoji的值会是undefined
// 如果useClass和provide是同一个service,可以不用写在providers里
{ provide: StudentToken, useValue: student },
// { provide: StudentFormToken, useClass: StudyFormDefinition } //?StudyFormDefinition
]
。。。
ngOnInit() {
console.log('>>>>>> test--FlowerService >|', this.flowerService.emoji);
console.log('>>>>>> test--CarService >|', this.carService.color);
console.log('>>>>>> test--AnimalService >|', this.animalService.emoji);
console.log(
'>>>>>> test new InjectionToken<>() >|',
this.studentType.name + this.studentType.age
);
// console.log('>>>>>> 测试中', this.studyFormDefinition.startup);
}
打印如下:
useClass和useExisting的区别:
useExisting会是同一实例,useClass会是新实例。还是上面这个例子,新增加一个trainService:
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class TrainService {
color: string = 'test-TrainService';
constructor() {}
}
在要注入的这个组件写一个按钮,目的是改变carService的值:
click() {
this.carService.color = 'change together?';
console.log('>>>>>> test--TrainService >|', this.trainService.color);
console.log('>>>>>> test--CarService >|', this.carService.color);
}
下面看2种情况:
情况1,使用useClass:
{ provide: TrainService, useClass: CarService } // 这样carService会是2个实例
打印如下:
情况2,使用useExisting:
{ provide: TrainService, useExisting: CarService } // 这样carService会是1个实例
打印如下:
1. constructor用法:
constructor
应该是ES6中明确使用constructor
来表示构造函数的,构造函数使用在class
中,用来做初始化和给属性赋值操作。当包含constructor
的类被实例化时,构造函数将被调用。
constructor
也有其用武之地,其主要作用是注入依赖。在constructor
中注入的依赖,就可以作为类的属性被使用了。
constructor是在组件就实例化的时候就已经调用了,这也就是说,在constructor中我们是取不到输入属性的值的。,在constructor中不适合进行任何与组件 通信类似的复杂操作,一般在constructor中值进行一些简单的初始化 工作:依赖注入,变量初始化等。
// parent.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'exe-parent',
template: `
<h1>Welcome to Angular World</h1>
<p>Hello {{name}}</p>
<exe-child [pname]="name"></exe-child> <!-- 绑定到子组件的属性 -->
`,
})
export class ParentComponent {
name: string;
constructor() {
this.name = 'God eyes';
}
}
// child.component.ts
import { Component, Input, OnInit } from '@angular/core';
@Component({
selector: 'exe-child',
template: `
<p>父组件的名称:{{pname}} </p>
`
})
export class ChildComponent implements OnInit {
@Input()
pname: string; // 父组件的输入属性
constructor() {
console.log('ChildComponent constructor', this.pname); // this.name=undefined
}
ngOnInit() {
// 只有父组件的模板中pname绑定生效后,才执行ngOnInit,所以属性绑定应该在
// ngOnInit内执行相应操作
console.log('ChildComponent ngOnInit', this.pname); // this.name=God eyes
}
}
* 使用构造函数初始化(但直接变量赋值方法更简单):
export class AppComponent {
title: string;
myHero: string;
constructor() {
this.title = 'Tour of Heroes';
this.myHero = 'Windstorm';
}
}
* 直接变量赋值方法:【推荐】
export class AppComponent {
title = 'Tour of Heroes';
myHero = 'Windstorm';
}
2. [ngSwitch]
有一组单选按钮,选中是myVal
会改变,ngSwitch
会去循环每个case
,如果找到了就显示那条case
中的数据,不然显示default
中的数据
<div>
<h2>ngSwitch</h2>
<input name="myVal" type="radio" title="" value="1" (click)="changeValue()">1
<input name="myVal" type="radio" title="" value="2" (click)="changeValue()">2
<input name="myVal" type="radio" title="" value="3" (click)="changeValue)">3
<input name="myVal" type="radio" title="" value="4" (click)="changeValue()">4
<input name="myVal" type="radio" title="" value="5" (click)="changeValue()">5
<hr>
<span [ngSwitch]="myVal">
<span *ngSwitchCase="'1'">ONE</span>
<span *ngSwitchCase="'2'">TWO</span>
<span *ngSwitchCase="'3'">THREE</span>
<span *ngSwitchCase="'4'">FOUR</span>
<span *ngSwitchCase="'5'">FIVE</span>
<span *ngSwitchDefault>other</span>
</span>
</div>
当[ngSwitch]里的myVal=2时,显示TWO
3. 父组件向子组件传值
<!-- 将userName的值通过[name]属性传给子组件 -->
<!-- 父组件html -->
<app-child [name]='userName'></app-child>
//父组件ts
//要传的数据userName
userName = 'user1';
//子组件ts
import { Component,OnInit,Input, Output, EventEmitter} from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './app-child.component.html'
})
export class AppChildComponent implements OnInit {
@Input() name:string;
ngOnInit() {
console.log(this.name) //'user1'
}
}
export class Hero {
name: string;
}
export const HEROES = [
{name: 'Dr IQ'},
{name: 'Magneta'},
{name: 'Bombasto'}
];
//父组件
import { Component } from '@angular/core';
import { HEROES } from './hero';
@Component({
selector: 'app-hero-parent',
template: `
<h2>{{master}} controls {{heroes.length}} heroes</h2>
<app-hero-child *ngFor="let hero of heroes" [hero]=hero [master]="master"></app-hero-child>
`
})
export class HeroParentComponent {
heroes = HEROES;
master = "Matser"
}
//子组件
import { Component, Input } from '@angular/core';
import { Hero } from './hero';
@Component({
selector: 'app-hero-child',
template: `
<h2>{{hero.name}} says:</h2>
<p>I, {{hero.name}},am at your service, {{master}}</p>
`
})
export class HeroChildComponent {
@Input() hero: Hero;
@Input() master: string;
}
4. 子组件向父组件传值
子组件暴露一个 EventEmitter
属性,当事件发生时,子组件利用该属性 emits
(向上弹射)事件。父组件绑定到这个事件属性,并在事件发生时作出回应。
angular 报错: Circular dependency detected:
Angular 不允许模块之间出现循环依赖,所以不要让模块'A'导入模块'B',而模块'B'又导入模块'A'。