我已经在这方面工作了一段时间,似乎无法找到足够明白的答案。我有一个TestComponent,它使用TestService从服务器获取一组TestModel。当我抓住这些测试模型时,它只是一个json文件,服务器正在读取并使用正确的mime类型发回。从服务器获取测试模型后,我将它们放在一个简单的select元素下拉列表中。选择测试模型后,它会在嵌套组件TestDetailComponent中显示所选的测试模型。
这一切都很好,并且工作正常。当我从服务器提取数据时,我一直遇到问题。由于JavaScript没有运行时检查,因此我们无法自动将JSON从服务器转换为typescript类,因此我需要使用已检索的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],
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模板:
<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模板
<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));
}
}
测试服务
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));
}
}
我尝试过使用ReflectiveInjector,因此TestService成为了这个:
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));
}
}
然后我才得到错误:
然后,如果我将Http添加到ReflectiveInjector,我只是得到另一个连接后端错误,我假设在我们找到底部之前会继续执行依赖链。
对不起,很长的帖子,任何帮助将不胜感激!
答案 0 :(得分:10)
您可以提供工厂功能。这与简单的useFactory: ...
提供商(如
{
provide: 'TestModelFactory',
useFactory: () => {
return (http, config) => {
return new TestModel(http, config);
};
},
deps: [Http, CONFIG];
}
然后像
一样使用它@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);
}
}
您还可以支持每个实例参数,例如
{
provide: 'TestModelFactory',
useFactory: (json) => {
return (http, config) => {
return new TestModel(http, config, json);
};
},
deps: [Http, CONFIG];
}
然后像
一样使用它@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);
}
}
但是你没有需要来使用DI。您已将Http
和CONFIG
注入TestService
。你可以
@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));
}
}
在每种情况下,您都需要提供一些方法来从TestModel
初始化result
,例如将JSON传递给构造函数并从传递的JSON初始化TestModel
的成员。 / p>
答案 1 :(得分:1)
首先,您在这里混合了两个不同的问题:一个是保存数据,这是您的TestModel关注的问题,另一个是保存数据,而不是。第二个问题应该在TestService中实现,而不是与服务器通信,所以让它完成它的工作。
然后,角度注射剂旨在成为单体。很明显,数据对象不是单例,所以不应该通过DI注入它们。在DI注册的内容旨在成为使用数据对象的服务,而不是数据对象本身。您可以直接操作数据对象或创建一些工厂服务,这将创建它们本身就是一个单例。没有DI,有很多方法可以实现这一目标。
您可以找到有关angular2 DI here的更多详细信息。这很长,但幸运的是并不复杂。
答案 2 :(得分:0)
感谢上面的每个人, 这是我使用的一个工作的plunker。希望它有所帮助
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);
}
classes(){
this.httpService.myFunction('BGGGG')
}
}
@Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
</div>
`,
})
export class App {
name:string;
country:any;
constructor(
@Inject('CountryFactory') countryFactory
) {
this.name = `Angular! v${VERSION.full}`;
this.country = countryFactory(3);
this.country.classes();
}
}
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 {}