4
votes

I'm working with Angular, and I need some advice. I tried to create a container, where it's possible to drop boxes with names like dropdown or calendar. These boxes come with attributes, like a pink calendar or a dropdown containing 3 items.

What I want is, for these names with attributes, to be saved in my database. I have created a REST API, but I don't really know how to save such things. I tried to drop these elements into an input, so I can save them with formControlName, but it's not possible to drop elements into a input. I also tried using a ngSwitch, where every ngSwitchCase has its own formControlName, but then I get the error:

Cannot find control with path: 'forms -> 0 -> Textbox.0'

formadd.component.html

div class="add">
  <form [formGroup]="paginaForm" (submit)="onFormSubmit()">
    <div formArrayName="forms">
      <div class="drag" *ngFor="let form of forms; let i = index;" [formGroupName]="i">
        <mat-toolbar class="toolbar" color="warn">
          <div class="title">
            <input class="form_name" placeholder="Formulier Naam" type="text" formControlName="form_name" #form_name />
          </div>
          <div
            *ngIf="paginaForm.controls['form_name']?.invalid && (paginaForm.controls['form_name'].dirty || paginaForm.controls['form_name'].touched)"
            class="alert alert-danger">
            <div *ngIf="paginaForm.controls['form_name']?.errors.required">
              Formuliernaam is required.
            </div>
          </div>
        </mat-toolbar>
        <fieldset class="element">
          <legend class="voeg-element" placeholder="voeg element toe" cdkDropList
          #doneList="cdkDropList"
          [cdkDropListData]="done"
          (cdkDropListDropped)="drop($event)" >
          <div [ngSwitch]="item" class="cdkdrag" *ngFor="let item of done; let i = index" cdkDrag>
            <div *ngSwitchCase="'Categorie'">{{item}}</div>
            <div *ngSwitchCase="'Textbox'">
              <input type="text" [formControlName]="item + '.' + i" #element/> 
            </div>
            <div *ngSwitchCase="'Textarea'">
              <textarea kendoTextArea></textarea>
            </div>
            <div *ngSwitchCase="'Date'">
                <div class="example-wrapper">
                    <p>Selecteer een datum:</p>
                    <kendo-dateinput
                [(value)]="value"
            ></kendo-dateinput>
                </div>
            </div>
            <div *ngSwitchCase="'Email'">{{item}}</div>
            <div *ngSwitchCase="'Integer'">{{item}}</div>
            <div *ngSwitchCase="'Boolean'">{{item}}</div>
            <div *ngSwitchCase="'Checkbox'">{{item}}</div>
            <div *ngSwitchCase="'Dropdown'">{{item}}</div>
            <div *ngSwitchCase="'Label'">{{item}}</div>
            <div *ngSwitchCase="'Locatie'">{{item}}</div>
            <div *ngSwitchCase="'Subject'">{{item}}</div>
            <div *ngSwitchCase="'Document'">{{item}}</div>
            <div *ngSwitchDefault>{{item}}</div>
            </div>
        </legend>
        <div
          *ngIf="paginaForm.controls['element']?.invalid && (paginaForm.controls['element'].dirty || paginaForm.controls['element'].touched)"
          class="alert alert-danger">
          <div *ngIf="paginaForm.controls['element']?.errors.required">
            Element is required.
          </div>
        </div>
        <div class="verwijder">
          <button (click)="removePagina(i)">Verwijder Pagina</button>

        </div>
        <div class="opslaan">
          <button (click)="addFolders(form_name.value, element.value)"
            [disabled]="paginaForm.pristine || paginaForm?.invalid">Opslaan Pagina</button>

        </div>
      </fieldset>
      </div>
    </div>
    <div class="toevoegen">
      <button type="button" (click)="addPagina()">
        Pagina toevoegen
      </button>
    </div>
  </form>
</div>

formadd.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, Validators, FormBuilder, FormArray } from '@angular/forms';
import { FoldersService } from '../folders.service';
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';

@Component({
  selector: 'app-formadd',
  templateUrl: './formadd.component.html',
  styleUrls: ['./formadd.component.css']
})
export class FormaddComponent implements OnInit {
  paginaForm: FormGroup;

  constructor(private fb: FormBuilder, private bs: FoldersService) {
    this.createForm();
  }


  createForm() {
    this.paginaForm = this.fb.group({
      form_name: ['', Validators.required],
      element: ['', Validators.required],
    });
  }

  addFolders(form_name, element) {
    console.log(this.paginaForm.value.forms[0]);
    this.bs.addFolders(form_name, element);
  }

  ngOnInit() {
    this.paginaForm = this.fb.group({
      forms: this.fb.array([])
    });
  }

  onFormSubmit() {
    alert(JSON.stringify(this.paginaForm.value));
  }

  addPagina() {
    (<FormArray>this.paginaForm.get('forms')).push(this.fb.group({
      form_name: [],
      element: [],
    }));
  }

  get forms() {
    return (<FormArray>this.paginaForm.get('forms')).controls;
  }

  removePagina(i: number) {
    (<FormArray>this.paginaForm.get('forms')).removeAt(i);
  }

  done = [];
  drop(event: CdkDragDrop<string[]>) {
    console.log(event);
    this.done.push(event.item.data);

or

Cannot read property 'value' of undefined

When I change the statement

<div [ngSwitch]="item" class="cdkdrag" *ngFor="let item of done; let i = index" cdkDrag>
            <div *ngSwitchCase="'Categorie'">{{item}}</div>
            <div *ngSwitchCase="'Textbox'">
              <input type="text" [formControlName]="item + '.' + i" #element/> 
            </div>

to

<div [ngSwitch]="item" class="cdkdrag" *ngFor="let item of done; let i = index" cdkDrag>
            <div *ngSwitchCase="'Categorie'">{{item}}</div>
            <div *ngSwitchCase="'Textbox'">
              <input type="text" [formControlName]="element" #element/> 
            </div>

Does anyone know a better way to figure out this super task?

1
Please show us what you've tried so far. Without seeing your code we can not check out whats wrong.J. Sadi
@J.Sadi yes, I'm sorry.Liza Darwesh
If I understand well you want to save the entire element and not just the innerText? Why not use document.getElementByID() and then save it as a string in your database?mikegross
Are you taking form control input from the user into a text box and using it to show bellow the form dynamically. Do you want like this functionalityHitech Hitesh
@LizaDarwesh, Inside your drop method you are having a console.log, can you please share what you are getting as an event?Arpit Kumar

1 Answers

1
votes

If you need your entire HTML element to be saved to the database, you can try to set the Content-Type of the httpClient.post() to text/plain. In this manner, you can be able to send the exact element with the attributes.

<form id="htmlContainer" [formGroup]="paginaForm" (submit)="onFormSubmit()">
    <!-- form data -->
</form>

Post your entire form element or whatever element you need by accessing it with the id property using document.getElementById('id_of_element')

ngOnInit() {
    this.body = document.getElementById('htmlContainer');
}

onFormSubmit() {
    const headers = new HttpHeaders().set('Content-Type', 'text/plain; charset=utf-8');
    return this.http.post('your_url', this.body, { headers, responseType: 'text' })
      .subscribe(data => console.log(data));
}

Then to retrieve the data in the text format, set the responseType to text.

return this.http.get('your_url', {responseType: 'text'})
    .subscribe(data => console.log(data));