@rangertechnologies/ngnxt
Version:
This library was used for creating dymanic UI based on the input JSON/data
448 lines • 186 kB
JavaScript
// 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