Crea una nuova istanza di class che abbia dipendenze, non comprendendo il fornitore di fabbrica

Ci sto lavorando da un po ‘e non riesco a trovare una risposta abbastanza chiara da capire. Ho un TestComponent che cattura una matrice di TestModels da un server usando TestService. Quando afferro questi modelli di test è solo un file JSON che il server sta leggendo e inviando indietro con il tipo MIME corretto. Una volta che i modelli di test sono stati prelevati dal server, li ho inseriti in un semplice elemento di selezione a discesa. Quando viene selezionato un modello di test, visualizza il modello di test selezionato in un componente nidificato, TestDetailComponent.

Questo è tutto a posto e funziona bene. Continuo a riscontrare problemi quando inserisco i dati dal server. Dal momento che JavaScript non esegue il controllo di runtime, non è ansible eseguire il cast automatico del JSON dal server a una class typescript, quindi è necessario creare manualmente una nuova istanza di TestModel con il JSON ritirato.

Va bene, ecco il problema Devo chiamare il nuovo TestModel e dargli le sue dipendenze, ma deve essere una nuova istanza di TestModel. Voglio che TestModel sia in grado di salvare e aggiornarsi di nuovo al server in modo che abbia una dipendenza da Http da @ angular / core e abbia una dipendenza da una class di configurazione che ho fatto che l’angular si inietta con un opaqueToken, CONFIG.I non riesco a capire come ottenere nuove istanze di TestModel. Ecco i file iniziali

TestComponent:

import { Component, OnInit } from '@angular/core'; import { TestService } from './shared/test.service'; import { TestModel } from './shared/test.model'; import { TestDetailComponent } from './test-detail.component'; @Component({ selector: "test-component", templateUrl: 'app/test/test.component.html', styleUrls: [], providers: [TestService], directives: [TestDetailComponent] }) export class TestComponent implements OnInit { tests: TestModel[] = []; selectedTest: TestModel; constructor(private testService: TestService) {}; ngOnInit() { this.testService.getTestsModels().subscribe( (tests) => { console.log(tests); this.tests = tests }); } } 

Modello TestComponent:

  {{test.testing}}   

TestDetailComponent:

 import { Component, Input } from '@angular/core'; import { JsonPipe } from '@angular/common'; import { TestModel } from './shared/test.model'; @Component({ selector: 'test-detail', templateUrl: 'app/test/test-detail.component.html', pipes: [JsonPipe] }) export class TestDetailComponent { @Input() test; } 

Modello TestDetailComponent

 

{{test | json}}

TestModel

 import { Injectable, Inject } from '@angular/core'; import { Http, Response, Headers, RequestOptions } from '@angular/http'; import { Observable } from 'rxjs/Rx'; import { CONFIG } from './../../config/constants'; @Injectable() export class TestModel { "testing": number; "that": string; "a": string; constructor(private http: Http, @Inject(CONFIG) private config) {} save(): Observable { let url = this.config.apiUrl + "test"; let body = JSON.stringify({ testing: this.testing, this: this.that, a: this.a }); let headers = new Headers({'Content-Type': 'application/json'}); let options = new RequestOptions({headers: headers}); return this.http.post(url, body, options) .map( (response) => response.json() ) .map( (results) => { results.map( (aggregate, current) => { aggregate.push(current); return aggregate; }, new Array()) }).catch(this.handleError); } update() { let url = this.config.apiUrl + "test"; let body = JSON.stringify({ testing: this.testing, this: this.that, a: this.a }); let headers = new Headers({'Content-Type': 'application/json'}); let options = new RequestOptions({headers: headers}); return this.http.put(url, body, options) .map( (response) => response.json() ) .map( (results) => { results.map( (aggregate, current) => { aggregate.push(current); return aggregate; }, new Array()) }).catch(this.handleError); } private handleError(err): Observable { let errMessage = err.message ? err.message : err.status ? `${err.status} - ${err.statusText}` : 'Server Error'; return Observable.throw(new Error(errMessage)); } } 

Test del servizio

 import { Injectable, Inject } from '@angular/core'; import { Http, Response } from '@angular/http'; import { Observable } from 'rxjs/Rx'; import { CONFIG } from './../../config/constants'; import { TestModel } from './test.model'; @Injectable() export class TestService { constructor(private http: Http, @Inject(CONFIG) private config) {} getTestsModels(): Observable { let url = this.config.apiUrl + "test"; return this.http.get(url) .map( (response) => response.json() ) .map( (results) => { return results.map( (current) => { return current; // <<<--- here is the error }) }) .catch(this.handleError); } private handleError(err): Observable { let errMessage = err.message ? err.message : err.status ? `${err.status} - ${err.statusText}` : 'Server Error'; return Observable.throw(new Error(errMessage)); } } 

Ho provato a utilizzare ReflectiveInjector in modo che TestService diventi questo:

  import { Injectable, Inject, ReflectiveInjector } from '@angular/core'; import { Http, Response } from '@angular/http'; import { Observable } from 'rxjs/Rx'; import { CONFIG } from './../../config/constants'; import { TestModel } from './test.model'; @Injectable() export class TestService { constructor(private http: Http, @Inject(CONFIG) private config) {} getTestsModels(): Observable { let url = this.config.apiUrl + "test"; return this.http.get(url) .map( (response) => response.json() ) .map( (results) => { return results.map( (current) => { return ReflectiveInjector.resolveAndCreate([TestModel]).get(TestModel); }) }) .catch(this.handleError); } private handleError(err): Observable { let errMessage = err.message ? err.message : err.status ? `${err.status} - ${err.statusText}` : 'Server Error'; return Observable.throw(new Error(errMessage)); } } 

Ma poi ho appena ricevuto l’errore:

inserisci la descrizione dell'immagine qui

Quindi, se aggiungo Http al ReflectiveInjector, ottengo solo un altro errore di backend di connessione e presumo che continuerebbe ad andare alla catena delle dipendenze finché non avremo trovato il fondo.

Scusa per il post lungo, ogni aiuto sarebbe apprezzato!

È ansible fornire una funzione di fabbrica. Questo è diverso da un semplice useFactory: ... provider come

 { provide: 'TestModelFactory', useFactory: () => { return (http, config) => { return new TestModel(http, config); }; }, deps: [Http, CONFIG]; } 

e poi usarlo come

 @Injectable() export class TestService { constructor(@Inject('TestModelFactory' testModelFactory) {} getTestsModels(): Observable { let url = this.config.apiUrl + "test"; return this.http.get(url) .map( (response) => response.json() ) .map( (results) => { return results.map( (current) => { let tm = testModelFactory(); tm.xxx // assign data }) }) .catch(this.handleError); } } 

Puoi anche supportare parametri di istanza come

 { provide: 'TestModelFactory', useFactory: (json) => { return (http, config) => { return new TestModel(http, config, json); }; }, deps: [Http, CONFIG]; } 

e poi usarlo come

 @Injectable() export class TestService { constructor(@Inject('TestModelFactory' testModelFactory) {} getTestsModels(): Observable { let url = this.config.apiUrl + "test"; return this.http.get(url) .map( (response) => response.json() ) .map( (results) => { return results.map( (current) => { let tm = testModelFactory(result); }) }) .catch(this.handleError); } } 

Ma non è necessario usare DI. Hai già inserito Http e CONFIG nel tuo TestService . Puoi solo

 @Injectable() export class TestService { constructor(private http: Http, @Inject(CONFIG) private config) {} getTestsModels(): Observable { let url = this.config.apiUrl + "test"; return this.http.get(url) .map( (response) => response.json() ) .map( (results) => { return results.map( (current) => { return new TestModel(http, config); }) }) .catch(this.handleError); } private handleError(err): Observable { let errMessage = err.message ? err.message : err.status ? `${err.status} - ${err.statusText}` : 'Server Error'; return Observable.throw(new Error(errMessage)); } } 

In ogni caso è necessario fornire un modo per inizializzare TestModel dal result ad esempio passando il JSON al costruttore e inizializzando i membri di TestModel dal JSON passato.

Vedi anche Angular2: Come utilizzare più istanze dello stesso servizio?

Prima di tutto, stai mescolando qui due problemi separati: uno sta tenendo i dati, che è la preoccupazione del tuo TestModel, e un altro sta salvando quei dati, che non lo sono. Questa seconda preoccupazione dovrebbe essere implementata in TestService invece, è sua preoccupazione parlare con il server, quindi lascia che faccia il suo lavoro.

Quindi, gli iniettabili angolari sono destinati a essere singoletti. Abbastanza ovvio che gli oggetti dati non siano singleton, quindi non dovresti iniettarli attraverso DI. Ciò che è registrato con DI è inteso come servizio che funziona con oggetti dati, non con oggetti dati stessi. Puoi gestire direttamente gli oggetti dati o creare un servizio di fabbrica che li creerà per te stesso. Ci sono molti modi per ottenerlo senza DI.

Puoi trovare maggiori dettagli su angular2 DI qui . È piuttosto lungo ma per fortuna non è molto complicato.

Grazie a tutti quelli sopra, questo è un plunker funzionante che ho usato. Spero che sia d’aiuto

http://plnkr.co/edit/NxGQoTwaZi9BzDrObzyP

 import {Component, NgModule, VERSION, Injectable, Inject} from '@angular/core' import {BrowserModule} from '@angular/platform-browser' import {HttpClient} from '@angular/common/http' import {HttpModule} from '@angular/http' @Injectable() export class HttpService{ token = 'hihaa'; constructor(){ } myFunction(value){ console.log(value) } } export class Country{ constructor(value,public httpService: HttpService){ console.log(value,this); } classs(){ this.httpService.myFunction('BGGGG') } } @Component({ selector: 'my-app', template: ` 

Hello {{name}}

`, }) export class App { name:string; country:any; constructor( @Inject('CountryFactory') countryFactory ) { this.name = `Angular! v${VERSION.full}`; this.country = countryFactory(3); this.country.classs(); } } export let CountryProvider = { provide: 'CountryFactory', useFactory: (httpService) => { return (value) =>{ return new Country(value,httpService) }; }, deps: [HttpService] } @NgModule({ imports: [ BrowserModule,HttpModule ], declarations: [ App ], bootstrap: [ App ], providers: [ HttpService, CountryProvider ] }) export class AppModule {}