#angular #angular-reactive-forms #angular-forms
#angular #угловые-реактивные-формы #angular-формы
Вопрос:
на самом деле я не знаю, как называется эта проблема, я создаю конструктор форм, подобный Google form, на основе этого кодаhttps://stackblitz.com/edit/angular-dynamic-survey-creation-golkhg , я создал форму викторины и успешно добавил ее в базу данных, но теперь я хочу создать страницу «редактировать форму викторины».
вот мой полный код
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
{
"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
}
]
}
]
}
о, справа должен быть массив форм, questions
и options
из ответа должно быть в форме, потому что я добавил patchValue
в editQuizForm
. но это не работает, кто-нибудь знает как?
вот как это должно выглядеть
Комментарии:
1. Было бы лучше, если бы вы включили свой пример в stackblitz
2. да, но я не могу воспроизвести это с помощью nebular в stackblitz, я не знаю почему, поэтому я просто привожу вам пример stacblitz, надеюсь, что кто-нибудь сможет понять только с этим
3. на самом деле это почти то же самое
4. вот простое создание и редактирование stackblitz.com/edit /…
5. @noval — вы смогли найти решение? Если да, можете ли вы опубликовать это в качестве ответа здесь
Ответ №1:
Поэтому вместо использования patchValue
, которое доставляло мне головную боль, я добавляю значение из API к каждому элементу управления формой следующим образом
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 amp;amp; 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),
});
Проверьте, есть ли у элемента управления существующее значение, если нет, установите для него значение empty ""
чтобы отобразить все данные в виде массива форм, я сделал что-то вроде этого
(<FormArray>this.editSectionForm.get("formItems")).push(itemControl);
Таким образом, я смог отобразить все мои данные на карточках с их типом формы на основе данных JSON, а также пользователь может изменять, добавлять и удалять форму