如何在创建组件时指定注入?

huangapple go评论68阅读模式
英文:

How to specify injections into component at creation?

问题

I've translated the code portion for you:

也许我误解了依赖注入的目的,但我创建了一个使用Service来获取一些数据的组件:

export abstract class MyService {   
  abstract getData(): string;    
}

@Injectable({
  providedIn: 'root'
})
export class FooService extends MyService {   
  getData() { return "foo"; }  
}

@Injectable({
  providedIn: 'root'
})
export class BarService extends MyService {   
  getData() { return "bar"; }  
}

@Component({
  selector: 'my-component',
  template: '<span> {{ data }} </span>'
})
export class MyComponent implements Component {
  data: string;

  constructor(service: MyService) {
    this.data = service.getData();
  }
}

如何在创建MyComponent时注入适当的Service,无论是FooServiceBarService还是MyService的其他子类?

我期望存在类似<my-component [service]="FooService"></my-component>的方式,但是在文档中找不到类似的内容。

英文:

Perhaps I've misunderstood the purpose of dependency injection, but I went and created a component that uses a Service to get some data:

export abstract class MyService {   
  abstract getData(): string;    
}

@Injectable({
  providedIn: &#39;root&#39;
})
export class FooService extends MyService {   
  getData() { return &quot;foo&quot;; }  
}

@Injectable({
  providedIn: &#39;root&#39;
})
export class BarService extends MyService {   
  getData() { return &quot;bar&quot;; }  
}

@Component({
  selector: &#39;my-component&#39;,
  template: `&lt;span&gt; {{ data }} &lt;/span&gt;`
})
export class MyComponent implements Component {
  data: string;

  constructor(service: MyService) {
    this.data = service.getData();
  }
}

How do I get the appropriate Service, whether FooService or BarService or some other subclass of MyService injected into a MyComponent when I create it?

I was expecting that there would exist something like &lt;my-component [service]=&quot;FooService&quot;&gt;&lt;/my-component&gt;, but I can't find anything like this in the docs.

答案1

得分: 1

From parent component providers array we can set different instance to same MyService using useExisting or useFactory.

When we provide a service in a component's providers array, the instance of that service is scoped to that component and its children.

@Component({
  providers: [
    {
      provide: MyService,
      useExisting: BarService // FooService
    }
  ],
})

使用提供商示例

或者

如果您使用的是 Angular 14+,您可以将 inject 函数与环境注入器结合使用以获得类似的行为。

@Input() service: ProviderToken<MyService>;
constructor(private envInj: EnvironmentInjector) {
}

ngOnInit() { 
  this.envInj.runInContext(() => {
    if (this.service) {
      this.data = inject(this.service).getData();
    }
  })
}

使用 Inject 函数示例

参考资料

英文:

From parent component providers array we can set different instance to same MyService using useExisting or useFactory

When we provide a service in a component's providers array, the instance of that service is scoped to that component and its children

@Component({
  providers:[
    {
      provide:MyService,
      useExisting:BarService //FooService
    }
  ],
})

Example Using Providers

Or

If you are using angular 14+ you could combine inject function with Environment injector to get similar behaviour

@Input() service:ProviderToken&lt;MyService&gt;;
  constructor(private envInj:EnvironmentInjector) {
  }

  ngOnInit() { 
    this.envInj.runInContext(()=&gt;{
      if(this.service){
        this.data = inject(this.service).getData();
      }
    })
  }

Example Using Inject function

Reference

答案2

得分: 0

Jay Swaminarayan!

我猜你应该这样做,这是更简单的方式!

export abstract class MyService {   
  abstract getData(): string;    
}

@Injectable({
  providedIn: 'root'
})
export class FooService extends MyService {   
  getData() { return "foo"; }  
}

@Injectable({
  providedIn: 'root'
})
export class BarService extends MyService {   
  getData() { return "bar"; }  
}

@Injectable({
  providedIn: 'root'
})
export class AllServices {   
    constructor(public Foo: FooService,public Bar: BarService) {}
}

@Component({
  selector: 'my-component',
  template: '<span> {{ data }} </span>'
})
export class MyComponent implements Component {
  @Input() service: MyService;
  data: string;

  constructor(public _: AllServices) {
    this.data = this.service.getData();
  }
}

然后在模板中按照你的需求使用它:

<my-component [service]="_.Foo"></my-component>
<my-component [service]="_.Bar"></my-component>

这可能不是标准的方式,但也能达到相同的目的并匹配你的实现。

英文:

Jay Swaminarayan!

I guess you should do this instead, it's more simple way!

export abstract class MyService {   
  abstract getData(): string;    
}

@Injectable({
  providedIn: &#39;root&#39;
})
export class FooService extends MyService {   
  getData() { return &quot;foo&quot;; }  
}

@Injectable({
  providedIn: &#39;root&#39;
})
export class BarService extends MyService {   
  getData() { return &quot;bar&quot;; }  
}


@Injectable({
  providedIn: &#39;root&#39;
})
export class AllServices {   
    constructor(public Foo: FooService,public Bar: BarService) {}
}


@Component({
  selector: &#39;my-component&#39;,
  template: `&lt;span&gt; {{ data }} &lt;/span&gt;`
})
export class MyComponent implements Component {
  @Input() service: MyService;
  data: string;

  constructor(public _: AllServices) {
    this.data = this.service.getData();
  }
}

Then use it in your template as you desired.

&lt;my-component [service]=&quot;_.Foo&quot;&gt;&lt;/my-component&gt;
&lt;my-component [service]=&quot;_.Bar&quot;&gt;&lt;/my-component&gt;

This may not be standard way, but kind of serves the purpose as well as match your implementation.

huangapple
  • 本文由 发表于 2023年4月4日 09:21:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/75924818.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定