@rangertechnologies/ngnxt
Version:
This library was used for creating dymanic UI based on the input JSON/data
989 lines • 297 kB
JavaScript
import { Component, EventEmitter, HostListener, Input, Output, ViewChild } from '@angular/core';
import { v4 as uuidv4 } from 'uuid'; //AP-28MAR25 import uuid
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { ImageCropperComponent } from "../../../components/image-cropper/component/image-cropper.component";
import { NxtSearchBox } from "../../../components/search-box/search-box.component";
//AP-25JUN25-Importing common constants for element, field, and appearance properties
import { COMMON_ELEMENT_PROPS, COMMON_OPTIONS_FIELD, COMMON_FIELD_PROPS, COMMON_APPEARANCE_PROPS } from '../properties/common-fields.constants';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common/http";
import * as i2 from "../../../services/form-builder.service";
import * as i3 from "../../../services/template.service";
import * as i4 from "@angular/common";
import * as i5 from "@angular/forms";
export class PropertiesComponent {
http;
formBuilderService;
templateService;
element;
from;
columns;
createElementConfig(config) {
return {
elementProps: [...COMMON_ELEMENT_PROPS, ...(config?.customElementProps || [])],
fieldProps: [...COMMON_FIELD_PROPS, ...(config?.customFieldProps || [])],
appearance: [...COMMON_APPEARANCE_PROPS, ...(config?.customAppearanceProps || [])]
};
}
formButtonHandler = new EventEmitter();
templateSaveHandler = new EventEmitter();
selectedOption = '';
selectedElementIndex = -1;
selectedElementType = '';
selectedAlign = 'align-left'; // Add this property
selectedStyles = []; // Using array since multiple styles can be selected
errorMessage = '';
selectedElement = null; // Receive the selected element
headerSelect = false;
bookId;
book;
activeTab = 'attributes';
selectColumn;
transform = {
translateUnit: 'px',
scale: 1,
rotate: 0,
flipH: false,
flipV: false,
translateH: 0,
translateV: 0
};
canvasRotation = 0;
cropper;
loading = false;
cropperMaxHeight = 0;
cropperMaxWidth = 0;
cropperMinHeight = 0;
cropperMinWidth = 0;
cropperStaticWidth = 0;
cropperStaticHeight = 0;
aspectRatio = 4 / 3;
roundCropper = false;
imageChangedEvent = null;
alignImage = 'center';
// "endpoint": "https://dev-api.valarhr.com/nxt",
// SKS28MAR25 default book search endpoint
bookSubtext = {
"endpoint": "https://dev-api.valarhr.com/nxt",
"variable": null,
"field": ['label', 'name'],
"defaultField": "label"
};
isLinkDropdownOpen = false;
templateSelected = false;
dropdown;
draggedId = null;
formElements = [];
unique_id = 'book-1234'; // should be consistent
selectedTemplate;
elementProperties = {
// AP-10MAR25 - Defines the Header element with a text input field
// AP-25MAR25 Add subtext all variables
'Header': {
elementProps: [
{ label: 'Label', placeholder: 'Enter Text', type: 'text', key: 'title' }
]
},
// AP-19MAR25 Add Line Property
'Line': {
elementProps: [
{ label: 'Line Width', type: 'fieldSize', key: 'size' },
{ label: 'Padding Top', type: 'number', key: 'paddingTop', placeholder: 'Enter padding top' },
{ label: 'Padding Bottom', type: 'number', key: 'paddingBottom', placeholder: 'Enter padding bottom' },
{
label: 'Line Style', type: 'select', key: 'lineStyle',
options: ['Solid', 'Dashed', 'Dotted']
}
],
fieldProps: []
},
'Space': {
elementProps: [
{ label: 'Element', type: 'number', key: 'questionNumber' },
{ label: 'Field Size', type: 'fieldSize', key: 'size' },
],
fieldProps: []
},
"Table": {
"elementProps": [
{ label: 'Is Label', placeholder: 'Enter Text ', type: 'checkbox', key: 'style.showLabel' },
{ key: 'primaryKey' },
{ "label": "tableName", "placeholder": "Employee Details", "type": "text", "key": "questionText" },
{ "label": "inputTextAlignment", "placeholder": "Left", "type": "text", "key": "inputTextAlignment" },
{ "label": "tableScaleSize", "placeholder": "06 - Full Scale", "type": "text", "key": "tableScaleSize" },
{ "label": "isNosIndicator", "placeholder": "06 - Full Scale", "type": "checkbox", "key": "tableConfig.isNosIndicator" },
{ "label": "isPagination", "placeholder": "06 - Full Scale", "type": "checkbox", "key": "tableConfig.isPagination" },
{ "label": "addInlineRecord", "placeholder": "06 - Full Scale", "type": "checkbox", "key": "tableConfig.addInlineRecord" },
{ "label": "actionButton", "placeholder": "06 - Full Scale", "type": "checkbox", "key": "tableConfig.actionButton" },
{ "label": "searchBar", "placeholder": "06 - Full Scale", "type": "checkbox", "key": "tableConfig.searchBar" },
{ "label": "isDeleteRow", "placeholder": "06 - Full Scale", "type": "checkbox", "key": "tableConfig.isDeleteRow" },
{ "label": "isEditRow", "placeholder": "06 - Full Scale", "type": "checkbox", "key": "tableConfig.isEditRow" },
{ "label": "isButtons", "placeholder": "06 - Full Scale", "type": "checkbox", "key": "tableConfig.isButtons" },
{ "label": "rowChoice", "placeholder": "", "type": "text", "key": "rowChoice" },
{ label: 'questionNumber', type: 'number', key: 'questionNumber' },
{ label: 'Field Size', type: 'fieldSize', key: 'size' },
],
"fieldProps": [
{ "label": "tableId", "placeholder": "Emp_Table_01", "type": "text", "key": "tableId" },
{ "label": "helpText", "placeholder": "Enter message", "type": "text", "key": "helpText" },
{ "label": "defaultValue", "placeholder": "Default Value", "type": "text", "key": "defaultValue" },
{ label: 'Reference', placeholder: 'Reference Field', type: 'text', key: 'referenceField' },
{
"label": "", "placeholder": "Enter Text", "type": "subQuestion", "key": "isSubText",
"subQuestion": [
{ "label": "End Point", "placeholder": "endpoint", "type": "text", "key": "subText.endpoint" },
{ "label": "Variable", "placeholder": "variable", "type": "text", "key": "subText.variable" },
{ "label": "Field", "placeholder": "field", "type": "text", "key": "subText.field" },
{ "label": "Default Field", "placeholder": "defaultField", "type": "text", "key": "subText.defaultField" },
{ "label": "Label Field", "placeholder": "labelField", "type": "text", "key": "subText.labelField" },
{ "label": "Value Field", "placeholder": "valueField", "type": "text", "key": "subText.valueField" },
{ "label": "Source Question Id", "placeholder": "sourceQuestionId", "type": "text", "key": "subText.sourceQuestionId" },
{ "label": "Dependent Value", "placeholder": "dependentValue", "type": "text", "key": "subText.dependentValue" },
{ "label": "Dependent Field", "placeholder": "isDependentField", "type": "boolean", "key": "subText.isDependentField" },
{ "label": "Query Field", "placeholder": "queryField", "type": "text", "key": "subText.queryField" },
{ "label": "Query Value", "placeholder": "queryValue", "type": "text", "key": "subText.queryValue" },
{ "label": "Query Value Ref", "placeholder": "queryValueRef", "type": "text", "key": "subText.queryValueReference" },
{ "label": "Unique Key", "placeholder": "uniqueKey", "type": "text", "key": "subText.uniqueKey" },
]
},
],
"appearance": [
{
label: 'Select Font', type: 'select', key: 'font', placeholder: 'Left', required: true,
options: ['Helvetica Neue', 'Arial', 'Times New Roman', 'Roboto']
},
{ label: 'Font Color', type: 'color', key: 'fontColor', defaultValue: '', required: true },
{
label: 'Font Size', type: 'select', key: 'fontSize', defaultValue: '', required: true,
options: [
{ label: 'Small', value: '12px' },
{ label: 'Medium', value: '14px' },
{ label: 'Large', value: '16px' }
]
},
{
label: 'Font Width', type: 'select', key: 'fontWeight', defaultValue: '', required: true,
options: [
{ value: '400', label: '400-Normal' },
{ value: '500', label: '500-Medium' },
{ value: '600', label: '600-Semi Bold' },
{ value: '700', label: '700-Bold' }
]
},
{ label: 'Duplicate Field', type: 'button-toggle', key: 'duplicateField', defaultValue: false }
]
},
"TableColumn": {
"elementProps": [
{ "label": "headerLabels", "placeholder": "Employee Details", "type": "text", "targetArray": "fieldsMeta", "targetArrayKey": "uniqueIdentifier", "key": "label" },
{ "label": "apiName", "placeholder": "Employee Details", "type": "text", "targetArray": "fieldsMeta", "targetArrayKey": "uniqueIdentifier", "key": "apiName" },
{
"label": "Summary Column", "placeholder": "Summary Column", "type": "subQuestion", "targetArray": "fieldsMeta", "targetArrayKey": "uniqueIdentifier", "key": "summaryColumn",
"subQuestion": [
{ "label": "Type", "placeholder": "Employee Details", "type": "text", "targetArray": "fieldsMeta", "targetArrayKey": "uniqueIdentifier", "key": "fldType" },
{ "label": "Operation", "placeholder": "Employee Details", "type": "text", "targetArray": "fieldsMeta", "targetArrayKey": "uniqueIdentifier", "key": "operation" },
{ "label": "Operands", "placeholder": "Employee Details", "type": "array", "targetArray": "fieldsMeta", "targetArrayKey": "uniqueIdentifier", "key": "operands" },
]
},
{
"label": "Summary Row", "placeholder": "Summary Row", "type": "subQuestion", "targetArray": "fieldsMeta", "targetArrayKey": "uniqueIdentifier", "key": "summaryRow", "subQuestion": [
{ "label": "Type", "placeholder": "Employee Details", "type": "text", "targetArray": "fieldsMeta", "targetArrayKey": "uniqueIdentifier", "key": "fldType" },
{ "label": "operation", "placeholder": "operation", "type": "text", "targetArray": "fieldsMeta", "targetArrayKey": "uniqueIdentifier", "key": "operation" },
{ "label": "column", "placeholder": "Employee Details", "type": "radio", "targetArray": "fieldsMeta", "targetArrayKey": "uniqueIdentifier", "key": "column" },
{ "label": "operands", "placeholder": "Employee Details", "type": "array", "targetArray": "fieldsMeta", "targetArrayKey": "uniqueIdentifier", "key": "operands" },
]
},
{ "label": "inputTextAlignment", "placeholder": "Left", "type": "text", "key": "inputTextAlignment" },
{ "label": "tableScaleSize", "placeholder": "06 - Full Scale", "type": "text", "key": "tableScaleSize" },
{ "label": "rowChoice", "placeholder": "", "type": "text", "key": "rowChoice" },
],
"fieldProps": [
{ "label": "tableId", "placeholder": "Emp_Table_01", "type": "text", "key": "tableId" },
{ "label": "inputTextAlignment", "placeholder": "Left", "type": "text", "key": "inputTextAlignment" },
{ "label": "helpText", "placeholder": "Enter help message here", "type": "text", "key": "helpText" },
{ "label": "defaultValue", "placeholder": "Default Value", "type": "text", "key": "defaultValue" },
{ "label": "referenceAnchor", "placeholder": "http://source/rangernxt_bio_data/74/d.doc", "type": "text", "key": "referenceAnchor" },
],
"appearance": [
{
label: 'Select Font', type: 'select', key: 'font', placeholder: 'Left', required: true,
options: ['Helvetica Neue', 'Arial', 'Times New Roman', 'Roboto']
},
{ label: 'Font Color', type: 'color', key: 'fontColor', defaultValue: '', required: true },
{
label: 'Font Size', type: 'select', key: 'fontSize', defaultValue: '', required: true,
options: [
{ label: 'Small', value: '12px' },
{ label: 'Medium', value: '14px' },
{ label: 'Large', value: '16px' }
]
},
{
label: 'Font Width', type: 'select', key: 'fontWeight', defaultValue: '', required: true,
options: [
{ value: '400', label: '400-Normal' },
{ value: '500', label: '500-Medium' },
{ value: '600', label: '600-Semi Bold' },
{ value: '700', label: '700-Bold' }
]
},
{ label: 'Duplicate Field', type: 'button-toggle', key: 'duplicateField', defaultValue: false }
]
},
ListColumn: this.createElementConfig({
customFieldProps: [
...COMMON_OPTIONS_FIELD.map(opt => ({
type: 'list'
})),
],
customElementProps: [
{ label: "headerLabels", placeholder: "Employee Details", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "label" },
{ label: "apiName", placeholder: "Employee Details", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "apiName" },
{
label: "Summary Column", placeholder: "Summary Column", type: "subQuestion", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "summaryColumn",
subQuestion: [
{ label: "Type", placeholder: "Employee Details", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "fldType" },
{ label: "Operation", placeholder: "Employee Details", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "operation" },
{ label: "Operands", placeholder: "Employee Details", type: "array", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "operands" },
]
},
{
label: "Summary Row", placeholder: "Summary Row", type: "subQuestion", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "summaryRow",
subQuestion: [
{ label: "Type", placeholder: "Employee Details", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "fldType" },
{ label: "operation", placeholder: "operation", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "operation" },
{ label: "column", placeholder: "Employee Details", type: "radio", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "column" },
{ label: "operands", placeholder: "Employee Details", type: "array", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "operands" },
]
},
]
}),
DropdownColumn: this.createElementConfig({
customFieldProps: [
...COMMON_OPTIONS_FIELD.map(opt => ({
...opt,
type: 'dropdown'
})),
],
customElementProps: [
{ label: "headerLabels", placeholder: "Employee Details", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "label" },
{ label: "apiName", placeholder: "Employee Details", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "apiName" },
{
label: "Summary Column", placeholder: "Summary Column", type: "subQuestion", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "summaryColumn",
subQuestion: [
{ label: "Type", placeholder: "Employee Details", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "fldType" },
{ label: "Operation", placeholder: "Employee Details", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "operation" },
{ label: "Operands", placeholder: "Employee Details", type: "array", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "operands" },
]
},
{
label: "Summary Row", placeholder: "Summary Row", type: "subQuestion", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "summaryRow",
subQuestion: [
{ label: "Type", placeholder: "Employee Details", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "fldType" },
{ label: "operation", placeholder: "operation", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "operation" },
{ label: "column", placeholder: "Employee Details", type: "radio", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "column" },
{ label: "operands", placeholder: "Employee Details", type: "array", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "operands" },
]
},
]
}),
DateColumn: this.createElementConfig({
customFieldProps: [
...COMMON_OPTIONS_FIELD.map(opt => ({
type: 'date'
})),
],
customElementProps: [
{ label: "headerLabels", placeholder: "Employee Details", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "label" },
{ label: "apiName", placeholder: "Employee Details", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "apiName" },
{
label: "Summary Column", placeholder: "Summary Column", type: "subQuestion", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "summaryColumn",
subQuestion: [
{ label: "Type", placeholder: "Employee Details", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "fldType" },
{ label: "Operation", placeholder: "Employee Details", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "operation" },
{ label: "Operands", placeholder: "Employee Details", type: "array", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "operands" },
]
},
{
label: "Summary Row", placeholder: "Summary Row", type: "subQuestion", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "summaryRow",
subQuestion: [
{ label: "Type", placeholder: "Employee Details", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "fldType" },
{ label: "operation", placeholder: "operation", type: "text", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "operation" },
{ label: "column", placeholder: "Employee Details", type: "radio", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "column" },
{ label: "operands", placeholder: "Employee Details", type: "array", targetArray: "fieldsMeta", targetArrayKey: "uniqueIdentifier", key: "operands" },
]
},
]
}),
Checkbox: this.createElementConfig({
customFieldProps: COMMON_OPTIONS_FIELD.map(opt => ({
...opt,
type: 'checkbox'
}))
}),
Dropdown: this.createElementConfig({
customFieldProps: COMMON_OPTIONS_FIELD.map(opt => ({
...opt,
type: 'dropdown'
}))
}),
Radio: this.createElementConfig({
customFieldProps: COMMON_OPTIONS_FIELD.map(opt => ({
...opt,
type: 'checkbox'
}))
}),
Text: this.createElementConfig(),
Calendar: this.createElementConfig(),
Date: this.createElementConfig(),
Time: this.createElementConfig(),
DateTime: this.createElementConfig(),
Email: this.createElementConfig(),
Book: this.createElementConfig(),
List: this.createElementConfig(),
TextArea: this.createElementConfig(),
RichTextArea: this.createElementConfig(),
Number: this.createElementConfig(),
Image: this.createElementConfig(),
Label: this.createElementConfig(),
Boolean: this.createElementConfig(),
File: this.createElementConfig(),
Icon: this.createElementConfig(), //MSM10JUL25 icon selector element
};
constructor(http, formBuilderService, templateService) {
this.http = http;
this.formBuilderService = formBuilderService;
this.templateService = templateService;
}
handleTemplateSelection(event) {
this.formElements = event.elements;
this.selectedTemplate = event.selectedTemplate;
this.templateService.formElements = this.formElements;
this.templateService.book = this.book;
this.templateService.unique_id = this.unique_id;
}
duplicateField(element) {
const elements = this.formBuilderService.getElements();
const copy = JSON.parse(JSON.stringify(element));
//AP-18APR25 Generate a new ID using the service's method
copy.id = this.formBuilderService.addElementWithId();
//copy.uuid = copy.id;
// AP-18APR25 Set the questionNumber to the next available number
copy.questionNumber = elements.length + 1;
this.formBuilderService.addElement(copy);
}
saveData() {
this.templateService.formElements = this.formElements;
this.templateService.book = this.book;
this.templateService.unique_id = this.unique_id;
const updatedBook = this.templateService.download();
}
ngOnInit() {
//AP-10MAR25 Subscribes to header selection changes and updates the selected element
this.formBuilderService.selectHeaderSubject$.subscribe(header => {
if (header) {
if (!this.selectedElement) {
this.selectedElement = {};
}
this.selectedElement['type'] = header;
this.headerSelect = true;
this.book = this.formBuilderService.getBook();
this.bookId = this.book.records[0].id;
}
});
this.formBuilderService.selectedElement$.subscribe(index => {
this.selectedElementIndex = index;
this.headerSelect = false;
if (index >= 0) {
const elements = this.formBuilderService.getElements();
this.selectedElement = elements[index];
if (this.selectedElement?.type === 'Table') {
this.selectedElement['fieldsMeta'] = typeof this.selectedElement.fieldsMeta === 'object' ? this.selectedElement.fieldsMeta : JSON.parse(this.selectedElement['fieldsMeta'] || []);
this.selectColumn = this.formBuilderService.getSelectTableColumn() === undefined ? null : this.formBuilderService.getSelectTableColumn();
}
else {
this.selectColumn = null;
}
}
this.getProperties();
});
this.formBuilderService.selectHeaderSubject$.subscribe(action => {
if (action) {
this.book = this.formBuilderService.getBook();
}
});
if (this.from === 'formBuilder') {
const fieldsMeta = typeof this.element.fieldsMeta === 'string'
? JSON.parse(this.element.fieldsMeta)
: this.element.fieldsMeta;
this.columns = fieldsMeta.map(column => ({
...column,
type: column.fldType || 'Text' // Default to 'Text' if fldType not available
}));
}
}
// AP 23MAY25 - Add a new button with default styling
addNewButton() {
const lastPercent = this.book?.questionbook?.action?.slice(-1)[0]?.positionPercent || 0;
const buttons = {
name: '',
eventtoemit: '',
alt: '',
endpoint: '',
method: '',
id: this.formBuilderService.addElementWithId(),
positionPercent: lastPercent + 10,
width: 100,
borderRadius: 6,
alignment: 'flex-start'
};
this.formBuilderService.updateQuestionBookActionButtons(buttons, 'add');
}
//AP 23MAY25 - Remove a button from the action list
removeButton(btn) {
this.formBuilderService.updateQuestionBookActionButtons(btn, 'remove');
}
//AP 23MAY25 - Update a specific property of a button
onButtonPropertyChange(index, key, value) {
const buttons = this.getValueByPath('action') || [];
if (buttons[index]) {
buttons[index][key] = value;
this.setValueByPath('action', buttons);
}
}
//AP-10MAR25 Updates the title using the form builder service
updateTitle(event) {
this.formBuilderService.updateTitle(event);
}
validateInput(value, type) {
if (type === 'label' || type === 'placeholder') {
const regex = /^[a-zA-Z0-9\s]*$/;
if (!regex.test(value)) {
this.errorMessage = 'Only letters and numbers are allowed';
return false;
}
}
this.errorMessage = '';
return true;
}
get fieldAsString() {
return this.bookSubtext.field.join(', '); //SKS28MAR25 Convert array to comma-separated string
}
updateField(value) {
this.bookSubtext.field = value.split(',').map(item => item.trim()); //SKS28MAR25 Convert string back to array
}
// SKS20MAR25 Getter to filter columns, excluding the one with currentUniqueIdentifier
get filteredColumns() {
const targetArray = this.getDataByPath('fieldsMeta');
return targetArray.filter(column => column.uniqueIdentifier !== this.selectColumn);
}
// SKS20MAR25 Method to handle checkbox changes
onCheckboxChange(targetArrayPath, targetArrayKey, key, apiName, isChecked) {
const targetArray = this.getDataByPath(targetArrayPath);
const foundItem = targetArray.find(item => item[targetArrayKey] === this.selectColumn);
foundItem[key] = foundItem[key] ? foundItem[key] : [];
if (isChecked) {
// Add apiName to selectedApiNames if not already present
if (!foundItem[key].includes(apiName)) {
foundItem[key].push(apiName);
}
}
else {
// Remove apiName from selectedApiNames if present
const index = foundItem[key].indexOf(apiName);
if (index > -1) {
foundItem[key].splice(index, 1);
}
}
// this.updateElement(this.selectedElement)
}
updateProperty(key, value) {
if (this.selectedElementIndex >= 0) {
if (this.selectedElement.type === 'Table') {
this.setValueByPath(key, value);
}
if (key === 'questionText' || key === 'question') {
if (!this.validateInput(value, key)) {
return;
}
}
if (key === 'questionNumber') {
//AP-10MAR25 Convert the value to an integer
const newOrder = parseInt(value, 10);
if (isNaN(newOrder))
return;
//AP-10MAR25 Update the element's questionNumber in the form builder service
this.formBuilderService.updateElement(this.selectedElementIndex, { questionNumber: newOrder });
//AP-10MAR25 Sort elements based on the updated questionNumber
this.formBuilderService.sortElementsByOrder();
}
if (key === 'fontWeight') {
this.selectedElement[key] = value;
}
const update = { [key]: value };
this.formBuilderService.updateElement(this.selectedElementIndex, update);
// Special handling for font and font weight
if (key === 'font') {
this.selectedElement.font = value; // Directly update the selected element's font property
}
}
}
// SKS21MAR25 radio button click handler
onRadioChange(targetArrayPath, targetArrayKey, key, value) {
if (this.selectedElement.type === 'Table') {
// this.updateValueByArrayPath(targetArray, targetArrayKey, this.selectColumn, key, value);
if (this.selectedElement?.type === 'Table') {
this.selectedElement['fieldsMeta'] = typeof this.selectedElement?.fieldsMeta === 'object' ? this.selectedElement?.fieldsMeta : JSON.parse(this.selectedElement['fieldsMeta'] || []);
}
const targetArray = this.getDataByPath(targetArrayPath);
// console.log("targetArray", targetArray, "targetArrayKey", targetArrayKey, "selectColumn", this.selectColumn, "keyPath", key, "event", value)
if (!Array.isArray(targetArray))
return;
// Find the object that matches selectColumn
let foundItem = targetArray.find(item => item[targetArrayKey] === this.selectColumn);
// If the item does not exist, create and add it
if (!foundItem) {
foundItem = { [targetArrayKey]: this.selectColumn }; // Ensure the key exists
targetArray.push(foundItem);
}
// Traverse and set the value
const keys = key.split('.');
let obj = foundItem;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!obj[key])
obj[key] = {}; // Initialize missing objects
obj = obj[key];
}
// Assign the value based on input type
const lastKey = keys[keys.length - 1];
obj[lastKey] = value;
if (this.selectedElement?.type === 'Table') {
this.selectedElement['fieldsMeta'] = typeof this.selectedElement?.fieldsMeta === 'object' ? JSON.stringify(this.selectedElement?.fieldsMeta) : this.selectedElement['fieldsMeta'] || [];
}
this.updateElement(this.selectedElement);
}
else {
this.setValueByPath(key, value); // Fallback for non-Table elements, if applicable
}
}
onRequiredChange(value) {
if (this.selectedElement) {
let label = this.selectedElement.label ? this.selectedElement.label.replace(/\s*\*+$/, '') : 'Label';
if (value) {
label = `${label} *`;
}
this.updateProperty('label', label);
this.updateProperty('isOptional', value);
}
}
// Toggle for Sub Questions (Each prop has its own state)
toggleSubQuestion(prop) {
prop.isExpanded = !prop.isExpanded;
}
// Separate Toggle for Style Section
isStyleExpanded = false;
toggleStyleSection() {
this.isStyleExpanded = !this.isStyleExpanded;
}
getProperties() {
if (!this.selectedElement)
return null;
// AP-10MAR25 Retrieve the latest book data
this.book = this.formBuilderService.getBook();
// AP-10MAR25 If the selected element is a 'Header', return its properties
if (this.selectedElement?.type === 'Header') {
return this.elementProperties['Header'];
}
if (this.selectedElement?.type === 'Table') {
if (this.selectColumn !== null) {
// Get the column metadata
const fieldsMeta = Array.isArray(this.selectedElement.fieldsMeta)
? this.selectedElement.fieldsMeta
: JSON.parse(this.selectedElement.fieldsMeta || '[]');
const column = fieldsMeta.find((c) => c.uniqueIdentifier === this.selectColumn);
if (column) {
// Return specific properties based on column type
switch (column.fldType) {
case 'List':
return this.elementProperties['ListColumn'];
case 'Dropdown':
return this.elementProperties['DropdownColumn'];
case 'Date':
return this.elementProperties['DateColumn'];
default:
return this.elementProperties['TableColumn'];
}
}
return this.elementProperties[this.selectedElement?.type] || this.elementProperties['DefaultColumn'];
}
}
return this.elementProperties[this.selectedElement?.type];
}
// AP-28MAR25 Add an option with a unique UUID
addOption(options) {
const unique_id = uuidv4();
options.push({ id: unique_id, value: '' });
}
// AP-28MAR25 Function to remove an option based on its unique UUID
removeOption(options, id) {
const index = options.findIndex(option => option.id === id);
if (index !== -1) {
options.splice(index, 1);
}
}
handleButtonClick() {
this.formButtonHandler.emit(this.formBuilderService.downloadElement());
}
handleTemplateSave() {
this.templateSaveHandler.emit(this.templateService.download());
}
// SKS13MAR25 active tab select
setActiveTab(tab) {
this.activeTab = tab;
}
// SKS13MAR25 table property save
onSave() {
// console.log('Saving data:');
}
// SKS13MAR25 table property reset
onCancel() {
// console.log('Operation cancelled');
}
updateProperties(elementType) {
// Reset alignment and styles if switching elements
this.selectedAlign = 'align-left';
this.selectedStyles = [];
// Fetch the properties of the selected element type
const properties = this.getProperties();
if (properties) {
// Make sure the properties are dynamically updated
}
}
onAlignSelect(value) {
if (this.selectedElement) {
this.selectedElement.textAlign = value;
}
}
onStyleSelect(value) {
if (!this.selectedElement)
return;
// Initialize styles array if it doesn't exist
this.selectedElement.styles = this.selectedElement.styles || [];
// Ensure only one style is selected at a time
this.selectedElement.styles = [value];
}
isStyleActive(value) {
return this.selectedElement?.styles?.includes(value) || false;
}
getValueByPath(path) {
if (this.selectedElement?.type === 'Table') {
this.selectedElement['fieldsMeta'] = typeof this.selectedElement?.fieldsMeta === 'object' ? this.selectedElement?.fieldsMeta : JSON.parse(this.selectedElement['fieldsMeta'] || []);
}
this.selectedElement['subText'] =
typeof this.selectedElement?.subText === 'object'
? this.selectedElement.subText
: (typeof this.selectedElement?.subText === 'string' && this.selectedElement.subText.trim() !== ''
? JSON.parse(this.selectedElement.subText)
: {});
if (this.selectedElement['subText'] && Array.isArray(this.selectedElement['subText'].field)) {
// Convert array to a comma-separated string
this.selectedElement['subText'].field = this.selectedElement['subText'].field.join(', ');
}
return path.split('.').reduce((obj, key) => obj?.[key] ?? '', this.selectedElement);
}
isAnotherIdSelected() {
return this.formBuilderService.getElements()
.some((el, i) => i !== this.selectedElementIndex && el.primaryKey);
}
onToggleChange(path, event) {
const checked = event.target.checked;
this.setValueByPath(path, checked);
if (this.selectedElement?.type === 'Table') {
this.selectedElement['fieldsMeta'] = typeof this.selectedElement?.fieldsMeta === 'object' ? JSON.stringify(this.selectedElement?.fieldsMeta) : this.selectedElement['fieldsMeta'] || [];
}
this.updateElement(this.selectedElement);
}
setValueByPath(path, value) {
if (this.selectedElementIndex >= 0) {
if (path === 'questionText' || value === 'question') {
if (!this.validateInput(value, value)) {
}
}
if (path === 'questionNumber') {
//AP-10MAR25 Convert the value to an integer
const newOrder = parseInt(value, 10);
if (isNaN(newOrder))
return;
//AP-10MAR25 Update the element's questionNumber in the form builder service
this.formBuilderService.updateElement(this.selectedElementIndex, { questionNumber: newOrder });
//AP-10MAR25 Sort elements based on the updated questionNumber
this.formBuilderService.sortElementsByOrder();
}
if (path === 'fontWeight') {
// console.log('Font weight selected:', value);
this.selectedElement[path] = value;
}
// Special handling for font and font weight
if (path === 'font') {
this.selectedElement.font = value; // Directly update the selected element's font property
}
}
const keys = path.split('.');
let obj = this.selectedElement;
if (this.selectedElement?.type === 'Table') {
this.selectedElement['fieldsMeta'] = typeof this.selectedElement?.fieldsMeta === 'object' ? this.selectedElement?.fieldsMeta : JSON.parse(this.selectedElement['fieldsMeta'] || []);
}
this.selectedElement['subText'] = typeof this.selectedElement?.subText === 'object' ? this.selectedElement?.subText : JSON.parse(this.selectedElement['subText']);
keys.forEach((key, index) => {
if (!obj[key]) {
// Check if the next key is a number (array index)
const nextKey = keys[index + 1];
obj[key] = isNaN(Number(nextKey)) ? {} : [];
}
if (index === keys.length - 1) {
obj[key] = value; // Assign value to last key
}
else {
obj = obj[key]; // Move deeper
}
});
this.formBuilderService.elementUpdate(this.selectedElementIndex, this.selectedElement);
}
getStyleKeys() {
if (!this.selectedElement || !this.selectedElement.style || typeof this.selectedElement.style !== 'object') {
return [];
}
return Object.keys(this.selectedElement.style);
}
// SKS19MAR25 update element in servies
updateElement(element) {
this.formBuilderService.elementUpdate(this.selectedElementIndex, element);
if (this.selectedElement?.type === 'Table' && this.selectColumn) {
this.selectedElement['fieldsMeta'] = typeof this.selectedElement?.fieldsMeta === 'object' ? this.selectedElement?.fieldsMeta : JSON.parse(this.selectedElement.fieldsMeta || []);
const foundItem = this.selectedElement['fieldsMeta'].find(item => item['uniqueIdentifier'] === this.selectColumn);
this.formBuilderService.setSelectedTableElement(this.selectedElementIndex, { column: foundItem?.apiName || null });
}
}
// SKS19MAR25 get value from array
getValueByArrayPath(targetArrayPath, targetArrayKey, selectColumn, keyPath) {
if (this.selectedElement?.type === 'Table') {
this.selectedElement['fieldsMeta'] = typeof this.selectedElement?.fieldsMeta === 'object' ? this.selectedElement?.fieldsMeta : JSON.parse(this.selectedElement['fieldsMeta'] || []);
}
const targetArray = this.getDataByPath(targetArrayPath);
if (!Array.isArray(targetArray))
return '';
const foundItem = targetArray.find(item => item[targetArrayKey] === selectColumn);
return foundItem ? keyPath.split('.').reduce((obj, key) => obj?.[key], foundItem) : '';
}
//SKS19MAR25 Function to update a value in an array dynamically
updateValueByArrayPath(targetArrayPath, targetArrayKey, selectColumn, keyPath, event) {
if (this.selectedElement?.type === 'Table') {
this.selectedElement['fieldsMeta'] = typeof this.selectedElement?.fieldsMeta === 'object' ? this.selectedElement?.fieldsMeta : JSON.parse(this.selectedElement['fieldsMeta'] || []);
}
const targetArray = this.getDataByPath(targetArrayPath);
// console.log("targetArray", targetArray, "targetArrayKey", targetArrayKey, "selectColumn", selectColumn, "keyPath", keyPath, "event", event)
if (!Array.isArray(targetArray))
return;
// Find the object that matches selectColumn
let foundItem = targetArray.find(item => item[targetArrayKey] === selectColumn);
// If the item does not exist, create and add it
if (!foundItem) {
foundItem = { [targetArrayKey]: selectColumn }; // Ensure the key exists
targetArray.push(foundItem);
}
// Traverse and set the value
const keys = keyPath.split('.');
let obj = foundItem;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!obj[key])
obj[key] = {}; // Initialize missing objects
obj = obj[key];
}
// Assign the value based on input type
const lastKey = keys[keys.length - 1];
const inputElement = event.target;
obj[lastKey] = inputElement?.type === 'checkbox' ? inputElement.checked : inputElement.value;
if (keyPath === 'summaryColumn') {
if (obj['summaryRow'] === true) {
obj['summaryRow'] = false;
}
if (inputElement.checked === true) {
obj['fldType'] = 'calculation';
}
else {
obj['fldType'] = 'Text';
}
}
if (keyPath === 'summaryRow') {
if (obj['summaryColumn'] === true) {
obj['summaryColumn'] = false;
}
if (inputElement.checked === true) {
obj['fldType'] = 'calculation';
}
else {
obj['fldType'] = 'Text';
}
}
if (this.selectedElement?.type === 'Table') {
this.selectedElement['fieldsMeta'] = typeof this.selectedElement?.fieldsMeta === 'object' ? JSON.stringify(this.selectedElement?.fieldsMeta) : this.selectedElement['fieldsMeta'] || [];
}
this.updateElement(this.selectedElement);
}
getDataByPath(path) {
if (this.selectedElement?.type === 'Table') {
this.selectedElement['fieldsMeta'] = typeof this.selectedElement?.fieldsMeta === 'object' ? this.selectedElement?.fieldsMeta : JSON.parse(this.selectedElement['fieldsMeta'] || []);
}
return path.split('.').reduce((obj, key) => obj?.[key], this.selectedElement);
}
// SKS25MAR25 image edit functions
flipHorizontal() {
this.transform = {
...this.transform,
flipH: !this.transform.flipH
};
}
flipVertical() {
this.transform = {
...this.transform,
flipV: !this.transform.flipV
};
}
resetImage() {
this.canvasRotation = 0;
this.cropper = undefined;
this.transform = {
translateUnit: 'px',
scale: 1,
rotate: 0,
flipH: false,
flipV: false,
translateH: 0,
translateV: 0
};
}
zoomOut() {
this.transform = {
...this.transform,
scale: this.transform.scale - .1
};
}
zoomIn() {
this.transform = {
...this.transform,
scale: this.transform.scale + .1
};
}
rotateLeft() {
this.loading = true;
setTimeout(() => {
this.canvasRotation--;
this.flipAfterRotate();
});
}
rotateRight() {
this.loading = true;
setTimeout(() => {
this.canvasRotation++;
this.flipAfterRotate();
});
}
moveLeft() {
this.transform = {
...this.transform,
translateH: this.transform.translateH - 1
};
}
moveRight() {
this.transform = {
...this.transform,
translateH: this.transform.translateH + 1
};
}
moveDown() {
this.transform = {
...this.transform,
translateV: this.transform.translateV + 1
};
}
moveUp() {
this.transform = {
...this.transform,
translateV: this.transform.translateV - 1
};
}
flipAfterRotate() {
const flippedH = this.transform.flipH;
const flippedV = this.transform.flipV;
this.transform = {
...this.transform,
flipH: flippedV,
flipV: flippedH,
translateH: 0,
translateV: 0
};
}
async imageCropped(event) {
try {
const base64 = await this.convertBlobToBase64(event.objectUrl);
this.selectedElement.imageData = base64;
await this.formBuilderService.elementUpdate(this.selectedElementIndex, this.selectedElement);
// console.log('CROPPED', event);
}
catch (error) {
console.error("Error in imageCropped:", error);
}
}
cropperReady(sourceImageDimensions) {
// console.log('Cropper ready', sourceImageDimensions);
this.loading = false;
}
// SKS25MAR25 blob to base 64 converter
convertBlobToBase64(objectUrl) {
return fetch(objectUrl)
.then(response => response.blob())
.then(blob => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
});
}
// SKS28MAR25 qb book update in book element
childEventCapture(event) {
this.selectedElement.qbReference = event.valueObj?.name;
this.selectedElement.qbReferenceQuestions = event.valueObj?.jsonBody;
this.formBuilderService.elementUpdate(this.selectedElementIndex, this.selectedElement);
}
// SKS28MAR25 book search dropdown emit
linkToggleDropdown(event) {
event.stopPropagation();
this.isLinkDropdownOpen = !this.isLinkDropdownOpen;
}
// SKS28MAR25 book search dropdown close
onClickOutside(event) {
if (this.dropdown && !this.dropdown.nativeElement.contains(event.target)) {
this.isLinkDropdownOpen = false;
}
}
// AP-28MAR25 When drag starts, store the index
onDragStart(event, id) {
this.draggedId = id;
event.dataTransfer.effectAllowed = "move";
}
// AP-28MAR25 Prevent default behavior to allow drop
onDragOver(event) {
event.preventDefault();
}
// AP-28MAR25 Swap the dragged item with the dropped position
onDrop(event, key) {
event.preventDefault();
const targetId = event.target.closest(".option-items")?.getAttribute("data-id");
if (this.draggedId && targetId && this.draggedId !== targetId) {
const options = this.selectedElement[key];
[options[this.draggedId], options[targetId]] = [options[targetId], options[this.dragge