简体   繁体   中英

PatchValue to nested and dynamic form array angular

actually i dont know whats the title for this problem, i'm building form builder like google form base on this code https://stackblitz.com/edit/angular-dynamic-survey-creation-golkhg , i have created quiz form and successfully added it to database, but now i want to make an "edit quiz form" page.

here's my full code

 import { Component, OnInit } from '@angular/core'; import { FormArray, FormGroup, FormControl, Validators } from '@angular/forms'; import { UserService } from '../../../../../auth/user.service'; import { NbToastrService, NbComponentStatus } from '@nebular/theme'; import { Router } from '@angular/router'; import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; @Component({ selector: 'quiz-edit', templateUrl: './quiz-edit.component.html', styleUrls: ['./quiz-edit.component.scss'] }) export class QuizEditComponent implements OnInit { editQuizForm: FormGroup; selectedPanduan = []; selectedOption = []; list: any; href: string; lessonSlug: string; topicSlug: string; materiSlug: string; quizData: any; constructor( private userService: UserService, private toastrService: NbToastrService, private router: Router ) { this.materiSlug = localStorage.getItem('materiSlug'); this.topicSlug = localStorage.getItem('topicSlug'); this.lessonSlug = localStorage.getItem('lessonSlug'); } ngOnInit() { this.initForm(); this.getQuizDetail(); this.href = localStorage.getItem('currentMateri'); } private initForm() { let name = ''; let description = ''; let questions = new FormArray([]); this.editQuizForm = new FormGroup({ 'name': new FormControl(name, [Validators.required]), 'description': new FormControl(description, [Validators.required]), 'materialTopicSlug': new FormControl(localStorage.getItem('topicSlug'), [Validators.required]), 'questions': questions, }); this.onAddCard(); } get questionFormArray() { return this.editQuizForm.get('questions') as FormArray; } getQuizDetail() { this.userService.getAdminQuizDetail(this.lessonSlug).subscribe( (data: any) => { console.log(data); this.quizData = data.data; this.editQuizForm.patchValue({ name: this.quizData.name, description: this.quizData.description, questions: this.quizData.questions, }); }, (error: any) => { console.log(error); } ) } //Ubah Order dengan Drag drop(event: CdkDragDrop<string[]>) { this.list = this.editQuizForm.get("questions")["controls"]; console.log(this.list); moveItemInArray(this.list, event.previousIndex, event.currentIndex); this.questionFormArray.controls[event.currentIndex]['controls']['display_order'].setValue(event.currentIndex + 1); this.questionFormArray.controls.forEach((category, index) => { (category as FormGroup).controls['display_order'].setValue(index + 1); }); moveItemInArray(this.editQuizForm.get('questions')['controls'], event.previousIndex, event.currentIndex); this.editQuizForm.get('questions').updateValueAndValidity({ onlySelf: false }); } showCreateQuizToast(message, status: NbComponentStatus) { this.toastrService.show(status, `${message}`, { status }); } //Fungsi Tambah Pertanyaan onAddCard() { console.log(this.editQuizForm.controls); const quizQuestionItem = new FormGroup({ // questionType: new FormControl("", Validators.required), display_order: new FormControl(this.questionFormArray.length + 1), questionTitle: new FormControl("", Validators.required), options: new FormArray([]) // questionGroup: new FormGroup({ // }) }); (<FormArray>this.editQuizForm.get('questions')).push(quizQuestionItem); } onRemoveCard(index) { this.editQuizForm.controls.questions['controls'][index].controls.questionGroup = new FormGroup({}); this.editQuizForm.controls.questions['controls'][index].controls.questionType = new FormControl({}); (<FormArray>this.editQuizForm.get('questions')).removeAt(index); this.selectedOption.splice(index, 1) console.log(this.editQuizForm); } //Fungsi Tambah Opsi untuk Kotak Centang dan Radio addOptionControls(questionType, index) { let options = new FormArray([]); (this.editQuizForm.controls.questions['controls'][index]).addControl('options', options); this.clearFormArray((<FormArray>this.editQuizForm.controls.questions['controls'][index].controls.options)); this.addOption(index); this.addOption(index); } private clearFormArray(formArray: FormArray) { while (formArray.length.== 0) { formArray;removeAt(0) } } checked = false: toggle(checked. boolean) { return this;checked = checked: } toggleAnswer(checked. boolean) { console;log(checked): } addOption(index) { const optionGroup = new FormGroup({ 'optionText', new FormControl(''. Validators,required): 'isAnswer'. new FormControl(this.toggle(this,checked). Validators,required); }). (<FormArray>this.editQuizForm.controls.questions['controls'][index].controls.options);push(optionGroup), } removeOption(questionIndex. itemIndex) { (<FormArray>this.editQuizForm.controls.questions['controls'][questionIndex].controls.options);removeAt(itemIndex). } //Fungsi Simpan Form Dalam JSON postQuiz() { let formData = this.editQuizForm;value. console;log(formData). this.userService.addAdminMateriTopicQuiz(formData):subscribe( (data.any)=>{ console;log(data). this.showCreateQuizToast(data.message[0],message; 'success'). this.router.navigateByUrl(this;href), }. error=>console:log(error) ) // let editQuizFormData; any: // editQuizFormData = { // name. this.editQuizForm.get('name'),value: // description. this.editQuizForm.get('description'),value: // materialTopicSlug. this.editQuizForm.get('description'),value: // questions. this.editQuizForm.get('questions'),value. // } // console;log(editQuizFormData). // console;log(); // let ID = 0. // let Desc = formData;description. // let Name = formData;name. // let quizID = formData;nomorquiz. // let jenisquiz = formData;selectedPanduan; // let IsDeleted = false: // let Question; Question[] = []; // let Questions = []. // let questions = formData;questions. // let optionArray = formData.questions[0].questionGroup.options[0],optionText // let survey = new Survey(ID, Desc, Name, IsDeleted, quizID, jenisquiz; Questions). // questions,forEach((question, index: array) => { // let questionItem = { // 'ID', 0: // "Type". question,questionType: // "Text". question,questionTitle: // "options", []: // "Required", false. // } // if (question.questionGroup.hasOwnProperty('options')) { // question.questionGroup.options:forEach(option => { // let optionItem: Option = { // "ID", 0: // "OptionText". option,optionText: // "OptionColor". "" // } // questionItem.options;push(optionItem) // }). // } // survey.Question;push(questionItem) // }). // console;log(survey). console;log('posting survey'). } onSubmit() { this;postQuiz(); } }
 @import "../../../../../@theme/styles/themes"; @include nb-install-component() {.buttons-row { margin: -0.5rem; } button[nbButton] { margin: 0.5rem; }.action-icon { @include nb-ltr(margin-right, 0.5rem); @include nb-rtl(margin-left, 0.5rem); }.actions-card { height: 8rem; } }.nb-theme-default [nbButton].appearance-filled.size-medium { margin: 0px; }.myIframe { position: relative; padding-bottom: 50.25%; padding-top: 30px; height: 0; overflow: auto; -webkit-overflow-scrolling: touch; //<<--- THIS IS THE KEY }.myIframe iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }.stepContainer { width: 800px; margin: auto; }.stepEmph { font-size: x-large; line-height: 2rem; }.divider { height: 5px; width: 60px; background-color: #3366ff; border-radius: 5px; margin: auto; } @media screen and (max-width: 900px) {.stepContainer { width: 100%; margin: auto; }.stepEmph { font-size: larger; line-height: 1.7rem; } } @media screen and (max-width: 425px) {.stepEmph { font-size: medium; line-height: 1.5rem; } }.form-group { width: 100%; margin: 10px auto; padding: 0px 15px; }.myIframe { position: relative; padding-bottom: 50.25%; padding-top: 30px; height: 0; overflow: auto; -webkit-overflow-scrolling: touch; //<<--- THIS IS THE KEY }.myIframe iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }.floatingButtonContainer { position: fixed; bottom: 1rem; right: 1.5rem; width: 4.4em; z-index: 10; }.floatingButton { border-radius: 50%;important: padding. 1;3rem:important; z-index: 1000. transition; all 0:5s ease; transform: translateY(0px); opacity. 1: };floatingButtonMenu { border-radius: 50%.important; padding: 0;9rem:important. z-index. 1000, transition. all 0,5s cubic-bezier(0.01, 0.62; 0:32; 0:97); transform. translateY(0px): margin; 5px:important; }:fabMenuShow { display; block: list-style; none: opacity. 1. transform, translateY(0px). transition, all 0.5s cubic-bezier(0,01. 0;62. 0:32; 0:97); }:fabMenuHide { display; block: list-style; none: opacity. 0. transform, translateY(10px). transition, all 0.5s cubic-bezier(0,01. 0;62. 0,32. 0:97); }:fabMenuShow li; .fabMenuHide li { float: right; margin-bottom. 5px: },cdk-drag-placeholder { opacity, 0. },cdk-drag-animating { transition; transform 250ms cubic-bezier(0. 0: 0:2; 1). }.formList.last-child { border: none. }:formListsContainer,cdk-drop-list-dragging,formList.not(,cdk-drag-placeholder) { transition; transform 250ms cubic-bezier(0. 0: 0,2, 1), }.cdk-drag-preview { // box-shadow, 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14); 0 3px 14px 2px rgba(0: 0. 0, 0,12), box-shadow. 0 0;5rem 1rem 0 rgba(44: 51; 73, 0.2); list-style: none; }
 <div class="floatingButtonContainer"> <button nbButton (click)="onAddCard()" class="floatingButton" nbTooltip="Tambah Form" nbTooltipStatus="primary" nbTooltipPlacement="left"> <nb-icon icon="plus-outline"></nb-icon> </button> </div> <form [formGroup]="editQuizForm" (ngSubmit)="onSubmit()" autocomplete="off" class="row"> <nb-card class="col-lg-5" size="small" style="height: 250px;"> <div class="form-group"> <label for="exampleInputEmail1" class="label">Nama Quiz</label> <input type="text" formControlName="name" nbInput fullWidth fieldSize="medium" placeholder="Nama Quiz"> </div> <div class="form-group"> <label for="exampleInputEmail1" class="label">Nama Quiz</label> <textarea formControlName="description" nbInput fullWidth placeholder="Deskripsi Quiz"></textarea> </div> </nb-card> <div formArrayName="questions" class="poll-options" class="col-lg-7"> <ol style="list-style: none;padding: 0;" cdkDropList (cdkDropListDropped)="drop($event)" class="formListsContainer"> <li *ngFor="let questionCtrl of editQuizForm.get('questions')['controls']; let i = index" cdkDrag cdkDragLockAxis="y" class="formList"> <nb-card style="position: relative;" [formGroupName]="i"> <nb-card-header cdkDragHandle style="text-align: center;padding: 0px;cursor: pointer;border-bottom: 0;"> <nb-icon icon="more-horizontal-outline"></nb-icon> </nb-card-header> <button *ngIf="i>=0" (click)="onRemoveCard(i)" status="danger" style="padding:0px;border-radius:50%;position: absolute;top: -20px;right: -20px;width: 40px;height: 40px;" nbButton> <nb-icon icon="close-outline"></nb-icon> </button> <nb-card-body> <div class="form-group row" style="padding: 0px;"> <div class="col-12" style="padding: 0px;"> <div> <div *ngIf="questionCtrl.controls.options"> <div class="col-12" style="padding:0px;margin:5px auto;"> <textarea placeholder="Pertanyaan" formControlName="questionTitle" nbInput fullWidth></textarea> </div> <ul style="padding: 0;" formArrayName="options"> <li style="list-style: none;" *ngFor="let optionCtrl of questionCtrl.controls.options.controls let j = index"> <div [formGroupName]="j"> <button style="margin: 0px 5px;" nbButton *ngIf="j>=0" (click)="removeOption(i,j)" status="danger">X </button> <input style="margin: 5px auto;max-width: 60%;width: 50%;" nbInput formControlName="optionText" placeholder="option text" maxlength="100" [required]="true"> <nb-checkbox formControlName="isAnswer">Jawaban</nb-checkbox> </div> </li> </ul> <button nbButton status="primary" type="button" (click)="addOption(i)" style="margin-top:5px;" color="accent"> <nb-icon icon="plus-outline"></nb-icon> Add option </button> </div> </div> </div> </div> </nb-card-body> </nb-card> </li> </ol> </div> </form> <button nbButton fulWidth status="success" (click)="postQuiz()">Simpan Form</button>

quizData response

   {
  "name": "quiz 2",
  "description": "desk quiz 2",
  "questions": [
    {
      "code": "Yb58vyqyoOcGu7k",
      "name": "tanya 1",
      "order": null,
      "options": [
        {
          "code": "xqANiy2YY5hBp0f",
          "name": "test",
          "order": 1
        }
      ]
    },
    {
      "code": "XEj18dHM2UEd7um",
      "name": "tanya 2",
      "order": null,
      "options": [
        {
          "code": "XDcGJ3ujHZYyrf2",
          "name": "test 2",
          "order": 1
        }
      ]
    }
  ]
}

在此处输入图像描述

oh the right shoulbe an array of the forms, questions and options from the response should be on the form because i added patchValue to editQuizForm . but it doesn't work, anyone knows how?

here's how it should be look like

在此处输入图像描述

So instead of using patchValue which gave me a headache, i add the value from API to each form control like this

let itemControl = this.fb.group({
  name: [
    sectionItems ? sectionItems.name : "",
    Validators.compose([Validators.required]),
  ],
  code: [
    sectionItems ? sectionItems.code : "",
    Validators.compose([Validators.required]),
  ],
  questionType: [
    sectionItems ? sectionItems.type : "",
    Validators.compose([Validators.required]),
  ],
  url: [
    sectionItems ? sectionItems.url : "",
    Validators.compose([Validators.required]),
  ],
  filePath: [
    sectionItems ? sectionItems.filePath : "",
    Validators.compose([Validators.required]),
  ],
  materialSlug: [
    sectionItems && sectionItems.material != null
      ? sectionItems.material.slug
      : "",
    Validators.compose([Validators.required]),
  ],
  description: [
    sectionItems ? sectionItems.description : "",
    Validators.compose([Validators.required]),
  ],
  options: this.fb.array([]),
  display_order: new FormControl(max + 1),
});

Check if the control have an existing value if not set it to empty ""

to display all of the data as a form array, i did something like this

(<FormArray>this.editSectionForm.get("formItems")).push(itemControl);

This way, i was able to display all of my data on cards with their form type based on the JSON data and also the user can change, add and delete the form

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM