从API为Angular 2动态表单设置值

时间:2016-12-16 17:49:59

标签: angular

我正在尝试在Angular 2中创建动态表单,我正在使用Angular cookbook here中的设置作为我的起点。我的设置没有任何问题,只是将服务中的数据硬编码为api调用。我的问题是,当我尝试使用api调用时,值似乎没有正确设置。

在Angular食谱中,他们将question.service.ts文件硬编码为:

getQuestions() {
let questions: QuestionBase<any>[] = [
  new DropdownQuestion({
    key: 'brave',
    label: 'Bravery Rating',
    options: [
      {key: 'solid',  value: 'Solid'},
      {key: 'great',  value: 'Great'},
      {key: 'good',   value: 'Good'},
      {key: 'unproven', value: 'Unproven'}
    ],
    order: 3
  }),
  new TextboxQuestion({
    key: 'firstName',
    label: 'First name',
    value: 'Bombasto',
    required: true,
    order: 1
  }),
  new TextboxQuestion({
    key: 'emailAddress',
    label: 'Email',
    type: 'email',
    order: 2
  })
 ];
   return questions.sort((a, b) => a.order - b.order);
 }
}

然后从app.component.ts文件中简单地从构造函数调用:

 constructor(service: QuestionService) {
 this.questions = service.getQuestions();
 }

哪些&#34;问题&#34;然后在app.component.ts模板中绑定到这个

 <dynamic-form [questions]="questions"></dynamic-form> 

我对question.service.ts进行了更改以进行api调用(现在来自json文件,因为我无法在家中访问api)

 getFirstQuestion() {
    return this._http.get(this.__questionJSONApiBaseUrl)
        .map(data => data.json())
        .do(data => console.log('All: ' + JSON.stringify(data)))
        .catch(this.handleError);
}

从app.component.ts调用

ngOnInit() {
    this.service.getFirstQuestion()
        .subscribe(data => {
            this.data = data;

            if (data.Type == 'TextBox') {
                let questions: QuestionBase<any>[] = [
                    new TextboxQuestion({
                        key: data.Title,
                        label: data.Text,
                        value: '',
                        required: true,                          
                        order: data.Id
                    })];
            }              
        }
        );
 }

如您所见,我在.subscribe()中设置了属性,但它似乎没有正常工作,因为当它绑定到模板中的[问题]时,我得到了一个&#34;无法读取财产&#39; forEach&#39;未定义&#34;来自question-control.service文件的错误,该文件将问题转换为FormGroup。

我知道数据正在进入,因为我可以在if语句中设置警报并成功查看api调用中的数据。我相信我的问题是[问题]在数据准备好之前具有约束力。有人可以告诉我一个更好的方法来做到这一点,或者请提出任何建议,我做错了吗?有没有办法可以先在api中设置属性?

3 个答案:

答案 0 :(得分:1)

正如@silentsod指出的那样,这里的问题是你正在进行异步操作,并尝试将其存储为你的问题。您需要处理异步。

您可以采用以下两种方式......或者从组件类中执行:

while read -r branch_line; do

或者,您可以从模板中使用异步管道:

service.getQuestions((questions) => this.questions = questions);

async pipe订阅了observable,在本例中为<dynamic-form [form]="questions | async"></dynamic-form> ,并返回该值。

答案 1 :(得分:0)

我能够使用this示例中的想法进行操作,并根据我的需要进行修改。

我现在设置的方式是加载页面,用户必须单击开始按钮才能获得第一个问题。所以我不再在ngOnInt中调用我的第一个问题了,但是在我的按钮内单击事件方法就像这样:

 getFirstQuestion() {
    //hide the begin survey button once clicked
    this.clicked = true;
    this.service.getQuestion()
        .subscribe(
        q => {
            this.questions = q
        });
}

我的服务中的getQuestion()如下所示:

  getQuestion() {
    return this.http.get(this._questionApiBaseUrl + 'getFirstQuestion' + '?'              'questionId=' + this.questionId)
        .map(res => [res.json()])
        .map(data => {
            this.data = data;            
            return this.buildQuestions(data);
        })            
}

返回此buildQuestions()方法:

 buildQuestions(data: any[]) {
    let questions: any[] = [];
    data.forEach((item: QuestionsGroup) => {
        console.log("my item control in buildQuestion: " + item.controlType);
        if (item.controlType == 'group') {
            let group = new QUESTION_MODELS[item.controlType](item);
            group.questions = this.buildQuestions(item.questions);
            questions.push(group);
        }
        else if (item.controlType == 'RadioButtons') {
            item.controlType = 'radio';
            questions.push(new QUESTION_MODELS[item.controlType](item));
        }
        else if (item.controlType == 'TextBox'){
            item.controlType = 'textbox'; 
            item.type = 'text'               
            questions.push(new QUESTION_MODELS[item.controlType](item));
        }
        else if (item.controlType == 'Datepicker') {
            item.controlType = 'textbox';
            item.type = 'date'
            questions.push(new QUESTION_MODELS[item.controlType](item));
        }
        //TODO add any remaining question types
        else {
            questions.push(new QUESTION_MODELS[item.controlType](item));
        }
    });
    return questions;
}

上面的buildQuestions()方法稍后会被重构,因为当前存在从api到客户端的属性值不匹配。

我之前尝试做事的方式是在从我的通话中返回数据后操纵数据,但是对“questons”的绑定已经发生了。现在,当我订阅它时,从http get调用返回“问题”时,它已经以正确的格式返回。从这里开始,用户将根据他们的答案动态提交答案并获得另一个问题。

以下是我发布答案并提出下一个问题的服务方法(不得不留下一些细节,但你明白了):

 submitAnswer(answer: any) {
    //Interface to formulate my answer 
    var questionAnswer: IAnswer = <any>{};     

   //set answer properties interface here

    let headers = new Headers({ 'Content-Type': 'application/json; charset=utf-8' });
    let options = new RequestOptions({ headers: headers });
    let myAnswerObj = JSON.stringify(questionAnswer);

    return this.http.post(this._questionApiBaseUrl + 'submitanswer', myAnswerObj, options)
        .map(res => [res.json()])
        .map(data => {
            this.data = data;
            //return the next question to the user
            return this.buildQuestions(data);
        });          
}

答案 2 :(得分:0)

dynamic-form.component.ts ngOnInit()函数在我们收到来自api的响应之前运行。

下面是文件

<强>动态form.component.ts

&#13;
&#13;
import { Component, Input, OnInit }  from '@angular/core';
import { FormGroup }                 from '@angular/forms';

import { QuestionBase }              from './question-base';
import { QuestionControlService }    from './question-control.service';

@Component({
  selector: 'dynamic-form',
  templateUrl: './dynamic-form.component.html',
  providers: [ QuestionControlService ]
})
export class DynamicFormComponent implements OnInit {

  @Input() questions: QuestionBase<any>[] = [];
  form: FormGroup;
  payLoad = '';

  constructor(private qcs: QuestionControlService) {  }

  ngOnInit() {
    this.form = this.qcs.toFormGroup(this.questions);
  }

  onSubmit() {
    this.payLoad = JSON.stringify(this.form.value);
  }
}
&#13;
&#13;
&#13;