创建具有依赖关系的类的新实例,而不是了解工厂提供者 [英] Create new instance of class that has dependencies, not understanding factory provider

查看:144
本文介绍了创建具有依赖关系的类的新实例,而不是了解工厂提供者的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在这个工作了一段时间了,似乎找不到一个明确的答案。我有一个TestComponent,它使用TestService从服务器中获取一个TestModels数组。当我抓住这些测试模型时,它只是服务器正在读取并以正确的MIME类型发回的json文件。一旦测试模型从服务器上抓取,我把它们放在一个简单的选择元素下拉列表中。当选择测试模型时,它会在嵌套组件TestDetailComponent中显示所选的测试模型。



这很好,而且工作正常。当我从服务器中提取数据时,我会遇到问题。由于JavaScript没有运行时检查,因此我们无法将JSON从服务器自动转换为typescript类,所以我需要手动创建一个具有Retre JSON的TestModel实例。



好吧,这是问题。我需要调用新的TestModel并赋予它依赖性,但它需要是TestModel的一个新实例。我希望TestModel能够将其自身保存并更新到服务器,因此它具有对来自@ angular / core的Http的依赖性,并且它依赖于配置类,我将使用opaqueToken CONFIG.I注入角色无法弄清楚如何获取TestModel的新实例。这是初始文件



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],
指令:[TestDetailComponent]
})
导出类TestComponent实现OnInit {

测试:TestModel [] = [];
selectedTest:TestModel;

构造函数(private testService:TestService){};

ngOnInit(){
this.testService.getTestsModels()。subscribe((tests)=> {
console.log(tests);
this。 tests = tests
});
}
}

TestComponent模板:

 < select [(ngModel)] =selectedTest> 
< option * ngFor =let test of tests[ngValue] =test> {{test.testing}}< / option>
< / select>
< test-detail * ngIf =selectedTest[test] =selectedTest>< / test-detail>

TestDetailComponent:

 code> 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',
管道: [JsonPipe]
})
export class TestDetailComponent {
@Input()test;
}

TestDetailComponent模板

 < p style =font-size:3em> {{test | JSON}}< / p为H. 

TestModel

  import {Injectable,Inject} from'@ angular / core';来自'@ angular / http'的
import {Http,Response,Headers,RequestOptions};
import {Observable} from'rxjs / Rx';

import {CONFIG}来自'./../../config/constants';

@Injectable()
export class TestModel {

testing:number;
that:string;
a:string;

构造函数(私有http:Http,@Inject(CONFIG)private config){}

save():Observable< TestModel []> {

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

返回this.http.post(url,body,options)
.map((response)=> response.json())
.map((results) => {
results.map((aggregate,current)=> {
aggregate.push(< TestModel> current);
return aggregate;
} Array< TestModel>())
})。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});

返回this.http.put(url,body,options)
.map((response)=> response.json())
.map((results) => {
results.map((aggregate,current)=> {
aggregate.push(< TestModel> current);
return aggregate;
} Array< TestModel>())
})。catch(this.handleError);

}

private handleError(err):Observable< any> {

让errMessage = err.message? err.message:err.status? `$ {err.status} - $ {err.statusText}`:'服务器错误';

return Observable.throw(new Error(errMessage));

}

}

测试服务

  import {Injectable,Inject} from'@ angular / core'; 
import {Http,Response} from'@ angular / http';
import {Observable} from'rxjs / Rx';

import {CONFIG}来自'./../../config/constants';
import {TestModel} from'./test.model';

@Injectable()
导出类TestService {

构造函数(私有http:Http,@Inject(CONFIG)private config){}

getTestsModels():Observable< TestModel []> {

let url = this.config.apiUrl +test;

返回this.http.get(url)
.map((response)=> response.json())
.map((results)=> {
return results.map((current)=> {
return< TestModel> current; //<<< ---这里是错误
})
})
.catch(this.handleError);

}

private handleError(err):Observable< any> {

让errMessage = err.message? err.message:err.status? `$ {err.status} - $ {err.statusText}`:'服务器错误';

return Observable.throw(new Error(errMessage));

}

}

使用ReflectiveInjector,因此TestService成为:

  import'Injectable,Inject,ReflectiveInjector} from'@ angular / core'; 
import {Http,Response} from'@ angular / http';
import {Observable} from'rxjs / Rx';

import {CONFIG}来自'./../../config/constants';
import {TestModel} from'./test.model';

@Injectable()
导出类TestService {

构造函数(私有http:Http,@Inject(CONFIG)private config){}

getTestsModels():Observable< TestModel []> {

let url = this.config.apiUrl +test;

返回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< any> {

让errMessage = err.message? err.message:err.status? `$ {err.status} - $ {err.statusText}`:'服务器错误';

return Observable.throw(new Error(errMessage));

}

}

但是那么我只是得到错误:





然后如果我添加Http到ReflectiveInjector我只是得到另一个连接后端错误,我假设将继续依赖链,直到我们找到底部。



对于长的帖子任何帮助将不胜感激!

解决方案

您可以提供工厂功能。这不同于简单的 useFactory:... 提供者,如

  {
提供:'TestModelFactory',
useFactory:()=> {
return(http,config)=> {
返回新的TestModel(http,config);
};
},
deps:[Http,CONFIG];
}

然后使用它像

  @Injectable()
export class TestService {

构造函数(@Inject('TestModelFactory'testModelFactory){}

getTestsModels():Observable< TestModel []> {
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 //分配数据
})
})
.catch(this.handleError);
}
}

您还可以支持每个实例参数,如

  {
提供:'TestModelFactory',
useFac tory:(json)=> {
return(http,config)=> {
返回新的TestModel(http,config,json);
};
},
deps:[Http,CONFIG];
}

然后使用它像

  @Injectable()
export class TestService {

构造函数(@Inject('TestModelFactory'testModelFactory){}

getTestsModels():Observable< TestModel []> {
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);
}
}

但是您不需要需要使用DI,您已经注入 Http CONFIG 插入到您的 TestService 中,您可以

  @Inje ctable()
export class TestService {

constructor(private http:Http,@Inject(CONFIG)private config){}

getTestsModels() TestModel []> {

let url = this.config.apiUrl +test;

返回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< any> {

让errMessage = err.message? err.message:err.status? `$ {err.status} - $ {err.statusText}`:'服务器错误';

return Observable.throw(new Error(errMessage));

}
}

在每种情况下,您需要提供例如,通过将JSON传递给构造函数并初始化<$ c的成员,从某种方式初始化 TestModel result $ c> TestModel 从传递的JSON。



另请参见 Angular2:如何使用同一服务的多个实例?


I've been working on this for a while now and can't seem to find an answer clear enough to understand. I have a TestComponent that grabs an array of TestModels from a server using TestService. When I grab these test models it is just a json file that the server is reading and sending back with the correct mime type. Once the test models are grabbed from the server, I put them in a simple select element drop down. When a test model is selected it display the selected test model in a nested component, TestDetailComponent.

That is all well and good and is working fine. I keep running into issues when I am pulling in the data from the server. Since JavaScript has no runtime checking we can't automatically cast the JSON from the server to a typescript class so I need to manually create a new instance of the TestModel with the retreived JSON.

Okay so here is the problem. I need to call new TestModel and give it its dependencies but it needs to be a new instance of TestModel. I want the TestModel to be able to save and update itself back to the server so it has a dependency on Http from @angular/core and it has a dependency on a config class I made that the angular injects with an opaqueToken, CONFIG.I can't figure out how to get new instances of TestModel. Here are the initial files

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

TestComponent template:

<select [(ngModel)]="selectedTest">
    <option *ngFor="let test of tests" [ngValue]="test">{{test.testing}}</option>
</select>
<test-detail *ngIf="selectedTest" [test]="selectedTest"></test-detail>

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

TestDetailComponent template

<p style="font-size: 3em;">{{test | json}}</p>

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<TestModel[]> {

        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(<TestModel>current);
                                return aggregate;
                            }, new Array<TestModel>())
                        }).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(<TestModel>current);
                                return aggregate;
                            }, new Array<TestModel>())
                        }).catch(this.handleError);

    }

    private handleError(err): Observable<any> {

        let errMessage = err.message ? err.message : err.status ? `${err.status} - ${err.statusText}` : 'Server Error';

        return Observable.throw(new Error(errMessage));

    }

}

Test Service

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<TestModel[]> {

        let url = this.config.apiUrl + "test";

        return this.http.get(url)
                        .map( (response) => response.json() )
                        .map( (results) => {
                            return results.map( (current) => {
                                return <TestModel>current; // <<<--- here is the error
                            })
                        })
                        .catch(this.handleError);

    }

    private handleError(err): Observable<any> {

        let errMessage = err.message ? err.message : err.status ? `${err.status} - ${err.statusText}` : 'Server Error';

        return Observable.throw(new Error(errMessage));

    }

}

I have tried using the ReflectiveInjector so TestService becomes this:

    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<TestModel[]> {

        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<any> {

        let errMessage = err.message ? err.message : err.status ? `${err.status} - ${err.statusText}` : 'Server Error';

        return Observable.throw(new Error(errMessage));

    }

}

But then I just get the error:

Then if I add Http to the ReflectiveInjector I just get another connection backend error and I am assuming that would keep going to the dependency chain till we found the bottom.

Sorry for the long post, any help would be appreciated!

解决方案

You can provide a factory function. This is different from a simple useFactory: ... provider like

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

and then use it like

@Injectable()
export class TestService {

   constructor(@Inject('TestModelFactory' testModelFactory) {}

   getTestsModels(): Observable<TestModel[]> {
        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);
    }
}

You can also support per instance parameters like

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

and then use it like

@Injectable()
export class TestService {

   constructor(@Inject('TestModelFactory' testModelFactory) {}

   getTestsModels(): Observable<TestModel[]> {
        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);
    }
}

But you don't need to use DI. You already inject Http and CONFIG into your TestService. You can just

@Injectable()
export class TestService {

    constructor(private http: Http, @Inject(CONFIG) private config) {}

    getTestsModels(): Observable<TestModel[]> {

        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<any> {

        let errMessage = err.message ? err.message : err.status ? `${err.status} - ${err.statusText}` : 'Server Error';

        return Observable.throw(new Error(errMessage));

    }
}

In every case you need to provide some way to initialize TestModel from result for example by passing the JSON to the constructor and initialize the members of TestModel from the passed JSON.

See also Angular2: How to use multiple instances of same Service?

这篇关于创建具有依赖关系的类的新实例,而不是了解工厂提供者的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆