@rangertechnologies/ngnxt
Version:
This library was used for creating dymanic UI based on the input JSON/data
444 lines • 182 kB
JavaScript
// AP 22JAN25 - form preview and All form elements
import { Component, Input } from '@angular/core';
import { v4 as uuidv4 } from 'uuid';
import { VERSION } from '../../../../environments/version';
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";
import * as i4 from "../../../components/datatable/datatable.component";
import * as i5 from "@angular/material/tooltip";
import * as i6 from "../../booklet/booklet.component";
export class ElementComponent {
formBuilderService;
//@Output() elementButtonClicked = new EventEmitter<string>();
bookletJSON;
bookletId;
field;
formElements = [];
elements = [];
bookId;
sections = {
basic: true, // Basic Elements open by default
advanced: true // Advanced Elements closed by default
};
basicElements = [];
advancedElements = [];
elementDisabledArray;
version = VERSION.version; //SKS10MAR25 get version from environment/version.ts
book;
selectedElement = null;
isSelectTablePopup = false;
currentType;
addTable = true;
dots = Array(6);
draggedIndex = null;
//subscription: any;
constructor(formBuilderService) {
this.formBuilderService = formBuilderService;
}
// AP-06MAR25 New Design Change Elements Basic , Advanced
// AP-06MAR25 Add RichText Area
// AP-12MAR25 Add Date
ngOnInit() {
this.basicElements = [
{ "type": "Text", "img": "Text", "label": "Text" },
{ "type": "TextArea", "img": "TextArea", "label": "Text Area" },
{ "type": "RichTextArea", "img": "RichText", "label": "Rich Text" },
{ "type": "Number", "img": "Number", "label": "Number" },
{ "type": "Label", "img": "Label", "label": "Label" },
{ "type": "Image", "img": "Image", "label": "Image" },
{ "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": "Line", "img": "line", "label": "Line" },
{ "type": "Space", "img": "space", "label": "Space" },
{ "type": "Boolean", "img": "Boolean", "label": "Boolean" },
];
this.advancedElements = [
{ "type": "Book", "img": "Search", "label": "Book" },
{ "type": "Calendar", "img": "Calendar", "label": "Calendar" },
{ "type": "List", "img": "Search", "label": "List" },
{ "type": "File", "img": "File", "label": "Files" },
{ "type": "Table", "img": "Table", "label": "Table" },
{ "type": "Checkbox", "img": "CheckBox", "label": "Checkbox" },
{ "type": "Radio", "img": "Radio", "label": "Radio" },
{ "type": "Dropdown", "img": "Drop", "label": "Dropdown" },
];
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]
});
}
// 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 !== '')) {
this.initializeForm();
}
else {
this.formBuilderService.newBook();
}
}
}
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; // Check for empty object early
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();
}
// ngOnDestroy() {
// this.subscription.unsubscribe();
// }
// drop(event: CdkDragDrop<string[]>) {
// moveItemInArray(this.formElements, event.previousIndex, event.currentIndex);
// //AP-10MAR25 Update order properties to match new indices
// this.formElements.forEach((element, index) => {
// element.order = index + 1;
// });
// this.formBuilderService.updateElementsOrder(this.formElements);
// }
// Add this method to handle element selection
selectElement(index) {
this.selectedFieldIndex = index; // element is selected
this.formBuilderService.setSelectedElement(index);
this.book = this.formBuilderService.getBook();
//const element = this.formElements[index];
// this.elementButtonClicked.emit(element.type);
}
//selectedIndex: number | null = null;
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
}
addElement(type) {
const unique_id = uuidv4();
this.currentType = type;
if (this.selectedElement?.type === 'Table' && this.addTable) {
this.isSelectTablePopup = true;
}
else {
const newElement = {
id: unique_id,
uid: 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,
parentQuestion: null,
fieldsMeta: [],
recordTypeName: null,
recordTypeId: null,
trackingId: null,
dateText: null,
timeText: null,
recordId: null,
qbReference: null,
qbReferenceQuestions: null,
questionBookSubTitle: null,
style: {
labelClass: null,
labelStyle: null,
labelValueStyle: null,
inputClass: null,
inputStyle: null,
showLabel: true,
bookStyle: null,
direction: 'ltr',
questionStyle: null,
},
subText: {
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,
},
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.formElements.map(ele => {
if (ele.type === 'Table') {
ele.fieldsMeta = typeof ele.fieldsMeta === 'string'
? ele.fieldsMeta
: JSON.stringify(ele.fieldsMeta || []);
}
return ele;
});
this.addTable = true;
}
}
// Remove an element by index
removeElement(field, index) {
this.formBuilderService.removeElementComponent(field.id);
this.formElements = this.formBuilderService.getElements();
// SKS19MAR25 fieldsmeta check
this.formElements = this.formElements.map(ele => {
if (ele.type === 'Table') {
ele.fieldsMeta = typeof ele.fieldsMeta === 'string'
? ele.fieldsMeta
: JSON.stringify(ele.fieldsMeta || []);
}
return ele;
});
}
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;
}
getFontStyles(field) {
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',
// 'border-style': field.lineStyle?.toLowerCase() || 'solid',
'color': field.fontColor || '#000000',
// 'border-color': field.color || '#EFF8FF',
'margin-top': field.paddingTop ? `${field.paddingTop}px` : '0px',
'margin-bottom': field.paddingBottom ? `${field.paddingBottom}px` : '10px'
};
return styles;
}
getLineStyles(field) {
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',
'border-style': field.lineStyle?.toLowerCase() || 'solid',
'color': field.fontColor || '#000000',
//'border-color': field.color || '#EFF8FF',
'margin-top': field.paddingTop ? `${field.paddingTop}px` : '0px',
'margin-bottom': field.paddingBottom ? `${field.paddingBottom}px` : '10px'
};
return styles;
}
// 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 = uuidv4();
const tableElement = {
label: `Header Lable ${rowNum}`,
fieldName: `fieldName${rowNum}`,
type: this.currentType,
id: unique_id
};
this.formBuilderService.addTableElement(tableElement, this.selectedFieldIndex);
this.formElements = this.formBuilderService.getElements();
// SKS19MAR25 fieldsmeta checking
this.formElements = this.formElements.map(ele => {
if (ele.type === 'Table') {
ele.fieldsMeta = typeof ele.fieldsMeta === 'string'
? ele.fieldsMeta
: JSON.stringify(ele.fieldsMeta || []);
}
return ele;
});
// this.addTableData(unique_id, fieldName)
}
addTableData(fieldId, fieldName) {
// this.formBuilderService.addTablefieldData(tableElement);
}
columnSelected(event) {
// console.log(event)
// SKS19MAR25 table column update
this.formBuilderService.setSelectedTableElement(this.selectedFieldIndex, event);
}
removeColumn(event) {
// console.log(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);
});
}
// SKS2APR25 disabled element
isElementDisabled(elementType) {
if (this.selectedElement) {
const elements = this.elementDisabledArray[this.selectedElement.type];
if (elements) {
return elements.includes(elementType);
}
}
return false;
}
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, selector: "app-element", inputs: { bookletJSON: "bookletJSON", bookletId: "bookletId" }, 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\" [class.disabled]=\"isElementDisabled(element.type)\"\n (click)=\"!isElementDisabled(element.type) && addElement(element.type)\"\n [draggable]=\"!isElementDisabled(element.type)\" [matTooltip]=\"isElementDisabled(element.type) ? 'This element is not supported when a ' + (selectedElement?.type || 'certain element') + ' is present' : null\">\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\" [class.disabled]=\"isElementDisabled(element.type)\"\n (click)=\"!isElementDisabled(element.type) && addElement(element.type)\"\n [draggable]=\"!isElementDisabled(element.type)\" [matTooltip]=\"isElementDisabled(element.type) ? 'This element is not supported when a ' + (selectedElement?.type || 'certain element') + ' is present' : null\">\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\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 <!-- 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.isRequired\" *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.isRequired\"></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.isRequired\" *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.isRequired\" *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.isRequired\" *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.isRequired\">{{ 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.isRequired\" *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.isRequired\"> {{ 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.isRequired\" *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.isRequired\" *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.isRequired\" *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.isRequired\" *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.isRequired\" *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.isRequired\" *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=\"checkbox-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 : '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.isRequired\" *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.isRequired\" *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.isRequired\" *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\" [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.isRequired\" *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 <input type=\"text\" class=\"custom-input\" placeholder=\"Search...\" [readonly]=\"field.isReadOnly\"\n [class.hidden]=\"field.isHidden\" [value]=\"field.defaultValue ? field.defaultValue : ''\" />\n </div>\n </div>\n </div>\n\n </ng-container>\n </div>\n</div>\n<!-- SKS13MAR25 popup conformation box -->\n<div class=\"dialog-overlay\" *ngIf=\"isSelectTablePopup\">\n <div class=\"dialog-box\">\n <button class=\"close-btn-fb\" (click)=\"onClose()\">\u2715</button>\n <p>These element want to add a table</p>\n <div class=\"b