2017-10-05 65 views
0

我想在Angular Universal中构建一个动态表单。表单的设置使得某些问题是强制性的,而其他问题则不是,这取决于表单是由创建者设计的。当显示用户填写的表单时,如果没有Angular Universal(JiT编译器,相对于AoT编译器),它就会工作得很好。Angular Universal:“无法读取属性'_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.

这是形式的打字稿:

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表格:

<div class="container animated fadeIn" style="padding-top:140px" > 
    <div class="session-container"> 
    <div class="row nomargin"> 
    <div class="session-container-header"> 
     <div *ngIf="introCompleted" class="back" [routerLink]="['/account/sessions/view', sessionId]"> 
     <i class="fa fa-arrow-circle-left"></i>Session Dashboard 
     </div> 
     <div *ngIf="!introCompleted" class="back" [routerLink]="['/account/sessions']"> 
     <i class="fa fa-arrow-circle-left"></i>All Sessions 
     </div> 
     <div class="title"> 
     Session Introduction 
     </div> 
     <div *ngIf="introCompleted" class="settings-icon"> 
        <i class="fa fa-gear" [class.fa-spin]="mouseOvered" (mouseover)="mouseOvered=true" (mouseleave)="mouseOvered=false" [routerLink]="['/account/sessions/view/'+id+'/settings']"></i> 
       </div> 
    </div> 
    </div> 
    <div class="row nomargin"> 
     <div *ngIf="!loading" class="session-container-content"> 
     <div class="row nomargin"> 



     <div class="intro-container"> 
      <div class="intro-welcome"> 
      <a>{{welcomeHeader}}</a> 
      </div> 
      <div class="intro-photo"> 

      </div> 
      <div class="intro-description"> 
      <a>{{welcomeDescription}}</a> 
      </div> 


      <div class="intro-files"> 
      <div class="intro-border"> 
       <a>Introduction Files</a> 
      </div> 
      <div class="files-row"> 
       <div *ngFor="let file of welcomeFiles" class="file-container" [style.background]="'url('+file.url+')'"> 
       <div class="overlay"> 
        <a [href]="file.url" class="file-url"><div class="download-button"> 
        <a><i class="fa fa-cloud-download" style="margin-right: 5px;"></i>Download</a> 
        </div></a> 
       </div> 
       </div> 
      </div> 
      </div> 



      <div class="intro-questions"> 
      <div class="intro-border"> 
       <a>Introduction Questions</a> 
      </div> 
      <form *ngIf="isForm == true;" [formGroup]="myForm"> 
      <div class="intro-answers-container"> 

       <div *ngFor="let question of myForm.controls.questions.controls; let i=index" class="panel panel-default"> 
        <answer [group]="myForm.controls.questions[i]"></answer> 
       </div> 


      </div>   
      </form> 

      </div> 

      <div *ngIf="!introCompleted && !loading" class="intro-submit"> 
      <button *ngIf="myForm.valid" class="submit-button" (click)="save(myForm.value, true)">Complete Program Introduction</button> 
      <button *ngIf="!myForm.valid" class="submit-button invalid" >Complete Program Introduction</button> 
      </div> 
     </div> 

     </div> 


     </div> 
     <div *ngIf="loading" class="session-container-content"> 
     <img class="loading-ring" src="../assets/img/ring.svg"> 
     </div> 
    </div> 
    </div> 
</div> 

这是自定义的答案组件打字稿

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





} 

最后,这里是自定义组件的HTML

<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> 

回答

0

我想通了这个问题,在ngFor对象,其中一个答复该数组有空白值,因此弄乱了组件。

相关问题