2017-10-05 1 views
0

Ich versuche eine dynamische Form in Angular Universal zu erstellen. Das Formular ist so eingerichtet, dass bestimmte Fragen obligatorisch sind und andere nicht, je nachdem, wie das Formular vom Ersteller entworfen wurde. Wenn das Formular für den Benutzer ausgefüllt wurde, funktionierte es ohne Angular Universal (JiT Compiler, gegen AoT Compiler) völlig einwandfrei.Angular Universal: "Kann die Eigenschaft '_updateTreeValidity' von undefined nicht lesen"

Das Formular enthält eine benutzerdefinierte Komponente, die in jede Formularfrage eingefügt wird und es dem Benutzer ermöglicht, seine Antwort in die zu übergebende Komponente einzugeben.

Die Anwendung kompiliert in Ordnung, aber wenn diese Komponente geladen ist, habe ich viele Fehler erhalten:

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.

Dies ist das Typoskript für die Form ist:

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

} 

Dies ist der html für das Formular:

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

Dies ist die Komponente Typoskript

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





} 

Schließlich ist hier die benutzerdefinierte Komponente 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> 

Antwort

0

ich das Problem herausgefunden, eine der Antworten für die ngFor Objekte individuelle Antwort ist in Das Array hatte leere Werte und verwirrte daher die Komponenten.

Verwandte Themen