我已经为此工作了一段时间,似乎找不到足够清晰的答案来理解。我有一个 TestComponent,它使用 TestService 从服务器获取一组 TestModel。当我获取这些测试模型时,它只是一个 json 文件,服务器正在读取并以正确的 mime 类型发回。从服务器获取测试模型后,我将它们放在一个简单的选择元素下拉列表中。选择测试模型后,它会在嵌套组件 TestDetailComponent 中显示选定的测试模型。

这一切都很好,并且运行良好。当我从服务器中提取数据时,我一直遇到问题。由于 JavaScript 没有运行时检查,我们无法自动将 JSON 从服务器转换为 typescript 类,因此我需要使用检索到的 JSON 手动创建 TestModel 的新实例。

好的,问题就在这里。我需要调用新的 TestModel 并为其提供依赖项,但它需要是 TestModel 的新实例。我希望 TestModel 能够将自身保存并更新回服务器,因此它依赖于来自 @angular/core 的 Http 并且它依赖于我制作的配置类,该类使用 opaqueToken CONFIG.I 注入(inject)无法弄清楚如何获取 TestModel 的新实例。这是初始文件

测试组件:

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

测试组件模板:
<select [(ngModel)]="selectedTest">
    <option *ngFor="let test of tests" [ngValue]="test">{{test.testing}}</option>
</select>
<test-detail *ngIf="selectedTest" [test]="selectedTest"></test-detail>

测试细节组件:
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>

测试模型
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));

    }

}

但后来我得到了错误:

angular - 创建具有依赖关系的类的新实例,不了解工厂提供者-LMLPHP

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

抱歉,帖子很长,任何帮助将不胜感激!

最佳答案

您可以提供工厂功能。这与简单的 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。您已经将 HttpCONFIG 注入(inject)到您的 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 的成员。

另见 Angular2: How to use multiple instances of same Service?

关于angular - 创建具有依赖关系的类的新实例,不了解工厂提供者,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38472103/

10-15 09:01