UNPKG

@rangertechnologies/ngnxt

Version:

This library was used for creating dymanic UI based on the input JSON/data

448 lines 186 kB
// AP 22JAN25 - form preview and All form elements import { Component, EventEmitter, Input, Output, } from "@angular/core"; import { VERSION } from "../../../../environments/version"; import { QuestionbookComponent } from "../../questionbook/questionbook.component"; import { CommonModule } from "@angular/common"; import { FormsModule } from "@angular/forms"; import { BookletComponent } from "../../booklet/booklet.component"; import { NxtDatatable } from "../../../components/datatable/datatable.component"; import * as i0 from "@angular/core"; import * as i1 from "../../../services/form-builder.service"; import * as i2 from "@angular/common"; import * as i3 from "@angular/forms"; export class ElementComponent { formBuilderService; bookletJSON; bookletId; templateMode = new EventEmitter(); field; formElements = []; elements = []; bookId; sections = { basic: true, // Basic Elements open by default advanced: true, // Advanced Elements closed by default }; basicElements = []; advancedElements = []; //elementDisabledArray: any; version = VERSION.version; //SKS10MAR25 get version from environment/version.ts book; selectedElement = null; isSelectTablePopup = false; currentType; addTable = true; dots = Array(6); draggedIndex = null; templateSelected = false; constructor(formBuilderService) { this.formBuilderService = formBuilderService; } // AP-06MAR25 Basic elements updated (RichTextArea, Date added) ngOnInit() { this.basicElements = [ { type: "Text", img: "Text", label: "Text" }, { type: "Number", img: "Number", label: "Number" }, { type: "Label", img: "Label", label: "Label" }, { type: "Email", img: "Email", label: "Email" }, { type: "Date", img: "Date", label: "Date" }, { type: "Time", img: "Time", label: "Time" }, { type: "DateTime", img: "DateTime", label: "DateTime" }, { type: "Calendar", img: "Calendar", label: "Calendar" }, { type: "File", img: "File", label: "Files" }, { type: "Image", img: "Image", label: "Image" }, { type: "Checkbox", img: "CheckBox", label: "Checkbox" }, { type: "Radio", img: "Radio", label: "Radio" }, { type: "Dropdown", img: "Drop", label: "Dropdown" }, { type: "TextArea", img: "TextArea", label: "Text Area" }, { type: "RichTextArea", img: "RichText", label: "Rich Text" }, ]; this.advancedElements = [ { type: "Icon", img: "Icon", label: "Icon" }, //MSM10JUL25 icon selector component { type: "Line", img: "line", label: "Line" }, { type: "Space", img: "space", label: "Space" }, { type: "Boolean", img: "Boolean", label: "Boolean" }, { type: "Book", img: "Search", label: "Book" }, { type: "List", img: "Search", label: "List" }, { type: "Table", img: "Table", label: "Table" }, { type: "Button", img: "Button", label: "Button" }, ]; // this.elementDisabledArray = { // Table: [ // 'Book', 'Calendar',"Boolean", 'List', 'Table', 'Checkbox', 'Radio', // 'Dropdown', 'TextArea', 'RichTextArea', 'Number', 'Label', 'Image', // 'Email', 'Date', 'Time', 'DateTime', 'Line', 'Space' // ] // }; this.formBuilderService.formElements$.subscribe((elements) => { setTimeout(() => { this.formElements = elements.map((field) => ({ ...field })); }, 0); }); if (this.bookletJSON && this.bookletJSON !== "") { this.initializeForm(); } else { this.formBuilderService.newBook(); } // AP-12MAR25 - Added to handle bookletId if (this.bookletId) { localStorage.setItem("unique_id", this.bookletId); } this.book = this.formBuilderService.getBook(); this.formBuilderService.selectedElement$.subscribe((index) => { const elements = this.formBuilderService.getElements(); if (index >= 0) { this.selectedElement = elements[index]; } // SKS19MAR25 for fieldMeta checking if (this.selectedElement?.type === "Table") { this.selectedElement["fieldsMeta"] = typeof this.selectedElement.fieldsMeta === "string" ? this.selectedElement.fieldsMeta : JSON.stringify(this.selectedElement["fieldsMeta"] || []); } // this.formElements = [...elements] }); this.formBuilderService.addElementWithId(); } // Add these methods toggleSection(section) { this.sections[section] = !this.sections[section]; } isSectionOpen(section) { return this.sections[section]; } // AP - 26FEB25 - Added ngOnChanges to handle changes in bookletJSON ngOnChanges(changes) { if (changes["bookletJSON"] && changes["bookletJSON"].currentValue) { if (this.bookletJSON && this.bookletJSON !== "") { // AP-28MAY25 - Check and transform `action` if it's in Existing format if (this.bookletJSON.questionbook && this.bookletJSON.questionbook.action && typeof this.bookletJSON.questionbook.action === "string") { try { const parsedActions = JSON.parse(this.bookletJSON.questionbook.action); // AP-28MAY25 Assign specific positionPercent based on action name const newActions = parsedActions.map((item, index) => { const positionPercent = item.name === "Cancel" ? 3 : item.name === "Save" ? 14 : 10 + index * 10; return { ...item, positionPercent: positionPercent, width: 100, textColor: "#ffffff", borderRadius: 6, id: index + 1, }; }); // AP-28MAY25 Replace the old action string with the newly formatted array this.bookletJSON.questionbook.action = newActions; } catch (e) { console.error("Error parsing action JSON string:", e); } } this.initializeForm(); } else { this.formBuilderService.newBook(); } } } // AP-08APR25 Template is selected, update form elements and emit template mode onTemplateSelected(event) { this.formBuilderService.clearElements(); event.elements.forEach((el) => this.formBuilderService.addElement(el)); // Emit template mode to parent this.templateMode.emit(true); } initializeForm() { if (!this.bookletJSON || !this.bookletJSON.bookQuestionsMap) { console.warn("Invalid bookletJSON structure"); return; } this.formElements = []; this.formBuilderService.clearElements(); this.formBuilderService.intializeBook(this.bookletJSON); const bookQuestionsMap = this.bookletJSON.bookQuestionsMap; const bookQuestionsMapKeys = Object.keys(bookQuestionsMap); if (bookQuestionsMapKeys.length === 0) return; for (const key of bookQuestionsMapKeys) { const subQuestions = bookQuestionsMap[key]?.subQuestions; if (Array.isArray(subQuestions)) { subQuestions.forEach((subQuestion) => { // AP-04APR24 If subQuestion.style exists as a string and is empty, replace it with a default style object if (typeof subQuestion.style === "string" && subQuestion.style.trim() === "") { subQuestion.style = { labelClass: null, labelStyle: null, labelValueStyle: null, inputClass: null, inputStyle: null, showLabel: true, bookStyle: null, direction: "ltr", questionStyle: null, }; } }); } } this.formElements = this.formBuilderService.getElements(); } // Add this method to handle element selection selectElement(index) { this.selectedFieldIndex = index; // element is selected this.formBuilderService.setSelectedElement(index); this.book = this.formBuilderService.getBook(); } selectedFieldIndex = null; // element is cleared selectHeading(event) { this.formBuilderService.selectHeading(event); //AP-10MAR25 Updates the selected heading in the service this.book = this.formBuilderService.getBook(); //AP-10MAR25 Retrieves the updated book/form data } // AP-17APR25 generateUiId generateUiId() { return this.formBuilderService.addElementWithId(); } addElement(type) { const unique_id = this.generateUiId(); this.currentType = type; if (this.selectedElement?.type === "Table" && this.addTable) { this.isSelectTablePopup = true; } else { const newElement = { action: null, id: unique_id, type, name: null, questionText: null, question: null, helpText: null, errorMessage: null, isReadOnly: false, isHidden: false, required: false, referenceField: null, additionalRichContent: null, groupName: null, isDateBackward: false, title: null, subTitle: null, size: 12, isDateForward: false, isOptional: false, isTitle: false, nextQuestion: null, allowedFileExtensions: null, questionNumber: this.formBuilderService.getElements().length + 1, order: this.formElements.length + 1, questionBookId: this.bookletId, fieldsMeta: [], trackingId: null, recordId: null, qbReference: null, qbReferenceQuestions: null, primaryKey: false, style: { labelClass: null, labelStyle: null, labelValueStyle: null, inputClass: null, inputStyle: null, showLabel: true, bookStyle: null, direction: "ltr", questionStyle: null, }, subText: this.getDefaultSubText(), imageData: null, boolean: false, options: type === "Dropdown" || type === "Radio" || type === "Checkbox" ? [] : null, imageSize: type === "Image" ? { width: 150, height: 150 } : null, tableConfig: type === "Table" ? { isNosIndicator: true, addInlineRecord: true, isPagination: true, actionButton: true, isDeleteRow: true, isEditRow: true, searchBar: true, isButtons: true, itemsPerPage: 10, } : null, }; this.formBuilderService.addElement(newElement); this.formElements = this.formBuilderService.getElements(); // SKS19MAR25 fieldsmeta check this.formElements = this.updateTableFieldsMeta(this.formElements); this.addTable = true; } } // AP-07MAY25 - Added to handle default subText getDefaultSubText() { const defaultData = { endpoint: null, variable: null, field: null, defaultField: null, sourceQuestionId: null, valueField: null, labelField: null, isDependentField: false, dependentValue: null, queryField: null, queryValue: null, queryValueReference: null, uniqueKey: null, }; const isEmpty = Object.values(defaultData).every((val) => val === null || val === false); return isEmpty ? null : defaultData; } // Remove an element by index removeElement(field, index) { this.formBuilderService.removeElementComponent(field.id); this.formElements = this.formBuilderService.getElements(); // SKS19MAR25 fieldsmeta check this.formElements = this.updateTableFieldsMeta(this.formElements); } onDragStart(event, index) { this.draggedIndex = index; event.dataTransfer?.setData("text/plain", index.toString()); } // Allow dropping by preventing default onDragOver(event, index) { event.preventDefault(); } // Handle drop event onDrop(event, dropIndex) { event.preventDefault(); if (this.draggedIndex === null || this.draggedIndex === dropIndex) return; const draggedItem = this.formElements[this.draggedIndex]; // Remove dragged item from old position and insert it in new position this.formElements.splice(this.draggedIndex, 1); this.formElements.splice(dropIndex, 0, draggedItem); //AP-28MAR25 Update questionNumber dynamically based on new order this.formElements.forEach((element, index) => { element.questionNumber = index + 1; }); // Reset dragged index this.draggedIndex = null; // Notify service about the update this.formBuilderService.updateElementsOrder(this.formElements); } toggleBoolean(field) { field.boolean = !field.boolean; } getBaseStyles(field, includeBorderStyle = false) { const styles = { "font-family": field?.font || "Helvetica Neue", "font-weight": field?.fontWeight || "400", "font-size": field?.fontSize || "14px", "width": field?.size ? `${(field.size / 12) * 100}%` : "100%", "text-align": field?.textAlign || "left", "border-radius": "5px", "border-width": field?.lineWidth ? `${field.lineWidth}px` : "1px", "color": field?.fontColor || "#000000", "margin-top": field?.paddingTop ? `${field.paddingTop}px` : "0px", "margin-bottom": field?.paddingBottom ? `${field.paddingBottom}px` : "10px", "border-color": field?.color || "#EFF8FF", }; if (includeBorderStyle) { styles["border-style"] = field?.lineStyle?.toLowerCase() || "solid"; } return styles; } getFontStyles(field) { return this.getBaseStyles(field, false); } getLineStyles(field) { return this.getBaseStyles(field, true); } // SKS13MAR25 table popup conformation based element add onClose() { this.isSelectTablePopup = false; this.addTable = false; this.addElement(this.currentType); } // SKS13MAR25 column element add inside a table addOnTable() { this.addTable = true; this.isSelectTablePopup = false; const elements = [...this.formBuilderService.getElements()]; // Find the element and update its columns const index = elements.findIndex((el) => el.id === this.selectedElement.id); const rowNum = this.formElements[index].columns ? this.formElements[index].columns?.length : 0; const unique_id = this.generateUiId(); const tableElement = { label: `HEADER LABEL ${rowNum}`, fieldName: `FIELD NAME${rowNum}`, type: this.currentType, id: unique_id, }; this.formBuilderService.addTableElement(tableElement, this.selectedFieldIndex); this.formElements = this.formBuilderService.getElements(); // SKS19MAR25 fieldsmeta checking this.formElements = this.updateTableFieldsMeta(this.formElements); } updateTableFieldsMeta(elements) { return elements.map((ele) => { if (ele.type === "Table") { ele.fieldsMeta = typeof ele.fieldsMeta === "string" ? ele.fieldsMeta : JSON.stringify(ele.fieldsMeta || []); } return ele; }); } columnSelected(event) { // SKS19MAR25 table column update this.formBuilderService.setSelectedTableElement(this.selectedFieldIndex, event); } removeColumn(event) { this.formBuilderService.removeSelectedTableElement(this.selectedFieldIndex, event); } // SKS25MAR25 image add async fileChangeEvent(index, event) { const file = event.target.files[0]; if (file) { try { const imageData = await this.readFileAsDataURL(file); this.formElements[index].imageData = imageData; this.formElements[index].orgImageData = imageData; // Initialize logo size if not already set if (!this.formElements[index].imageSize) { this.formElements[index].imageSize = { width: 150, height: 150 }; } await this.formBuilderService.elementUpdate(index, this.formElements[index]); } catch (error) { console.error("Error reading file:", error); } } } readFileAsDataURL(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(reader.result); reader.onerror = (error) => reject(error); reader.readAsDataURL(file); }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ElementComponent, deps: [{ token: i1.FormBuilderService }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: ElementComponent, isStandalone: true, selector: "app-element", inputs: { bookletJSON: "bookletJSON", bookletId: "bookletId" }, outputs: { templateMode: "templateMode" }, usesOnChanges: true, ngImport: i0, template: "<!-- AP 22JAN25 - form preview and All form elements -->\n<!-- AP 25FEB25 - All elements update -->\n<div class=\"center-frame\">\n <!-- Form Builder Section All Elements -->\n <div class=\"form-builder\">\n <!-- Basic Elements Toggle -->\n <div class=\"toggle-header\" (click)=\"toggleSection('basic')\">\n <div class=\"head-elements\">Basic Elements</div>\n <img [src]=\"sections.basic ? '../assets/icons/arrow-down.svg' : '../assets/icons/arrow-right.svg'\"\n alt=\"Toggle Arrow\" class=\"arrow-icon\">\n </div>\n\n <div *ngIf=\"sections.basic\">\n <ng-container *ngFor=\"let element of basicElements\">\n <div class=\"element\" (click)=\"addElement(element.type)\">\n <img src=\"../assets/icons/{{ element.img }}.svg\" class=\"element-icon\">\n <div class=\"hover-label\">{{ element.label }}</div>\n <div class=\"drag-dots\">\n <div class=\"dot\" *ngFor=\"let dot of dots\"></div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Advanced Elements Toggle -->\n <div class=\"toggle-header\" (click)=\"toggleSection('advanced')\">\n <div class=\"head-elements\">Advanced Elements</div>\n <img [src]=\"sections.advanced ? '../assets/icons/arrow-down.svg' : '../assets/icons/arrow-right.svg'\"\n alt=\"Toggle Arrow\" class=\"arrow-icon\">\n </div>\n\n <div *ngIf=\"sections.advanced\">\n <ng-container *ngFor=\"let element of advancedElements\">\n <div class=\"element\" (click)=\"addElement(element.type)\">\n <img src=\"../assets/icons/{{ element.img }}.svg\">\n <div class=\"hover-label\">{{ element.label }}</div>\n <div class=\"drag-dots\">\n <div class=\"dot\" *ngFor=\"let dot of dots\"></div>\n </div>\n </div>\n </ng-container>\n </div>\n <!-- AP-08APR25 Add Templates Component -->\n <!-- <app-templates (templateSelected)=\"onTemplateSelected($event)\"></app-templates> -->\n\n <!-- SKS10MAR25 footer version show -->\n <div class=\"sticky-footer-version\">\n {{version}}\n </div>\n </div>\n <!-- AP-27MAR25 Remove CDK drag and drop replace draggable function -->\n <div class=\"form-preview\">\n <!-- AP-10MAR25 Heading -->\n <div class=\"field-container\"\n style=\"width: 100%;background-color: #EFF8FF; border: 1px solid #E6F3FF;display: flex;justify-content: center;margin-bottom:10px\"\n (click)=\"selectHeading('Header')\">\n <div class=\"label-container\" style=\"padding: 10px;\">\n <div *ngIf=\"book?.records\">\n <div *ngIf=\"book.records[0].title == ''\" style=\"color:#3f4a525c\">Heading</div>\n <div *ngIf=\"book.records[0].title !== ''\">{{book.records[0].title}}</div>\n </div>\n </div> \n </div>\n\n <ng-container *ngFor=\"let field of formElements; let i = index\" getProperties().elementProps>\n\n <!-- TextBox -->\n <div *ngIf=\"field.type === 'Text'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel !== false\">{{\n field.questionText ? field.questionText : 'Label' }}</label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n <input type=\"text\" class=\"custom-input\" [placeholder]=\"field.question || 'Enter text'\"\n [readonly]=\"field.isReadOnly\" [class.hidden]=\"field.isHidden\"\n [value]=\"field.defaultValue ? field.defaultValue : '' \" />\n </div>\n </div>\n </div>\n\n <!-- MSM-09JUL25 Icon-selectir Element -->\n <div *ngIf=\"field.type === 'Icon'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isRequired\" *ngIf=\"field.style?.showLabel !== false\">{{\n field.questionText ? field.questionText : 'Choose Icon'\n }}</label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n <div class=\"choose-icon-placeholder\">\n </div>\n </div>\n </div>\n </div>\n\n <!-- AP-19MAR25 Line Element -->\n <div *ngIf=\"field.type === 'Line'\" class=\"line-field\" (click)=\"selectElement(i)\"\n [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\" (dragstart)=\"onDragStart($event, i)\"\n (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"line-element\">\n <div></div>\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n <hr class=\"custom-line\" style=\"display: inline-flex\" [ngStyle]=\"getLineStyles(field)\" />\n </div>\n\n <!--SKS25MAR25 Image Upload Element -->\n <div *ngIf=\"field.type === 'Image'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\" (dragstart)=\"onDragStart($event, i)\"\n (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\" [ngStyle]=\"getFontStyles(field)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel !== false\">{{\n field.questionText ? field.questionText : 'Upload Image' }}</label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n <div>\n <div class=\"logo-container\">\n <!-- Logo preview area -->\n <div class=\"logo-preview\" *ngIf=\"field.imageData\">\n <img [src]=\"field.imageData\" />\n </div>\n\n <!-- Upload button -->\n <div *ngIf=\"!field.imageData\" class=\"logo-upload-placeholder\">\n <label for=\"logo-upload-{{i}}\" class=\"logo-upload-label\">\n <img src=\"../assets/icons/Image.svg\" alt=\"Upload\" />\n <span>Upload Image</span>\n </label>\n <input type=\"file\" id=\"logo-upload-{{i}}\" accept=\"image/*\" (change)=\"fileChangeEvent(i, $event)\"\n style=\"display: none;\" />\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Space Element -->\n <div *ngIf=\"field.type === 'Space'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\" style=\"height:93px\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <label [class.required]=\"field.isOptional\"></label>\n <div class=\"top-right\" style=\"margin: -11px -11px 0 0;\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Boolean Element -->\n <div *ngIf=\"field.type === 'Boolean'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel !== false\">{{ field.questionText\n ? field.questionText : 'Boolean'}}</label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n <input type=\"checkbox\" [checked]=\"field.boolean\" (change)=\"toggleBoolean(field)\"\n [value]=\"field.defaultValue ? field.defaultValue : ''\" />\n </div>\n </div>\n\n <!-- Calendar -->\n <div *ngIf=\"field.type === 'Calendar'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel !== false\">{{\n field.questionText ? field.questionText : 'Select Date'\n }}</label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n\n </div>\n <input type=\"date\" class=\"custom-input\" [readonly]=\"field.isReadOnly\" [class.hidden]=\"field.isHidden\"\n [value]=\"field.defaultValue ? field.defaultValue : ''\" />\n </div>\n </div>\n </div>\n\n <!-- AP -12MAR25 Date -->\n <div *ngIf=\"field.type === 'Date'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel !== false\">{{\n field.questionText ? field.questionText : 'Select Date'\n }}</label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n\n </div>\n <input type=\"date\" class=\"custom-input\" [readonly]=\"field.isReadOnly\" [class.hidden]=\"field.isHidden\"\n [value]=\"field.defaultValue ? field.defaultValue : ''\" />\n </div>\n </div>\n </div>\n\n <!-- AP-21MAR25 Add Time element -->\n <!-- Time Field -->\n <div *ngIf=\"field.type === 'Time'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <label [class.required]=\"field.isOptional\">{{ field.questionText ? field.questionText : 'Time' }}</label>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n <input type=\"time\" class=\"custom-input\" [readonly]=\"field.isReadOnly\" [class.hidden]=\"field.isHidden\"\n [value]=\"field.defaultValue ? field.defaultValue : ''\" />\n </div>\n </div>\n </div>\n\n <!-- AP-28MAR25 DateTime -->\n <div *ngIf=\"field.type === 'DateTime'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel !== false\">{{\n field.questionText ? field.questionText : 'Select Date & Time'\n }}</label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n <input type=\"datetime-local\" class=\"custom-input\" [readonly]=\"field.isReadOnly\"\n [class.hidden]=\"field.isHidden\" />\n </div>\n </div>\n </div>\n\n <!-- Email -->\n <div *ngIf=\"field.type === 'Email'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\"> {{ field.questionText ? field.questionText : 'Label' }}\n </label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n <input type=\"email\" class=\"custom-input\" [placeholder]=\"field.question || 'Enter email'\"\n [readonly]=\"field.isReadOnly\" [class.hidden]=\"field.isHidden\"\n [value]=\"field.defaultValue ? field.defaultValue : ''\" />\n </div>\n </div>\n </div>\n\n <!-- Numbers -->\n <div *ngIf=\"field.type === 'Number'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel !== false\">{{\n field.questionText ? field.questionText : 'Label' }}</label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n <input type=\"number\" class=\"custom-input\" [placeholder]=\"field.question || 'Enter number'\"\n [readonly]=\"field.isReadOnly\" [class.hidden]=\"field.isHidden\"\n [value]=\"field.defaultValue ? field.defaultValue : ''\" />\n </div>\n </div>\n </div>\n\n <!-- TextArea -->\n <div *ngIf=\"field.type === 'TextArea'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel !== false\">{{\n field.questionText ? field.questionText : 'Enter your text'}}</label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n <textarea class=\"custom-textarea\" [placeholder]=\"field.question || 'Enter detailed text here...'\"\n [style.height.px]=\"field.size || 100\" [readonly]=\"field.isReadOnly\" [class.hidden]=\"field.isHidden\"\n [value]=\"field.defaultValue ? field.defaultValue : ''\"></textarea>\n </div>\n </div>\n </div>\n\n <!-- RichText -->\n <div *ngIf=\"field.type === 'RichTextArea'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel !== false\">{{\n field.questionText ? field.questionText : 'Enter your text'}}</label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n <textarea class=\"custom-textarea\" [placeholder]=\"field.question || 'Enter detailed text here...'\"\n [style.height.px]=\"field.size || 100\" [readonly]=\"field.isReadOnly\" [class.hidden]=\"field.isHidden\"\n [value]=\"field.defaultValue ? field.defaultValue : ''\"></textarea>\n </div>\n </div>\n </div>\n\n <!-- Label -->\n <div *ngIf=\"field.type === 'Label'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel !== false\">{{\n field.questionText ? field.questionText : 'Label' }}</label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Book -->\n <div *ngIf=\"field.type === 'Book'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel !== false\">{{\n field.questionText ? field.questionText : 'Label' }}</label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n <lib-booklet [bookletJSON]=\"field.qbReferenceQuestions\"></lib-booklet>\n </div>\n </div>\n </div>\n\n <!-- File -->\n <div *ngIf=\"field.type === 'File'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel !== false\">{{\n field.questionText ? field.questionText : 'Upload File'\n }}</label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n <input type=\"file\" class=\"custom-input\" [readonly]=\"field.isReadOnly\" [class.hidden]=\"field.isHidden\" />\n </div>\n </div>\n </div>\n\n <!-- CheckBox -->\n <div *ngIf=\"field.type === 'Checkbox'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel !== false\">\n {{ field.questionText ? field.questionText : 'Label' }}\n </label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n\n <div class=\"checkbox-options-container\">\n <div *ngFor=\"let option of field.options\" class=\"checkbox-option\">\n <input type=\"checkbox\" [id]=\"option.value + i\" [name]=\"field.id\"\n [value]=\"option.value || field.defaultValue\" class=\"checkbox-input\" [disabled]=\"field.isReadOnly\"\n [class.hidden]=\"field.isHidden\">\n <label [for]=\"option.value + i\" class=\"checkbox-label\">{{ option.value }}</label>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Radio -->\n <div *ngIf=\"field.type === 'Radio'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel !== false\">{{\n field.questionText ? field.questionText : 'Label' }}</label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n <div class=\"radio-options-container\">\n <div *ngFor=\"let option of field.options; let j = index\" class=\"radio-option\">\n <input type=\"radio\" [id]=\"'radio-' + field.id + '-' + j\" [name]=\"'radio-group-' + field.id\"\n [value]=\"option.value || field.defaultValue\" [(ngModel)]=\"field.selectedValue\" class=\"radio-input\"\n [disabled]=\"field.isReadOnly\" [class.hidden]=\"field.isHidden\">\n <label [for]=\"'radio-' + field.id + '-' + j\" class=\"radio-label\"> {{ option.value }}</label>\n </div>\n </div>\n </div>\n </div>\n </div>\n <!-- Dropdown -->\n <div *ngIf=\"field.type === 'Dropdown'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel !== false\">{{\n field.questionText ? field.questionText : 'Label' }}</label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n <select id=\"options\" class=\"dropdown\" [disabled]=\"field.isReadOnly\" [class.hidden]=\"field.isHidden\">\n <option *ngFor=\"let option of field.options\" [value]=\"option.value || field.defaultValue\"> {{ option.value\n }} </option>\n </select>\n </div>\n </div>\n </div>\n\n <!-- Table -->\n <!-- AP-06MAR25 -->\n <div *ngIf=\"field.type === 'Table'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\" style=\"overflow: hidden;\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel !== false\">{{\n field.questionText ? field.questionText : 'Label' }}</label>\n </div>\n <div class=\"top-right\">\n <img src=\"../assets/icons/drag-dots.svg\" alt=\"Drag\" class=\"drag-dot\" />\n <img src=\"../assets/icons/Trash.svg\" (click)=\"removeElement(field, i)\" class=\"delete-icon\" />\n </div>\n </div>\n <div class=\"nxt-table-container\">\n <nxt-datatable isButtons [question]=\"field\" from=\"formBuilder\" [mode]=\"'edit'\" [apiMeta]=\"field.subText\"\n [tableConfig]=\"field.tableConfig\" tableId=\"\" direction=\"ltr\" tableWidth=\"auto\" isEditable=true\n (columnSelected)=columnSelected($event) (removeColumn)=removeColumn($event)>\n </nxt-datatable>\n </div>\n </div>\n </div>\n </div>\n\n <!-- List -->\n <!-- AP-06MAR25 - List data show-->\n <div *ngIf=\"field.type === 'List'\" class=\"field-container\" (click)=\"selectElement(i)\"\n [ngStyle]=\"getFontStyles(field)\" [class.highlight]=\"selectedFieldIndex === i\" draggable=\"true\"\n (dragstart)=\"onDragStart($event, i)\" (dragover)=\"onDragOver($event, i)\" (drop)=\"onDrop($event, i)\">\n <div class=\"field-wrapper\">\n <div class=\"field-content\">\n <div class=\"label-container\">\n <div>\n <label [class.required]=\"field.isOptional\" *ngIf=\"field.style?.showLabel