例如有一项这项服务
class Service {
constructor(public name:string){}
}
我想将它的不同实例传递给子组件
@Component({
selector: 'child-component',
template: `
<div>{{service.name}}</div>
`,
})
export class ChildComponent {
constructor(public service: Service){}
}
@Component({
selector: 'parent-component',
template: `
<child-component></child-component>
<child-component></child-component>
`,
})
export class ParentComponent {
constructor(public service: Service){}
}
在React中,可以通过使用上下文来完成。像这样
const ServiceContext = React.createContext<Service>({} as any);
function ChildComponent(){
const service = useContext(ServiceContext)
return <div>{service.name}</div>
}
export function ContextTest(){
const service1 = new Service("foo")
const service2 = new Service("bar")
return <div>
<ServiceContext.Provider value={service1}>
<ChildComponent/>
</ServiceContext.Provider>
<ServiceContext.Provider value={service2}>
<ChildComponent/>
</ServiceContext.Provider>
</div>
}
是否可以在Angular中做类似的事情?
答案 0 :(得分:1)
是的,可以这样做。技巧是在将使用该服务的组件的providers
数组中声明该服务,而不是在Module
中声明该服务。
当您在Module
级别上“提供”服务时,该Module
中的每个组件都可以使用DI的单个实例。
但是,如果您在组件级别“提供”,则该组件每次都会获得一个全新的服务实例。
在此处查看docs以获得更多信息。
使用一个组件的@Component
装饰器的基本示例:
@Component({
selector: 'child-component',
template: `<div>{{service.name}}</div>`,
providers: [Service]
})
对要使用自己的实例的每个组件执行此操作,并再次确保不要将服务放入Module's
providers
数组中。
编辑:
如果您希望父组件知道服务(及其值),那么它可以手动创建它们并通过@Input()
绑定将它们传递进来。
举个简单的例子,您的组件将具有以下属性:
@Input() service: Service;
然后在您父母的HTML中:
<child-component [service]="new Service('foo')"></child-component>
<child-component [service]="new Service('bar')"></child-component>
或者,在父级上创建字段,例如:
fooService = new Service('foo');
barService = new Service('bar');
然后在HTML中:
<child-component [service]="fooService"></child-component>
<child-component [service]="barService"></child-component>
编辑2:
虽然我不认为开箱即用Angular的DI可以实现这一点,但我认为可能有一种方法可以达到期望的结果(仍然使用构造函数DI)。
首先,创建一个“ config”类型,例如:
export interface ServiceConfig {
name: string;
}
现在,像这样修改您的服务:
export class Service {
private config: ServiceConfig;
constructor() {
}
registerConfig(config: ServiceConfig) {
this.config = config;
}
get name(): string {
return this.config.name;
}
}
然后在您的组件中:
@Component({
selector: 'child-component',
template: `<div>{{service.name}}</div>`,
providers: [Service]
})
export class ChildComponent implements OnInit {
@Input() serviceConfig: ServiceConfig;
constructor(private service: Service) {
}
ngOnInit(): void {
this.service.registerConfig(this.serviceConfig);
}
}
然后,最后一件事是将唯一的配置连接到父模板中的每个子组件:
<child-component [serviceConfig]="{ name: 'fooService' }"></child-component>
<child-component [serviceConfig]="{ name: 'barService' }"></child-component>
这并不是一个完美的解决方案,但它满足了您的要求(我认为这很奇怪)。