Je sais comment injecter un service dans un composant (via @Component), mais comment puis-je utiliser l'ID pour transmettre des services en dehors des composants?
En d'autres termes, je ne veux pas faire ceci:
export class MyFirstSvc {
}
export class MySecondSvc {
constructor() {
this.helpfulService = new MyFirstSvc();
}
}
export class MyThirdSvc {
constructor() {
this.helpfulService = new MyFirstSvc();
}
}
Oui, la première chose à faire est d’ajouter le décorateur @Injectable
à chaque service que vous souhaitez injecter. En fait, le nom Injectable
est un peu insidieux. Cela ne signifie pas que la classe sera "injectable" mais elle décorera afin que les paramètres du constructeur puissent être injectés. Voir ce numéro de github pour plus de détails: https://github.com/angular/angular/issues/4404 .
Voici ma compréhension du mécanisme d'injection. Lors de la définition d'un décorateur @Injectable
pour une classe, Angular essaiera de créer ou d'obtenir des instances pour les types correspondants dans l'injecteur pour la chaîne d'exécution en cours. En fait, il n'y a pas qu'un seul injecteur pour une application Angular2, mais un arbre d'injecteurs. Ils sont implicitement associés à l'ensemble de l'application et des composants. Une caractéristique clé à ce niveau est qu’elles sont liées entre elles de manière hiérarchique. Cet arbre d'injecteurs mappe l'arbre de composants. Aucun injecteur n'est défini pour "services".
Prenons un échantillon. J'ai l'application suivante:
Composant AppComponent
: composant principal de mon application fourni lors de la création de l'application Angular2 dans la fonction bootstrap
@Component({
selector: 'my-app',
template: `
<child></child>
`,
(...)
directives: [ ChildComponent ]
})
export class AppComponent {
}
Composant ChildComponent
: un sous-composant qui sera utilisé dans le composant AppComponent
@Component({
selector: 'child',
template: `
{{data | json}}<br/>
<a href="#" (click)="getData()">Get data</a>
`,
(...)
})
export class ChildComponent {
constructor(service1:Service1) {
this.service1 = service1;
}
getData() {
this.data = this.service1.getData();
return false;
}
}
Deux services, Service1
et Service2
: Service1
sont utilisés par les variables ChildComponent
et Service2
de Service1
@Injectable()
export class Service1 {
constructor(service2:Service2) {
this.service2 = service2;
}
getData() {
return this.service2.getData();
}
}
@Injectable()
export class Service2 {
getData() {
return [
{ message: 'message1' },
{ message: 'message2' }
];
}
}
Voici un aperçu de tous ces éléments et de leurs relations:
Application
|
AppComponent
|
ChildComponent
getData() --- Service1 --- Service2
Dans une telle application, nous avons trois injecteurs:
bootstrap
AppComponent
qui peut être configuré à l'aide de l'attribut providers
de ce composant. Il peut "voir" les éléments définis dans l'injecteur d'application. Cela signifie que si un fournisseur n’est pas trouvé dans ce fournisseur, il sera automatiquement recherché dans cet injecteur parent. S'il n'est pas trouvé dans le dernier cas, une erreur "fournisseur introuvable" sera renvoyée.ChildComponent
qui suivra les mêmes règles que celui de AppComponent
. Pour injecter des éléments impliqués dans la chaîne d'injection exécutée pour le composant, les fournisseurs seront d'abord recherchés dans cet injecteur, puis dans celui-ci à la variable AppComponent
et enfin dans celui de l'application.Cela signifie que pour tenter d’injecter le Service1
dans le constructeur ChildComponent
, Angular2 examinera l’injecteur ChildComponent
, puis celui AppComponent
et finalement celui-ci dans l’application.
Étant donné que Service2
doit être injecté dans Service1
, le même traitement de résolution sera effectué: ChildComponent
injector, AppComponent
one et application one.
Cela signifie que Service1
et Service2
peuvent être spécifiés à chaque niveau en fonction de vos besoins en utilisant l'attribut providers
pour les composants et le second paramètre de la fonction bootstrap
pour l'injecteur d'application.
Cela permet de partager des instances de dépendances pour un ensemble d’éléments:
C'est donc très puissant et vous êtes libre d'organiser ce que vous voulez et selon vos besoins.
Voici le dossier correspondant pour que vous puissiez jouer avec: https://plnkr.co/edit/PsySVcX6OKtD3A9TuAEw?p=preview .
Ce lien de la documentation Angular2 pourrait vous aider: https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html .
En espérant que cela vous aide (et pardon pour la longue réponse), Thierry
Le service est considéré comme partagé entre les composants. Alors disons que si j'ai un service, je peux l'utiliser dans différents composants.
Ici, dans cette réponse, je vous montre un service qui accepte les données d'un composant et les envoie à un autre composant.
J'ai utilisé le concept de routage, service partagé, objet partagé . J'espère que cela vous aidera à comprendre la base du service partagé.
Remarque: @Injectable decorater est utilisé pour rendre le service injectable.
Boot.ts
import {Component,bind} from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
import {Router,ROUTER_PROVIDERS,RouteConfig, ROUTER_DIRECTIVES,APP_BASE_HREF,LocationStrategy,RouteParams,ROUTER_BINDINGS} from 'angular2/router';
import {SharedService} from 'src/sharedService';
import {ComponentFirst} from 'src/cone';
import {ComponentTwo} from 'src/ctwo';
@Component({
selector: 'my-app',
directives: [ROUTER_DIRECTIVES],
template: `
<h1>
Home
</h1>
<router-outlet></router-outlet>
`,
})
@RouteConfig([
{path:'/component-first', name: 'ComponentFirst', component: ComponentFirst}
{path:'/component-two', name: 'ComponentTwo', component: ComponentTwo}
])
export class AppComponent implements OnInit {
constructor(router:Router)
{
this.router=router;
}
ngOnInit() {
console.log('ngOnInit');
this.router.navigate(['/ComponentFirst']);
}
}
bootstrap(AppComponent, [SharedService,
ROUTER_PROVIDERS,bind(APP_BASE_HREF).toValue(location.pathname)
]);
FirstComponent
import {Component,View,bind} from 'angular2/core';
import {SharedService} from 'src/sharedService';
import {Router,ROUTER_PROVIDERS,RouteConfig, ROUTER_DIRECTIVES,APP_BASE_HREF,LocationStrategy,RouteParams,ROUTER_BINDINGS} from 'angular2/router';
@Component({
//selector: 'f',
template: `
<div><input #myVal type="text" >
<button (click)="send(myVal.value)">Send</button>
`,
})
export class ComponentFirst {
constructor(service:SharedService,router:Router){
this.service=service;
this.router=router;
}
send(str){
console.log(str);
this.service.saveData(str);
console.log('str');
this.router.navigate(['/ComponentTwo']);
}
}
SecondComponent
import {Component,View,bind} from 'angular2/core';
import {SharedService} from 'src/sharedService';
import {Router,ROUTER_PROVIDERS,RouteConfig, ROUTER_DIRECTIVES,APP_BASE_HREF,LocationStrategy,RouteParams,ROUTER_BINDINGS} from 'angular2/router';
@Component({
//selector: 'f',
template: `
<h1>{{myName}}</h1>
<button (click)="back()">Back<button>
`,
})
export class ComponentTwo {
constructor(router:Router,service:SharedService)
{
this.router=router;
this.service=service;
console.log('cone called');
this.myName=service.getData();
}
back()
{
console.log('Back called');
this.router.navigate(['/ComponentFirst']);
}
}
SharedService et objet partagé
import {Component, Injectable,Input,Output,EventEmitter} from 'angular2/core'
// Name Service
export interface myData {
name:string;
}
@Injectable()
export class SharedService {
sharingData: myData={name:"nyks"};
saveData(str){
console.log('save data function called' + str + this.sharingData.name);
this.sharingData.name=str;
}
getData:string()
{
console.log('get data function called');
return this.sharingData.name;
}
}
je ne sais pas si une réponse est toujours nécessaire, alors j'essaierais d'y répondre.
Prenons l'exemple suivant où nous avons un composant qui utilise un service pour renseigner certaines valeurs dans son modèle, comme ci-dessous.
testComponent.component.ts
import { Component } from "@angular/core"
import { DataService } from "./data.service"
@Component({
selector:"test-component",
template:`<ul>
<li *ngFor="let person of persons">{{ person.name }}</li>
</ul>
})
export class TestComponent {
persons:<Array>;
constructor(private _dataService:DataService){
this.persons = this._dataService.getPersons()
}
}
Le code ci-dessus est assez simple et il essaiera d'extraire tout ce que getPersons retournera du DataService. Le fichier DataService est disponible ci-dessous.
data.service.ts
export class DataService {
persons:<Array>;
constructor(){
this.persons = [
{name: "Apoorv"},
{name: "Bryce"},
{name: "Steve"}
]
}
getPersons(){
return this.persons
}
Le code ci-dessus fonctionnera parfaitement sans l'utilisation du décorateur @Injectable. Mais le problème va commencer quand notre service (DataService dans ce cas) nécessite des dépendances comme par exemple. Http. si nous modifions notre fichier data.service.ts
comme ci-dessous, nous obtiendrons une erreur disant Cannot resolve all parameters for DataService(?). Make sure they all have valid type or annotations.
import { Http } from '@angular/http';
export class DataService {
persons:<Array>;
constructor(){
this.persons = [
{name: "Apoorv"},
{name: "Bryce"},
{name: "Steve"}
]
}
getPersons(){
return this.persons
}
Cela a quelque chose à voir avec la manière dont les décorateurs fonctionnent dans Angular 2. Veuillez lire https://blog.iblytram.io/angular/2015/05/03/the-difference-between-annotations-and-decorators.html pour bien comprendre ce problème.
Le code ci-dessus ne fonctionnera pas non plus, car nous devons également importer HTTP dans notre module d'amorçage.
Mais une règle de base que je peux suggérer est que si votre fichier de service nécessite une dépendance, vous devez décorer cette classe avec un décorateur @Injectable.
référence: https://blog.blingtram.io/angular/2015/09/17/resolve-service-dependencies-in-angular-2.html
Quelque part, @Injectable ne fonctionne pas dans Angular 2.0.0-beta.17 lors du câblage ComponentA -> ServiceB -> ServiceC.
J'ai pris cette approche:
Run this Plunker pour voir un exemple ou voir le code ci-dessous
app.ts
@Component({selector: 'my-app',
template: `Hello! This is my app <br/><br/><overview></overview>`,
directives: [OverviewComponent]
})
class AppComponent {}
bootstrap(AppComponent);
aperçu.ts
import {Component, bind} from 'angular2/core';
import {OverviewService} from "../services/overview-service";
import {PropertiesService} from "../services/properties-service";
@Component({
selector: 'overview',
template: `Overview listing here!`,
providers:[OverviewService, PropertiesService] // Include BOTH services!
})
export default class OverviewComponent {
private propertiesService : OverviewService;
constructor( overviewService: OverviewService) {
this.propertiesService = overviewService;
overviewService.logHello();
}
}
overview-service.ts
import {PropertiesService} from "./properties-service";
import {Inject} from 'angular2/core';
export class OverviewService {
private propertiesService:PropertiesService;
// Using @Inject in constructor
constructor(@Inject(PropertiesService) propertiesService:PropertiesService){
this.propertiesService = propertiesService;
}
logHello(){
console.log("hello");
this.propertiesService.logHi();
}
}
properties-service.ts
// Using @Injectable here doesn't make a difference
export class PropertiesService {
logHi(){
console.log("hi");
}
}
La première chose à faire est d'annoter tous les services avec l'annotation @Injectable
. Notez les parenthèses à la fin de l'annotation, sans cela cette solution ne fonctionnerait pas.
Une fois cela fait, nous pouvons ensuite nous injecter des services les uns aux autres en utilisant l'injection de constructeur:
@Injectable()
export class MyFirstSvc {
}
@Injectable()
export class MySecondSvc {
constructor(helpfulService: MyFirstSvc) {
}
}
@Injectable()
export class MyThirdSvc {
constructor(helpfulService: MyFirstSvc) {
}
}
Vous devez d'abord fournir votre service
Vous pouvez le fournir soit dans la méthode bootstrap:
bootstrap(AppComponent,[MyFirstSvc]);
ou le composant sur l'application, ou dans tout autre composant, selon vos besoins .:
@Component({
...
providers:[MyFirstSvc]
}
...
puis juste vous injecter le service en utilisant le constructeur:
export class MySecondSvc {
constructor(private myFirstSvc : MyFirstSvc ){}
}