我有一个订阅服务数据的组件。此服务返回我可以订阅的BehaviorSubject
。在返回的数据对象中,有几个数组构成了我的下拉列表的标签/值。
我正在尝试将每个数组的类型转换为自己的接口,然后在我的UI中使用它们。
组件:
import { Observable } from 'rxjs/Rx';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Component, OnInit } from '@angular/core';
import { MassEmpService } from '../shared';
import { Segments } from '../definitions';
@Component({
selector: 'app-transition',
templateUrl: './transition.component.html',
styleUrls: ['./transition.component.css']
})
export class TransitionComponent implements OnInit {
effectiveStartDate: string;
error: string;
transitionFields: any[];
fieldsLoaded = false;
transitionForm: FormGroup;
segments: Segments[] = [];
constructor(
private fb: FormBuilder,
private _massEmpService: MassEmpService
) {
}
ngOnInit() {
this.createForm();
}
// Generate the form
createForm() {
// Create our form for the transition options
this.transitionForm = this.fb.group({
changeType: ['', Validators.required],
effectiveStartDate: ['', Validators.required],
effectiveEndDate: [''],
hierarchy: ['-1'],
segment: ['-1'],
supervisor: ['-1'],
budgetMarket: ['-1'],
incentivePlan: ['-1'],
role: ['-1'],
primaryLanguage: ['-1'],
secondaryLanguage: ['-1'],
});
// Get our form data to populate
this.fetchFieldData();
}
// Fetch the data from our service and set our array to its value received
fetchFieldData() {
this._massEmpService.transitionFields.subscribe((results) => {
this.segments = results.segments.options;
});
this._massEmpService.fetchTransitionFields('');
}
}
接口
export interface Segments {
SegmentID: number;
SegmentName: string;
}
服务
public transitionFields: BehaviorSubject<any> = new BehaviorSubject(null);
/**
* Return an object of the input field data to render the drop-downs.
* If provided a date, use this to find inputs that will either be
* available or removed on that date.
*
* @param {any} effectiveStartDate
* @returns
* @memberof MassEmpService
*/
fetchTransitionFields(effectiveStartDate) {
return this._http.post(this.baseUrl + '/fetchTransitionFields', { "effectiveStartDate": effectiveStartDate }, { "headers": this.headers })
.map((result: Response) => result.json())
.subscribe((results) => this.transitionFields.next(results.data));
};
数据对象:
这:
this._massEmpService.transitionFields.subscribe((results) => {
console.log(results);
});
返回:
我的HTML:
<select name="segment" id="segment" formControlName="segment" class="form-control input-sm">
<option value="-1" selected="selected">No Segment Change</option>
<option *ngFor="let s of segments" value="{{ s.SegmentID }}">{{ s.SegmentName }}</option>
</select>
问题:
在我的组件中,由于订阅在尝试将数据分配给var时没有数据,因此抛出了未定义的错误。我相信我订阅这些数据的方式有问题,不允许我分配这些数据。具体来说,它是segments
未定义。
我尝试直接从结果对象分配segments
的原因是因为我希望能够type
它。一旦我弄清楚这个问题,我会定义更多的下拉菜单。
我的最终目标是我收到的对象中的每个数组都将typed
输出并拥有自己的接口。我宁愿只需要对获取数据对象的服务进行一次调用,然后从那里将其分配给自己的各个对象,就像我正在尝试使用segments
一样。
许多人指出,由于我在分配时没有获得数据而导致async
问题。我只是不确定如何在我当前的设置中解决这个问题。
我在建议中尝试了async pipe
,ngIf
和?.
,但仍然会导致未定义的错误。
答案 0 :(得分:2)
由于您的数据是异步检索的,因此HTML不会获取数据,因此构建组件时skillsets
将为null。有几种方法可以解决这个问题。
方法1 :在html中使用async
管道:
<select name="skillset" id="skillset" formControlName="skillSet" class="form-control input-sm">
<option value="-1" selected="selected">No SkillSet Change</option>
<option *ngFor="let s of skillSets | async" value="{{ s.SkillSetID }}">{{ s.SkillSetName }}</option>
</select>
方法2 :使用猫王操作员?.
<select name="skillset" id="skillset" formControlName="skillSet" class="form-control input-sm">
<option value="-1" selected="selected">No SkillSet Change</option>
<option *ngFor="let s of skillSets" value="{{ s?.SkillSetID }}">{{ s?.SkillSetName }}</option>
</select>
方法3 :使用*ngIf
:
<select *ngIf="skillSets" name="skillset" id="skillset" formControlName="skillSet" class="form-control input-sm">
<option value="-1" selected="selected">No SkillSet Change</option>
<option *ngFor="let s of skillSets" value="{{ s.SkillSetID }}">{{ s.SkillSetName }}</option>
</select>
您仍需要在构造函数中初始化skillsets
。打字稿不能神奇地知道你的默认值Skillsets
。
constructor(){
this.skillSets = [];
}
或者你可以在你的财产层面上做到:
skillSets: SkillSets[] = []; //initialize to empty array.
如果需要,您还可以使用as
:
export class DemoComponent {
effectiveStartDate: string;
error: string;
transitionFields: any[];
fieldsLoaded = false;
transitionForm: FormGroup;
skillSets: SkillSets[];
constructor(){
this.skillSets = [];
}
// Fetch the data from our service and set our array to its value received
fetchFieldData() {
this._massEmpService.transitionFields.subscribe((results) => {
this.transitionFields = results;
this.skillSets = results.segments.options as SkillSets[];
});
this._massEmpService.fetchTransitionFields('');
}
}
答案 1 :(得分:1)
您需要初始化SkillSets数组
{{1}}
答案 2 :(得分:0)
据我所知,你有两个选择:
首先只使用* ngIf,另一个是在构造函数中预定义类。
E.g:
export interface SkillSets {
SkillSetID: number;
SkillSetName: string;
constructor() {
this.SkillSetID = 0;
this.SkillSetName = "Yet undefined";
}
}
在组件内部,例如在构造函数中:
this.skillSets = new SkillSets();
答案 3 :(得分:0)
如果您想使用异步管道,请像这样设置您的技能
skillSets = this._massEmpService.transitionFields();
请注意,您不需要订阅方法。这是使用异步管道并使代码更短的好处。 并在您的模板中。
<option *ngFor="let s of skillSets | async" value="{{ s.SkillSetID }}">
{{ s.SkillSetName }}</option>
最后,像这样更新你的skillSet数据类型
skillSets: Observable<SkillSets[]>;
因为你现在处理的是observable而不仅仅是一个普通的数组。
请注意,如果遇到问题,请尝试在构造函数或OnInit中设置skillSets,从那里调用fetchFieldData()。
更新1
由于您从更新中提供了大量新代码,因此请点击我的最新答案。
如果您使用异步管道,则不需要此代码
this.segments = results.segments.options;
这是您从服务中获取选项数据的方式。您担心的是,您获得了整个数据,而您只需要选择&#39;选项。数据。您需要更改服务中返回数据的方式。将其更改为此
return this._http.post(this.baseUrl + '/fetchTransitionFields', { "effectiveStartDate": effectiveStartDate }, { "headers": this.headers })
.map((result: Response) => result.json().segments.options)
希望这有帮助