Frage Was ist der beste Weg, einen Dienst in eckigen 2 (Beta) in einen anderen zu injizieren?


Ich weiß, wie man einen Service in eine Komponente injiziert (über @Component), aber wie kann ich DI verwenden, um Services außerhalb von Komponenten weiterzugeben?

Mit anderen Worten, ich möchte das nicht tun:

export class MyFirstSvc {

}

export class MySecondSvc {
    constructor() {
        this.helpfulService = new MyFirstSvc();
    }
}

export class MyThirdSvc {
    constructor() {
        this.helpfulService = new MyFirstSvc();
    }
}

37
2018-01-15 04:14


Ursprung


Antworten:


Ja, die erste Sache ist, das hinzuzufügen @Injectable Decorator auf jeder Dienstleistung, die Sie injizieren möchten. In der Tat, die Injectable Name ist ein bisschen heimtückisch. Es bedeutet nicht, dass die Klasse "injizierbar" sein wird, aber sie wird dekorieren, so dass die Konstruktorparameter injiziert werden können. In diesem GitHub-Thema finden Sie weitere Informationen: https://github.com/angular/angular/issues/4404.

Hier ist mein Verständnis des Einspritzmechanismus. Beim Einstellen eines @Injectable Dekorator für eine Klasse, wird Angular versuchen, Instanzen für entsprechende Typen im Injektor für die aktuelle Ausführungskette zu erzeugen oder zu erhalten. Tatsächlich gibt es nicht nur einen Injektor für eine Angular2-Anwendung, sondern einen Injektor-Baum. Sie sind implizit der gesamten Anwendung und den Komponenten zugeordnet. Ein Hauptmerkmal auf dieser Ebene ist, dass sie hierarchisch miteinander verknüpft sind. Dieser Injektorbaum bildet den Baum der Komponenten ab. Für "Services" sind keine Injektoren definiert.

Lass uns ein Beispiel nehmen. Ich habe folgende Anwendung:

  • Komponente AppComponent: Die Hauptkomponente meiner Anwendung, die beim Erstellen der Angular2 - Anwendung in der bootstrap Funktion

    @Component({
      selector: 'my-app', 
        template: `
          <child></child>
        `,
        (...)
        directives: [ ChildComponent ]
    })
    export class AppComponent {
    }
    
  • Komponente ChildComponent: eine Unterkomponente, die innerhalb der verwendet wird AppComponent Komponente

    @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; 
      }
    }
    
  • Zwei Dienste, Service1 und Service2: Service1 wird von der verwendet ChildComponent und Service2 durch 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' }
        ];
      }
    }
    

Hier ist eine Übersicht über all diese Elemente und ihre Beziehungen:

Application
     |
AppComponent
     |
ChildComponent
  getData()     --- Service1 --- Service2

In einer solchen Anwendung haben wir drei Injektoren:

  • Der Anwendungsinjektor, der mit dem zweiten Parameter des bootstrap Funktion
  • Das AppComponent Injektor, der mit dem konfiguriert werden kann providers Attribut dieser Komponente. Er kann die im Applikationsinjektor definierten Elemente "sehen". Dies bedeutet, wenn ein Anbieter in diesem Anbieter nicht gefunden wird, wird automatisch nach diesem Eltern-Injektor gesucht. Wenn in letzterem nicht gefunden wird, wird ein Fehler "Provider nicht gefunden" ausgelöst.
  • Das ChildComponent Injektor, der den gleichen Regeln folgt wie der AppComponent ein. Um Elemente zu injizieren, die an der Einspritzkette beteiligt sind, die für die Komponente ausgeführt werden, werden die Anbieter zuerst in diesem Injektor und dann in dem AppComponent Eins und schließlich in der Anwendung eins.

Dies bedeutet, dass beim Versuch, die Service1 in die ChildComponent Konstruktor, Angular2 wird in die ChildComponent Injektor, dann in die AppComponent Eins und schließlich in die Anwendung eins.

Schon seit Service2 muss hinein gespritzt werden Service1, die gleiche Auflösung Verarbeitung erfolgt: ChildComponent Injektor, AppComponent eins und eins.

Dies bedeutet, dass beide Service1 und Service2 kann auf jeder Ebene nach Ihren Bedürfnissen mit der providers Attribut für Komponenten und der zweite Parameter des bootstrap Funktion für den Anwendungsinjektor.

Dies ermöglicht es, Instanzen von Abhängigkeiten für eine Reihe von Elementen zu teilen:

  • Wenn Sie einen Provider auf Anwendungsebene definieren, wird die entsprechende erstellte Instanz von der gesamten Anwendung (alle Komponenten, alle Services, ...) gemeinsam genutzt.
  • Wenn Sie einen Anbieter auf Komponentenebene definieren, wird die Instanz von der Komponente selbst, ihren Unterkomponenten und allen "Diensten", die an der Abhängigkeitskette beteiligt sind, gemeinsam genutzt.

Es ist also sehr mächtig und Sie können sich frei organisieren, wie Sie wollen und für Ihre Bedürfnisse.

Hier ist der entsprechende Plunkr, damit du damit spielen kannst: https://plnkr.co/edit/PsySvcXOktd3A9TuAEw?p=preview.

Dieser Link aus der Angular2-Dokumentation könnte Ihnen helfen: https://angular.io/docs/ts/latest/guide/hierarchical-dependency- injection.html.

Hoffe es hilft dir (und entschuldige die lange Antwort), Thierry


46
2018-01-15 08:56



  • "Stellen" Sie Ihre Dienste an oder über dem Ort bereit, an dem Sie sie verwenden möchten, z. B. können Sie sie mit Hilfe der Anwendung an die Wurzel Ihrer Anwendung stellen bootstrap() wenn Sie nur eine einmalige Instanz jedes Dienstes (Singletons).
  • Benutze die @Injectable() Dekorator auf jedem Dienst, der von einem anderen abhängt.
  • Inject die anderen Dienste in den Konstruktor des abhängigen Diensts.

boot.ts

import {bootstrap} from 'angular2/platform/browser';
import {AppComponent} from './app.component';
import {MyFirstSvc} from '../services/MyFirstSvc';
import {MySecondSvc} from '../services/MySecondSvc';

bootstrap(AppComponent, [MyFirstSvc, MySecondSvc]);

MySecondSvc.ts

import {Injectable} from 'angular2/core';
import {MyFirstSvc} from '../services/MyFirstSvc';

@Injectable()
export class MySecondSvc {
  constructor(private _firstSvc:MyFirstSvc) {}
  getValue() {
    return this._firstSvc.value;
  }
}

Sehen Plunker für andere Dateien.

Was an Service DI etwas komisch ist, ist, dass es immer noch auf Komponenten ankommt. Z.B., MySecondSvc wird erstellt, wenn eine Komponente es anfordert und abhängig davon, wo MyFirstSvc wurde im Komponentenbaum "bereitgestellt", was beeinflussen kann MyFirstSvc Instanz wird injiziert MySecondSvc. Dies wird hier mehr diskutiert: Können Sie Dienste nur über Bootstrap in Dienste einspeisen?


5
2018-01-15 04:32



Der Dienst wird als von den Komponenten gemeinsam genutzt angesehen. Sagen wir mal, wenn ich einen Service habe, kann ich ihn in verschiedenen Komponenten verwenden.

Hier In dieser Antwort zeige ich Ihnen einen Dienst, der Daten von einer Komponente akzeptiert und diese Daten an andere Komponente sendet.

Ich habe das Konzept von Routing, Shared-Service, Shared-Object verwendet. Ich hoffe, dies wird Ihnen helfen, die Grundlagen von Share-Service zu verstehen.

Hinweis: @Injectable Dekorateur wird verwendet, um den Service injizierbar zu machen.

Antworten

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)
    ]);

Erste Komponente

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']);
  }

}

Zweite Komponente

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 und gemeinsames Objekt

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;
  }
} 

4
2018-01-15 08:55



Irgendwie funktioniert @Injectable bei mir in Angular nicht 2.0.0-beta.17 beim Verdrahten von ComponentA -> ServiceB -> ServiceC.

Ich habe diesen Ansatz gewählt:

  1. Verweisen Sie auf alle Dienste im Feld "Provider" von @ ComponentA.
  2. In ServiceB verwenden Sie die Annotation @Inject im Konstruktor, um ServiceC zu verbinden.

Lauf dieser Plunker um ein Beispiel zu sehen oder den Code unten zu sehen

app.ts

@Component({selector: 'my-app',
    template: `Hello! This is my app <br/><br/><overview></overview>`,
    directives: [OverviewComponent]
})
class AppComponent {}

bootstrap(AppComponent);

übersicht.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();
    }
}

Übersicht-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();
    }
}

Eigenschaften-service.ts

// Using @Injectable here doesn't make a difference
export class PropertiesService {

    logHi(){
        console.log("hi");
    }
}

2
2018-05-22 14:47



Ich bin mir nicht sicher, ob eine Antwort noch erforderlich ist, also würde ich weitermachen und versuchen, dies zu beantworten.

Betrachten Sie das folgende Beispiel, in dem wir eine Komponente haben, die einen Service verwendet, um einige Werte in ihrer Vorlage wie unten zu füllen

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()
  }
}

Der obige Code ist ziemlich einfach und es wird versuchen, alle GetPersons aus dem DataService zurückzuholen. Die DataService-Datei ist unten verfügbar.

data.service.ts

export class DataService {

persons:<Array>;

constructor(){
    this.persons = [
      {name: "Apoorv"},
      {name: "Bryce"},
      {name: "Steve"}
    ]
}

getPersons(){

return this.persons

}

Der obige Code wird ohne den @Injectable Decorator einwandfrei funktionieren. Aber das Problem beginnt, wenn unser Dienst (in diesem Fall DataService) einige Abhängigkeiten benötigt, wie z. Http. wenn wir unsere ändern data.service.ts Datei wie unten erhalten wir eine Fehlermeldung, die sagt 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

}

Dies hat etwas damit zu tun, wie Dekoratoren in Angular 2 funktionieren. Bitte lesen https://blog.thoughtram.io/angular/2015/05/03/the-difference-between-annotations-and-decorators.html um ein tiefes Verständnis für dieses Problem zu bekommen.

Der obige Code funktioniert auch nicht, da wir HTTP auch in unser Bootstrap-Modul importieren müssen.

Aber eine Daumenregel, die ich vorschlagen kann, ist, dass, wenn Ihre Servicedatei eine Abhängigkeit benötigt, sollten Sie diese Klasse mit einem Decorator @Injectable dekorieren.

Referenz:https://blog.thoughtram.io/angular/2015/09/17/resolve-service-dependencies-in-angular-2.html


2
2018-03-21 08:25



Das erste, was zu tun ist, um alle Dienstleistungen mit dem zu kommentieren @Injectable Anmerkung. Beachten Sie die Klammern am Ende der Anmerkung, ohne dass diese Lösung nicht funktioniert.

Sobald dies erledigt ist, können wir dann mithilfe der Konstruktorinjektion Dienste miteinander injizieren:

@Injectable()
export class MyFirstSvc {

}

@Injectable()
export class MySecondSvc {
    constructor(helpfulService: MyFirstSvc) {        
    }
}

@Injectable()
export class MyThirdSvc {
    constructor(helpfulService: MyFirstSvc) {        
    }
}

0
2017-08-21 19:53



Zuerst müssen Sie Ihren Service bereitstellen

Sie können es entweder in der Bootstrap-Methode angeben:

bootstrap(AppComponent,[MyFirstSvc]);

oder die auf der App-Komponente oder in einer anderen Komponente, je nach Ihren Bedürfnissen .:

@Component({
    ...
      providers:[MyFirstSvc]
}
...

Dann injiziere nur deinen Dienst mit dem Konstruktor:

export class MySecondSvc {
      constructor(private myFirstSvc : MyFirstSvc ){}
}

0
2018-04-05 10:07