私はアンギュラユニバーサルで動的フォームを作成しようとしています。フォームは作成者によってフォームがどのようにデザインされたかによって、特定の質問が必須であるように設定され、その他は設定されません。ユーザーが記入するためのフォームを表示すると、Angular Universal(JiTコンパイラ、AoTコンパイラと比較して)を使わずに完全に正常に機能しました。アンギュラユニバーサル: "未定義の '_updateTreeValidity'プロパティを読み取ることができません。
フォームには、各フォームの質問に注入されるカスタムコンポーネントが含まれています。これにより、ユーザーは送信するためにコンポーネントにレスポンスを入力できます。
アプリケーションが正常にコンパイルされますが、このコンポーネントがロードされたとき、私は多くのエラーを取得:
Cannot read property '_updateTreeValidity' of undefined
Cannot read property 'setParent' of undefined at e._registerControl
ERROR Error: formGroup expects a FormGroup instance. Please pass one in.
これは、フォームのtypescriptですです:
import { Component, OnInit, ViewChild, OnDestroy, NgZone, EventEmitter } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { AuthenticationService } from '../../services/authentication.service';
import { ProgramsService } from '../../services/programs.service';
import { InfoService } from '../../services/info.service';
import { FormGroup, FormControl, FormBuilder, Validators, FormArray } from '@angular/forms';
import { SessionsService } from '../../services/sessions.service';
import { Answers } from '../formComponents/answers';
import { AnswerComponent } from '../formComponents/answer.component';
@Component({
templateUrl: './intro.component.html',
styleUrls: ['./intro.component.css'],
providers: [SessionsService, InfoService, ProgramsService]
})
export class IntroComponent implements OnInit, OnDestroy{
constructor(private router: Router, private route: ActivatedRoute, private _programsService: ProgramsService, private zone: NgZone, private _fb: FormBuilder, private _sessionsService: SessionsService){
this.myForm = this._fb.group({
questions: this._fb.array([])
});
this.subcribeToFormChanges();
}
programId: string;
sessionId: string;
private sub: any;
res;
coachUsername;
welcomeHeader;
welcomeDescription;
welcomeFiles;
requiredQuestions;
formData: FormData;
public myForm: FormGroup;
public events: any[] = [];
loading;
introCompleted;
isForm = false;
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
this.sessionId = params['id'];
this.getSessionInfo(this.sessionId);
});
}
getSessionInfo(id){
this.loading = true;
this._sessionsService.getSession(id).subscribe(res=>{
this.loading = false;
console.log(res.programId);
this.programId = res.programId;
if(res.introSessionCompleted == false){
this.introCompleted = false;
this.getForm();
}
if(res.introSessionCompleted == true){
this.introCompleted = true;
this.getAnswers();
}
})
}
getAnswers(){
this._sessionsService.getAnswerIntro(this.sessionId).subscribe(res=>{
console.log('session answers');
console.log(res);
this.fillAnswers(res);
})
}
fillAnswers(res){
this.getFormLight();
for(var i=0; i<res.questions.length; i++){
this.answerQuestion(res.questions[i].type, res.questions[i].placeholder, res.questions[i].title, res.questions[i].required, res.questions[i].answer);
}
}
getFormLight(){
this._programsService.clientGetIntro(this.programId).subscribe(res=>{
console.log('Intro res:')
console.log(res)
this.welcomeDescription = res.welcomeDescription;
this.welcomeHeader = res.welcomeHeader;
this.welcomeFiles = res.welcomeFiles;
})
}
getForm(){
this._programsService.clientGetIntro(this.programId).subscribe(res=>{
this.isForm = true;
console.log('Intro res:')
console.log(res)
this.res = res;
this.welcomeDescription = res.welcomeDescription;
this.welcomeHeader = res.welcomeHeader;
this.welcomeFiles = res.welcomeFiles;
this.requiredQuestions = res.requiredQuestions;
if(this.requiredQuestions){
for(var i=0; i<this.requiredQuestions.length; i++){
this.addQuestion(this.requiredQuestions[i].type, this.requiredQuestions[i].placeholder, this.requiredQuestions[i].title, this.requiredQuestions[i].required);
}
}
})
}
initQuestion(type, placeholder, title, required) {
if(required == 'yes'){
return this._fb.group({
type: [type],
placeholder: [placeholder],
title: [title],
required: [required],
answer: ['', Validators.required]
});
}
if(required == 'no'){
return this._fb.group({
type: [type],
placeholder: [placeholder],
title: [title],
required: [required],
answer: ['']
});
}
}
initAnswerQuestion(type, placeholder, title, required, answer){
return this._fb.group({
type: [type],
placeholder: [placeholder],
title: [title],
required: [required],
answer: new FormControl({value: answer, disabled: true})
});
}
ngOnDestroy() {
this.sub.unsubscribe();
}
save(model: Answers, isValid: boolean) {
this._sessionsService.answerIntro(this.programId, this.sessionId, JSON.stringify(model)).subscribe(res=>{
console.log(res);
if(res.message == 'Finished updating answers'){
this.router.navigateByUrl('/account/sessions/view/'+this.sessionId)
}
})
}
addQuestion(type, placeholder, title, required) {
const control = <FormArray>this.myForm.controls['questions'];
const addrCtrl = this.initQuestion(type, placeholder, title, required);
control.push(addrCtrl);
}
answerQuestion(type, placeholder, title, required, answer) {
const control = <FormArray>this.myForm.controls['questions'];
const addrCtrl = this.initAnswerQuestion(type, placeholder, title, required, answer);
control.push(addrCtrl);
}
removeQuestion(i: number) {
const control = <FormArray>this.myForm.controls['questions'];
control.removeAt(i);
}
subcribeToFormChanges() {
const myFormStatusChanges$ = this.myForm.statusChanges;
const myFormValueChanges$ = this.myForm.valueChanges;
myFormStatusChanges$.subscribe(x => this.events.push({ event: 'STATUS_CHANGED', object: x }));
myFormValueChanges$.subscribe(x => this.events.push({ event: 'VALUE_CHANGED', object: x }));
}
}
これはhtmlです形式:
これは、カスタム回答コンポーネントtypescriptです
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
@Component({
moduleId: module.id,
selector: 'answer',
templateUrl: 'answer.component.html',
styleUrls: ['./answer.component.css']
})
export class AnswerComponent implements OnInit {
@Input('group')
public answerForm: FormGroup;
type;
title;
required;
disabled;
ngOnInit(){
this.type = this.answerForm.controls['type'].value;
this.required = this.answerForm.controls['required'].value;
this.title = this.answerForm.controls['title'].value;
if(this.answerForm.controls['answer'].value != null && this.answerForm.controls['answer'].value != ''){
this.disabled = true;
console.log('disabled');
}
}
}
最後にあり、ここで私が問題でngForオブジェクトに対する応答のいずれかを考え出し
<div [formGroup]="answerForm">
<div class="form-group">
<div class="left-hand">
<div class="question-text"><a>{{title}}</a></div>
</div>
<div class="right-hand">
<textarea *ngIf="type=='text'" class="form-answer" placeholder="Type answer here..." formControlName="answer"></textarea>
<input class="number" type="number" placeholder="Enter answer here..." formControlName="answer" *ngIf="type=='number'" >
<select *ngIf="type=='yesno'" formControlName="answer" >
<option value="" disabled selected>Choose answer</option>
<option>Yes</option>
<option>No</option>
</select>
</div>
</div>
</div>