FormGenerator

by der_robert

HTML

<script id="form-config" type="application/json">
{
  "action": "/submit-form",
  "method": "POST",
  "fields": [
    {
      "id": "personal-info",
      "type": "input-group",
      "fields": [
        {
          "id": "full_name",
          "type": "text",
          "label": "Name",
          "placeholder": "Max Mustermann",
          "required": true,
          "validation": "string",
          "layout": "horizontal"
        },
        {
          "id": "user_email",
          "type": "email",
          "label": "E-Mail",
          "placeholder": "[email protected]",
          "required": true,
          "validation": "email",
          "layout": "horizontal"
        }
      ]
    },
    {
      "id": "address_group_1",
      "type": "input-group",
      "fields": [
        {
          "id": "street",
          "type": "text",
          "label": "Straße",
          "placeholder": "Musterstraße",
          "required": true,
          "layout": "vertical"
        },
        {
          "id": "houseNumber",
          "type": "text",
          "label": "Nr.",
          "placeholder": "12a",
          "required": true,
          "layout": "vertical"
        }
      ]
    },
    {
      "id": "address_group_2",
      "type": "input-group",
      "fields": [
        {
          "id": "zip",
          "type": "text",
          "label": "PLZ",
          "placeholder": "12345",
          "required": true,
          "layout": "vertical"
        },
        {
          "id": "city_name",
          "type": "text",
          "label": "Stadt",
          "placeholder": "Berlin",
          "required": true,
          "layout": "vertical"
        }
      ]
    },
    {
      "id": "user_age",
      "type": "number",
      "label": "Alter",
      "required": true,
      "validation": "int",
      "min": 18,
      "max": 99,
      "layout": "horizontal"
    },
    {
      "id": "salary",
      "type": "text",
      "label": "Monatsgehalt (€)",
      "placeholder": "z.B....

CSS

/* Grundlegende Formulargestaltung */
form {
  max-width: 600px;
  margin: 20px auto;
  padding: 20px;
  border-radius: 8px;
  background: #f9f9f9;
  box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
}

/* Gemeinsame Struktur für Form-Felder */
.form-group {
  display: flex;
  align-items: center;
  gap: 15px;
  margin-bottom: 15px;
}

/* Labels mit fester Breite für Einheitlichkeit */
.form-group label {
  font-weight: bold;
  text-align: right;
  flex-basis: 30%; /* Setzt eine Basisbreite für alle Labels */
  min-width: 120px; /* Mindestens 120px, falls kürzere Labels */
  white-space: nowrap; /* Verhindert Umbrüche */
}

/* Eingabefelder */
.form-group input,
.form-group select,
.form-group textarea {
  flex-grow: 1;
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
  font-size: 16px;
}

.form-group textarea {
  height: 100px;
  resize: vertical;
}

/* Fehlerhafte Eingabefelder */
input.error, select.error, textarea.error {
  border-color: red;
  background-color: #ffecec;
}

/* Platzhalter-Bereich für AJAX */
.placeholder {
  border: 1px dashed #999;
  padding: 10px;
  min-height: 50px;
  background: #f5f5f5;
  text-align: center;
  font-size: 14px;
  color: #666;
}

/* Buttons */
button, .button-link {
  background-color: #007bff;
  color: white;
  padding: 10px 15px;
  border: none;
  border-radius: 4px;
  font-size: 16px;
  cursor: pointer;
  transition: background 0.3s;
  text-decoration: none;
  display: inline-block;
}

button:hover, .button-link:hover {
  background-color: #0056b3;
}

button:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}

/* 🔥 Vertikale Layout-Variante */
.vertical {
  flex-direction: column;
  align-items: flex-start;
}

.vertical label {
  text-align: left;
  flex-basis: auto;
  min-width: 100%;
  margin-bottom: 5px;
}

/* Input Group (mehrere Felder in einer Gruppe) */
.input-group {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 6px;
 ...

JavaScript

document.addEventListener("DOMContentLoaded", () => {
  const formElement = document.querySelector("dynamic-form");
  const jsonConfig = document.getElementById("form-config").textContent;
  formElement.setAttribute("data-json", jsonConfig);


class DynamicForm extends HTMLElement {
constructor() {
    super();
    this.formData = [];
  }
connectedCallback() {
    try {
      const jsonString = this.getAttribute("data-json");
      if (jsonString) {
        this.formData = JSON.parse(jsonString);

        if (!this.formData.fields || !Array.isArray(this.formData.fields)) {
          throw new Error("Das JSON enthält kein gültiges 'fields'-Array.");
        }

        this.renderForm();
      } else {
        console.warn("Kein JSON gefunden! Stelle sicher, dass 'data-json' gesetzt ist.");
      }
    } catch (error) {
      console.error("Fehler beim Parsen des JSON:", error);
    }
  }

renderForm() {
  try {
    this.innerHTML = "";

    const form = document.createElement("form");
    form.id = "dynamic-form";
    form.action = this.formData.action || "#";
    form.method = this.formData.method || "POST";

    console.log("Starte Rendering des Formulars...");

    this.formData.fields.forEach((field, index) => {
      try {
        if (!field.id || !field.type) {
          throw new Error(`Fehlende 'id' oder 'type' in Feld ${index + 1}: ${JSON.stringify(field)}`);
        }

        console.log(`Rendere Feld ${index + 1}:`, field.id);

        // 🔥 Jedes Element direkt an der entsprechenden Position einfügen
        const fieldElement = this.renderField(field);
        if (fieldElement) {
          form.appendChild(fieldElement);
        } else {
          console.warn(`Feld '${field.id}' konnte nicht gerendert werden.`);
        }
      } catch (fieldError) {
        console.error("Fehler beim Rendern eines Formularfeldes:", fieldError);
      }
    });

    // 🔥 Falls ein Submit-Button in der config existiert, hinzufügen
    const submitButtonConfig =...