UNPKG

@rangertechnologies/ngnxt

Version:

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

989 lines 297 kB
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