{"version":3,"file":"main.3f45e384fdc910db.js","mappings":"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","names":["BrandingService","constructor","sanitizer","argTitle","this","BehaviorSubject","setBranding","branding","next","setFooterLinks","footerLinks","setTitle","title","obtainBrandingBackgroundColor","backgroundStyle","Color","bypassSecurityTrustStyle","obtainBrandingIconUrl","iconUrl","Icon","bypassSecurityTrustUrl","core","factory","i0","HeaderComponent","argChangeDetector","brandingService","ngOnInit","subscribe","subscriber","detectChanges","_branding","brandingIconUrl","selectors","FooterComponent","argBranding","argFooterLinks","_footerLinks","brandingBackgroundColor","onFooterLinkClick","e","preventDefault","console","log","AppComponent","loadMessages","deMessages","locale","PopupType","ResponseState","PopupService","popupInfo","_popupInfo","UtilityService","popupService","ProcessResponse","argResponse","oResponse","State","Data","content","type","UserController","argHttpClient","argUtilityService","Authenticate","argLoadingAnimationContainer","$Deferred","$","AuthenticateDataSource","then","undefined","resolve","reject","promise","post","withCredentials","argError","AuthenticationService","CurrentUser","_UserSubject","value","argUserController","Deferred","argUser","AppInitializer","argAuthenticationService","Promise","argResolve","JwtInterceptor","intercept","argRequest","argNext","oCurrentUser","AccessToken","clone","setHeaders","Authorization","handle","UIElementType","StringUtilsService","euroSuffix","percentageSuffix","convertYesNoStringToBoolean","yesNoString","toLowerCase","convertBooleanToYesNoString","booleanValue","returnedString","convertDateStringToDate","displayDateString","dateString","timeString","split","day","month","year","hour","minute","Date","parseInt","convertDateNumberToDate","displayDateNumber","convertDateToDateString","dateData","includeTime","displayValue","toLocaleDateString","concat","getHours","toString","getMinutes","convertTableCellDisplayNamesToValues","itemsString","items","chosenItemsDisplay","chosenItemsValue","forEach","chosenItemDisplay","chosenItem","find","item","DisplayName","push","Value","length","convertItemsArrayToItemsDisplayName","map","join","convertItemsArrayTableDisplayNamesToPDF","itemsInTableFormat","replaceAll","convertItemExcelDisplayNamesToTable","getMinAndMaxInPlausibilityRange","conditions","conditionsArray","minAndMaxObject","min","max","condition","indexOf","minAndMaxArray","startsWith","substring","formatNumberStringIntoValue","numberString","getNumberTextFormat","currency","percentage","decimalDigits","currencyFormat","percentageFormat","fourDigitsDecimalFormat","twoDigitsDecimalFormat","getNumberDisplayValue","elementType","numberValue","formatNumber","getNumberValueFromDisplayValue","numberDisplayValue","parseNumber","ExcelService","stringUtils","exportTableFromDataGrid","fileName","tableElements","cellBorder","top","style","color","argb","left","bottom","right","__webpack_require__","Excel","workbook","Workbook","wsData","addWorksheet","wsDefinitions","exportDataGrid","component","selectedRowsOnly","worksheet","customizeCell","options","gridCell","excelCell","columnLetter","_column","letter","rowType","j","cell","getCell","border","column","visibleIndex","IsRequired","fill","pattern","fgColor","DataType","dataValidation","allowBlank","formulae","Items","definitionCellYes","definitionCellNo","k","adjustColumnWidth","xlsx","writeBuffer","buffer","saveAs","Blob","cancel","importExcelToDataGrid","file","dxDataGrid","tableGatheredColumns","name","fileExtension","lastIndexOf","fileReader","FileReader","readAsText","Observable","onload","importResult","importCsvFile","result","error","Error","importedItems","readAsArrayBuffer","load","importXlsFile","throwError","headerColumns","rows","i","newItemValue","newItemDisplayValue","columns","dataGridColumn","columnsChildren","col","caption","tableElement","ElementID","dataField","dataType","getDate","UIElement","controlValues","displayValues","sheet","getWorksheet","eachRow","row","rowIndex","values","valueOf","controlValue","cellValue","text","String","lengths","v","maxLength","Math","filter","x","width","ValidationFunctionType","DateValidatorDirective","static","today","control","dateInTheFuture","ReceiptService","submittedReceiptData","_submittedReceiptData","receiptData","createReceiptData","formName","creationDate","Type","addEditElementValue","createTable","Rows","addTable","table","tableName","Table","createTableRow","Columns","addTableRowToTable","createAndAddTableCell","editTableCell","columnIndex","ReactiveFormService","fb","receiptService","stringUtilsService","getReactiveForm","_reactiveForm","hasValidationFields","_hasValidationFields","createAppReactiveForm","lastElementRendered","group","UntypedFormControl","modulesArray","array","initializeAppReactiveForm","argDataInput","get","setValue","PageTitel","Module","currentModule","moduleIndex","Layout","layoutItemsArray","generateLayoutItems","LayoutItems","Orientation","layoutItems","module","argLayoutItemTitle","horizontal","layoutItem","layoutItemTitle","Header","element","Elements","addFormControlForElement","Label","addFormGroupForTable","avoidSubmitting","belongsToTableId","label","formControlIndex","parentFormArray","getLayoutItemsArrayFromModuleNumber","elementFormControlIndex","controls","id","displayName","visible","validationMessages","createValidatorsListForElement","at","lastElementIdAdded","elementFormControl","addRequiredToFormControl","Validations","setFormHasValidationRules","validation","FunctionType","addValidators","validationFn","message","Message","Condition","Validators","isElementVisible","elementVisible","currentElementFormGroup","searchElementFormGrouplInReactiveFormByElementId","changeFormControlValue","newValue","controlFormGroup","tableId","ElementTableID","itemsArray","addRowToTable","data","key","elementTableId","property","rowEditFormElement","itemsFormArray","itemIndex","itemId","keysArray","rowAddFailingFields","applyInputValuesToRow","removeAt","getRowDisplayValues","editElements","searchTableEditElementFormGroupsByTableId","newItemDisplayValues","disabled","prepareEditRowData","keysFormArray","applyRowValuesToInput","rowKeysArrayWithValues","tableEditElemens","clearEditRowValuesFromTable","tableCellGroup","editElement","tableEditElement","editRowValuesFromTable","editedRowIndex","rowInputFormGroups","invalidInputs","input","valid","clear","elementGroup","deleteRowFromTable","deletedRowIndex","getTableCellFormGroup","tableElementID","cellFormGroup","elementId","isTable","foundFormGroup","moduleFormGroup","layoutItemGroup","foundEditElementGroups","searchTableEditElementFormGroupByElementIDAndTableId","elementTableID","elementID","foundInputFormGroup","formInputGroup","hideElementFormGroup","elementBelongsToTableId","formGroup","showElementFormGroup","enableElementValueFormControl","enable","disable","controlElementRequiredAttribute","required","deleteRequiredFromFormControl","actionTaken","hasValidator","formatMessage","removeValidators","vm","updateElementFormControlValue","notifyLastElementLoaded","notifyFormExit","packElementsOutputData","outputDataContainer","index","elementOutput","itemElementsOutputArray","receiptTable","keyElementsOutputArray","submitTableHeaders","receiptTableRow","submitTableRowCells","itemOutput","tableOutput","receiptTableHeadersRow","MAX_COLUMNS_IN_RECEIPT_TABLE","keyOutput","printingValue","ValidationSummaryService","createValidationMessagesForFormGroup","Object","keys","formFieldGrouplKey","formFieldErrors","errors","fieldValidationMessage","createSummaryError","createValidationMessagesForFormControlsAndNames","formControlNamesArray","formElement","formControl","elementValidationMessages","fieldError","m","ElementValidationService","formService","validationSummaryService","Subject","applyElementValidations","TargetElementID","applyValidation","prepareValueString","elementInputType","valuesString","prepareStringValue","transformedValue","triggerAction","isActionToBeTriggered","formElementChanged","functionType","cond","transformedCondition","replace","isInNegatedGroup","metCondition","endsWith","isConditionChosen","trim","updateValidationSummary","tableValidationMessages","setValidationSummaryForTableId","setValidationSummary","formControlsToBeValidated","elementValue","getValidationMessageForElementFormGroup","elementFormGroup","clearValidationSummaryForTable","tableEditElementsFormGroups","FormElementOperationsService","validationService","initializeValidation","inputValue","elementRenderingInformation","validationInformation","checkValue","processValueChangeValidation","inputDisplayValue","markAsTouched","Array","isArray","processElementChangeValidation","elementFunctionChangeInformation","updatedAfterOperation","updatedValueAfterOperation","validationMessage","TextEditComponent","elementOperations","inputFormGroup","renderingInformation","subscribeToElementChanges","valueChanged","enteredValue","elementChangeInfo","ctx","DateEditComponent","isValid","bind","fixedWidth","dateBoxWidth","dateBoxType","dateDisplayFormat","updateDateInputValue","updateDateDisplayValue","dateValue","event","ElementItemsSortMode","ItemService","sortItemsBySortAttribute","itemsToSort","itemsSortMode","sort","a","b","Sort","localeCompare","LookupEditComponent","itemService","checkBoxes","selectionMode","showCheckBoxesMode","elementItems","sortedItems","_selectedItem","getDisplayValue","selectedItem","onDropDownBoxValueChanged","updateSelection","treeView","instance","unselectAll","changeLookupEditValue","args","getSelectedNodeKeys","isDropDownBoxOpened","userSelectedItems","foundSelectedItem","elementItem","DxTreeViewComponent","ComboBoxEditComponent","itemsDataSource","DataSource","store","setInputFromValue","onCustomItemCreate","addCustomItem","customItem","customItemValue","newItem","createCustomItemValueFromDisplayValue","insert","catch","customItemDisplayName","changeComboBoxEditValue","CheckEditComponent","currentValue","labelEmbedded","embeddedLabelPosition","labelLeft","MathPowPipe","transform","exponent","pow","pure","NumberBoxComponent","numberDisplayFormat","ngAfterViewInit","Validator","numberBoxInstance","validate","LabelService","getLabelInformation","labelPosition","labelInformation","displayLabel","isLabelToBePrinted","labelClass","getLabelHtmlClass","LabelComponent","labelService","ComboBoxEditCheckboxesComponent","selectedItems","changeComboBoxValue","valuesArray","emitItems","LookupEditDatagridComponent","currentSelectedRowKeys","submitLookupEditValue","ListComponent","displaySelectAll","selectedValue","sortedItem","changeListSelection","selectedValues","selectedDisplayNames","newValueArray","TextWrapEditComponent","ctx_r3","ValidationSummaryComponent","navigateToId","scrollTarget","document","getElementById","scrollIntoView","behavior","block","inline","inputElements","getElementsByTagName","classList","contains","focus","FileUploaderComponent","selectFileText","dropFileText","acceptTypes","FileUploadExtensions","maxFileSize","FileUploadMaxSize","multiple","FileUploadMultiSelect","uploadedFiles","customizeUploadRequest","currentUser","request","setRequestHeader","submitUploadedFileInfo","submitAndValidate","deleteUploadedFile","previousValue","uploadedFile","errorSummaryMessages","newSelectedFiles","slice","filesUploadedCounter","selectedFile","alreadyUploadedFile","cancelButton","getElementsByClassName","cancelUploadClickEvent","Event","dispatchEvent","fileNames","FormElementGeneratorComponent","parentRootFormGroup","getElementFormGroup","PopupComponent","EventEmitter","popupIsVisible","popupInfoInput","closePopup","popupClosed","emit","FormLayoutGeneratorComponent","layout","formControlStructure","layoutGrid","createLayoutGrid","generateLayoutGrid","getLayoutGridColumns","returnColumnsNumber","columnsNumber","returnedColumnsNumber","parentGrid","nestedGrid","addLayoutGridContainerColumn","addLayoutItemHeader","layoutElementPairs","LabelPosition","addLabelLeftAndInputColumns","addLabelTopAndInputColumn","getElementByElementId","layoutItemElementId","elements","getLayoutItemByElementId","li","newLayoutGrid","siblingsNumber","layoutTitle","colSpan","cssClass","labelLayoutGridColumn","inputLayoutGridColumn","labelInputLayoutGridColumn","TableGeneratorComponent","excelService","icon","onClick","MouseEvent","bubbles","fileUploadButton","nativeElement","getTableForElement","tableLayout","tableFormGroup","tableTitle","getTableElements","gatheredTableElements","tableColumn","popupWrapperClass","prepareNewRow","_editTableRowKey","onRowAdd","__KEY__","onRowAdded","updateRowDisplay","dataElements","tableSubmit","prepareEditFields","getRowIndexByKey","onRowUpdate","onRowUpdated","forceUpdateDialog","changes","onRowRemove","getDataSource","findIndex","saveInputValueInCell","receivedValue","cellInfo","columnIsVisibleInTable","exportTable","gatheredElement","importTable","target","files","importInfo","validRows","failingColumns","currentTableRows","rowId","uuid","rowEditFailingFields","field","renderImportTableErrorPopup","splice","clearPopupInfo","isPopupClosed","extractElementsFromGatheredElements","el","tablesInModule","currentLayoutItem","foundTableElement","gatheredTableElement","rowValuesRecord","entries","val","HomePageComponent","keyCloakService","loginKeyCloak","_this","login","redirectUri","WebformTargetType","FormClientService","httpClient","getDataById","pipe","response","catchError","handleError","saveData","status","ViewStateDataService","getFormSuccess","_formSucess","setFormSuccess","formSuccess","FormGeneratorComponent","dataInput","generateForm","formSubmitted","receivedModules","dataInputId","Id","dataInputType","formElementsOutput","formDataReady","jCaptcha","require","FormPageComponent","argRoute","formClientService","argRouter","viewStateDataService","paramMap","argParams","inputId","dataInputResult","pageDescription","PageDescription","Branding","FooterLinks","toggleSummary","formLoaded","renderCaptcha","initCaptcha","renderGetDataPopup","formHasValidation","onSubmit","captcha","handleFormSubmit","submitFormData","formData","submitResult","navigate","dataSubmitResult","err","renderSaveDataPopup","clearDataInputPopupInfo","clearDataSubmitPopupInfo","captchaLabel","createElement","setAttribute","captchaInput","captchaRowDiv","append","captchaRowCol","captchaContainerRowDiv","appendChild","formContainer","canvasClass","canvasStyle","height","textBaseline","font","textAlign","fillStyle","callback","validationSuccess","targetType","isSummaryVisible","$localize","FileClientService","createPdf","receipts","responseType","ReceiptComponent","fileClient","onSavePdfClick","pdfRequestResult","createPdfResult","fileURL","URL","createObjectURL","window","open","revokeObjectURL","renderPdfExportErrorPopup","FormSuccessPageComponent","router","UserSessionService","_userSubject","user","UserClientService","authenticateUser","returnInfo","LoginPageComponent","userSessionService","userClient","loginForm","UntypedFormGroup","email","messages","currentUrlTree","parseUrl","url","queryParams","returnUrl","Buffer","from","updateValidationMessages","loginSubmit","authenticationInfo","navigateByUrl","KeycloakInitializer","keycloak","init","config","realm","clientId","initOptions","checkLoginIframe","AppModule","bootstrap","provide","APP_INITIALIZER","useFactory","multi","deps","KeycloakService","HTTP_INTERCEPTORS","useClass","UntypedFormBuilder","DatePipe","imports","BrowserModule","appId","BrowserTransferStateModule","HttpClientModule","FormsModule","ReactiveFormsModule","RouterModule","path","anchorScrolling","DxDropDownBoxModule","DxDateBoxModule","DxListModule","DxDataGridModule","DxTextBoxModule","DxToolbarModule","DxValidationSummaryModule","DxButtonModule","DxPopupModule","DxLoadIndicatorModule","DxSelectBoxModule","DxCheckBoxModule","DxNumberBoxModule","DxTreeViewModule","DxTagBoxModule","DxTextAreaModule","DxFileUploaderModule","DxValidatorModule","DxTooltipModule","KeycloakAngularModule","providers","getBaseUrl","href","environment","enableProdMode","__NgCli_bootstrap_1","bootstrapModule"],"sourceRoot":"webpack:///","sources":["./src/app/services/branding.service.ts","./src/app/components/header/header.component.html","./src/app/components/header/header.component.ts","./src/app/components/footer/footer.component.html","./src/app/components/footer/footer.component.ts","./src/app/app.component.ts","./src/app/app.component.html","./src/app/interfaces/enum/popup-type.ts","./src/app/interfaces/form/enums/response-state-enum.ts","./src/app/services/popup.service.ts","./src/app/services/Utility.Service.ts","./src/app/client/R23_Webforms.WebInterface.UserController.ts","./src/app/services/Authentication.Service.ts","./src/app/app.initializer.ts","./src/app/app.jwt-interceptor.ts","./src/app/interfaces/form/enums/uielement-type-enum.ts","./src/app/services/string-utils.service.ts","./src/app/services/excel.service.ts","./src/app/interfaces/form/enums/validation-function-type-enum.ts","./src/app/services/form/custom-validators/date-validator.directive.ts","./src/app/services/receipt.service.ts","./src/app/services/form/reactive-form.service.ts","./src/app/services/validation-summary.service.ts","./src/app/services/form/element-validation.service.ts","./src/app/services/form/form-element-operations.service.ts","./src/app/components/form/elements/text-edit/text-edit.component.ts","./src/app/components/form/elements/text-edit/text-edit.component.html","./src/app/components/form/elements/date-edit/date-edit.component.ts","./src/app/components/form/elements/date-edit/date-edit.component.html","./src/app/interfaces/form/enums/element-items-sort-mode-enum.ts","./src/app/services/item.service.ts","./src/app/components/form/elements/lookup-edit/lookup-edit.component.ts","./src/app/components/form/elements/lookup-edit/lookup-edit.component.html","./src/app/components/form/elements/combo-box-edit/combo-box-edit.component.ts","./src/app/components/form/elements/combo-box-edit/combo-box-edit.component.html","./src/app/components/form/elements/check-edit/check-edit.component.ts","./src/app/components/form/elements/check-edit/check-edit.component.html","./src/app/pipes/math-pow.pipe.ts","./src/app/components/form/elements/number-box/number-box.component.ts","./src/app/components/form/elements/number-box/number-box.component.html","./src/app/services/form/label.service.ts","./src/app/components/form/elements/label/label.component.html","./src/app/components/form/elements/label/label.component.ts","./src/app/components/form/elements/combo-box-edit-checkboxes/combo-box-edit-checkboxes.component.ts","./src/app/components/form/elements/combo-box-edit-checkboxes/combo-box-edit-checkboxes.component.html","./src/app/components/form/elements/lookup-edit-datagrid/lookup-edit-datagrid.component.ts","./src/app/components/form/elements/lookup-edit-datagrid/lookup-edit-datagrid.component.html","./src/app/components/form/elements/list/list.component.html","./src/app/components/form/elements/list/list.component.ts","./src/app/components/form/elements/text-wrap-edit/text-wrap-edit.component.ts","./src/app/components/form/elements/text-wrap-edit/text-wrap-edit.component.html","./src/app/components/validation-summary/validation-summary.component.html","./src/app/components/validation-summary/validation-summary.component.ts","./src/app/components/form/elements/file-uploader/file-uploader.component.html","./src/app/components/form/elements/file-uploader/file-uploader.component.ts","./src/app/components/form/form-element-generator/form-element-generator.component.html","./src/app/components/form/form-element-generator/form-element-generator.component.ts","./src/app/components/popup/popup.component.ts","./src/app/components/popup/popup.component.html","./src/app/components/form/form-layout-generator/form-layout-generator.component.html","./src/app/components/form/form-layout-generator/form-layout-generator.component.ts","./src/app/components/form/table-generator/table-generator.component.html","./src/app/components/form/table-generator/table-generator.component.ts","./src/app/pages/home-page/home-page.component.ts","./src/app/pages/home-page/home-page.component.html","./src/app/interfaces/form/enums/webform-target-type-enum.ts","./src/app/client/form-client.service.ts","./src/app/services/view-state-data.service.ts","./src/app/components/form/form-generator/form-generator.component.html","./src/app/components/form/form-generator/form-generator.component.ts","./src/app/pages/form-page/form-page.component.html","./src/app/pages/form-page/form-page.component.ts","./src/app/client/file-client.service.ts","./src/app/components/receipt/receipt.component.html","./src/app/components/receipt/receipt.component.ts","./src/app/pages/form-success-page/form-success-page.component.ts","./src/app/pages/form-success-page/form-success-page.component.html","./src/app/services/user-session.service.ts","./src/app/client/user-client.service.ts","./src/app/pages/login-page/login-page.component.html","./src/app/pages/login-page/login-page.component.ts","./src/app/keycloak.initializer.ts","./src/app/app.module.ts","./src/main.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\r\nimport { BehaviorSubject } from 'rxjs';\r\nimport { DomSanitizer, SafeStyle, SafeUrl, Title } from '@angular/platform-browser';\r\nimport { Branding } from '../interfaces/branding';\r\nimport { FooterLink } from '../interfaces/form/footer-link';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class BrandingService {\r\n\r\n constructor(private sanitizer: DomSanitizer, private argTitle: Title) { }\r\n\r\n public branding: BehaviorSubject = new BehaviorSubject(null);\r\n public footerLinks: BehaviorSubject = new BehaviorSubject(null);\r\n public title: BehaviorSubject = new BehaviorSubject('');\r\n\r\n\r\n /**\r\n * Sets the Branding in a subject field in this class, so the subscribers can access the Branding information once it is available.\r\n * @param branding\r\n */\r\n public setBranding(branding: Branding) {\r\n this.branding.next(branding);\r\n }\r\n\r\n /**\r\n * Sets the footer links in a subject field in this class, so the subscribers can access them when available.\r\n * @param branding\r\n */\r\n public setFooterLinks(footerLinks: FooterLink[]) {\r\n this.footerLinks.next(footerLinks);\r\n }\r\n\r\n /**\r\n * Sets the title in a subject field in this class, so the subscribers can access it once it is available.\r\n * @param branding\r\n */\r\n public setTitle(title: string) {\r\n this.title.next(title);\r\n }\r\n\r\n /**\r\n * Gets the background color associated to the branding information.\r\n */\r\n public obtainBrandingBackgroundColor(branding: Branding): SafeStyle {\r\n let backgroundStyle: SafeStyle = '';\r\n\r\n if (branding && branding.Color) {\r\n backgroundStyle = this.sanitizer.bypassSecurityTrustStyle('background-color: ' + branding.Color);\r\n }\r\n\r\n return backgroundStyle;\r\n }\r\n\r\n /**\r\n * Gets the Icon URL associated to the branding information.\r\n */\r\n public obtainBrandingIconUrl(branding: Branding): SafeUrl {\r\n let iconUrl: SafeUrl = '';\r\n\r\n if (branding && branding.Icon) {\r\n iconUrl = this.sanitizer.bypassSecurityTrustUrl('data:image/jpeg;base64,' + branding.Icon);\r\n }\r\n\r\n return iconUrl;\r\n }\r\n}\r\n","\r\n
\r\n
\r\n
\r\n
\r\n \r\n
\r\n \r\n \r\n \r\n {{branding.Name}} \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n","import { ChangeDetectorRef, Component, OnInit } from '@angular/core';\r\nimport { BrandingService } from '../../services/branding.service';\r\nimport { Branding } from '../../interfaces/branding';\r\n\r\n@Component({\r\n selector: 'app-header',\r\n templateUrl: './header.component.html',\r\n styleUrls: ['./header.component.less']\r\n})\r\n\r\n/**\r\n* Manages the information related to the header.\r\n*/\r\nexport class HeaderComponent implements OnInit {\r\n\r\n private _branding: Branding;\r\n\r\n constructor(private argChangeDetector: ChangeDetectorRef, private brandingService: BrandingService) { }\r\n\r\n /**\r\n * Init method with the subscribers to the branding information.\r\n */\r\n ngOnInit(): void {\r\n this.brandingService.branding.subscribe((subscriber) => {\r\n this.argChangeDetector.detectChanges();\r\n this._branding = subscriber;\r\n });\r\n }\r\n\r\n\r\n // Getter method of branding.\r\n get branding(): Branding {\r\n return this._branding;\r\n }\r\n\r\n /**\r\n * Gets the Icon URL associated to the branding information.\r\n */\r\n public get brandingIconUrl() {\r\n return this.brandingService.obtainBrandingIconUrl(this._branding);\r\n }\r\n}\r\n","\r\n \r\n\r\n","import { ChangeDetectorRef, Component, OnInit } from '@angular/core';\r\nimport { BrandingService } from '../../services/branding.service';\r\nimport { Branding } from '../../interfaces/branding';\r\nimport { FooterLink } from '../../interfaces/form/footer-link';\r\n\r\n@Component({\r\n selector: 'app-footer',\r\n templateUrl: './footer.component.html',\r\n styleUrls: ['./footer.component.less']\r\n})\r\n\r\n/**\r\n* Manages the information related to the footer.\r\n*/\r\nexport class FooterComponent implements OnInit {\r\n\r\n public _footerLinks: FooterLink[];\r\n private _branding: Branding;\r\n\r\n constructor(private argChangeDetector: ChangeDetectorRef, private brandingService: BrandingService) { }\r\n\r\n /**\r\n * Init method with the subscribers to the branding information.\r\n */\r\n ngOnInit(): void {\r\n this.brandingService.branding.subscribe((argBranding) => {\r\n this.argChangeDetector.detectChanges();\r\n this._branding = argBranding;\r\n });\r\n this.brandingService.footerLinks.subscribe((argFooterLinks) => {\r\n this.argChangeDetector.detectChanges();\r\n this._footerLinks = argFooterLinks;\r\n });\r\n }\r\n\r\n\r\n // Getter method of branding.\r\n get branding(): Branding {\r\n return this._branding;\r\n }\r\n\r\n // Getter method of footer links.\r\n get footerLinks(): FooterLink[] {\r\n return this._footerLinks;\r\n }\r\n\r\n /**\r\n * Gets the background color associated to the branding information.\r\n */\r\n public get brandingBackgroundColor() {\r\n return this.brandingService.obtainBrandingBackgroundColor(this._branding);\r\n }\r\n\r\n /**\r\n * Handles the event of clicking in a footer link.\r\n * @param e with the click event\r\n */\r\n public onFooterLinkClick(e: Event) {\r\n e.preventDefault();\r\n console.log(e);\r\n }\r\n\r\n}\r\n","import { ChangeDetectorRef, Component, OnInit } from '@angular/core';\r\nimport { Title } from '@angular/platform-browser';\r\n// Dictionaries for German language\r\nimport deMessages from \"devextreme/localization/messages/de.json\";\r\nimport { locale, loadMessages } from \"devextreme/localization\";\r\nimport { BrandingService } from './services/branding.service';\r\n\r\n@Component({\r\n selector: 'app-root',\r\n templateUrl: './app.component.html'\r\n})\r\nexport class AppComponent implements OnInit {\r\n\r\n\r\n constructor(private brandingService: BrandingService, private argChangeDetector: ChangeDetectorRef, private argTitle: Title) {\r\n loadMessages(deMessages);\r\n //locale(navigator.language);\r\n locale(\"de\");\r\n }\r\n\r\n public ngOnInit() {\r\n this.brandingService.title.subscribe((argTitle) => {\r\n this.argChangeDetector.detectChanges();\r\n this.argTitle.setTitle(argTitle);\r\n });\r\n }\r\n}\r\n","
\r\n \r\n
\r\n
\r\n \r\n
\r\n
\r\n \r\n
\r\n","export enum PopupType {\r\n INFO = \"info\",\r\n ERROR = \"error\",\r\n CONFIRMATIN = \"confirmation\",\r\n}\r\n","export enum ResponseState {\r\n Success = 0,\r\n Info = 1,\r\n Warning = 3,\r\n Error = 4,\r\n}","import { Injectable } from \"@angular/core\";\r\nimport { PopupInfo } from \"../interfaces/popup-info\";\r\n\r\n/**\r\n * This service contains the data and methods needed by the popup component.\r\n */\r\n@Injectable()\r\nexport class PopupService {\r\n\r\n private _popupInfo: PopupInfo;\r\n\r\n get popupInfo(): PopupInfo {\r\n return this._popupInfo;\r\n }\r\n\r\n set popupInfo(popupInfo: PopupInfo) {\r\n this._popupInfo = popupInfo;\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { ResponseState } from '../interfaces/form/enums/response-state-enum';\r\nimport { PopupService } from './popup.service';\r\nimport { PopupType } from '../interfaces/enum/popup-type';\r\n\r\n@Injectable()\r\nexport class UtilityService {\r\n\r\n constructor(private popupService: PopupService) {\r\n }\r\n\r\n public ProcessResponse(argResponse: R23_Webforms.Model.General.Response): T {\r\n let oResponse: T;\r\n\r\n if (argResponse != null) {\r\n switch (argResponse.State) {\r\n case ResponseState.Success:\r\n oResponse = argResponse.Data;\r\n break;\r\n case ResponseState.Info:\r\n //this.argWindowService.Info('Info', argResponse.Message);\r\n oResponse = argResponse.Data;\r\n break;\r\n case ResponseState.Error:\r\n this.popupService.popupInfo = { title: 'Access denied', content: 'Es ist ein technisches Problem aufgetreten. Bitte wenden Sie sich an Ihren Ansprechpartner.', type: PopupType.ERROR };\r\n break;\r\n default:\r\n break;\r\n }\r\n }\r\n\r\n return oResponse;\r\n }\r\n}\r\n","\r\nimport { HttpClient } from \"@angular/common/http\";\r\nimport { Injectable } from \"@angular/core\";\r\nimport { UtilityService } from \"../services/Utility.Service\";\r\nimport { PopupService } from \"../services/popup.service\";\r\nimport { PopupType } from \"../interfaces/enum/popup-type\";\r\nimport * as $ from 'jquery';\r\n\r\n@Injectable()\r\n export class UserController {\r\n\r\n constructor(private argHttpClient: HttpClient, private argUtilityService: UtilityService, private popupService: PopupService) { }\r\n \r\n public Authenticate(argLoadingAnimationContainer: JQuery | null = null): JQueryPromise {\r\n const $Deferred = $.Deferred();\r\n \r\n this.AuthenticateDataSource(argLoadingAnimationContainer).then((argResponse) => {\r\n const oResponse = this.argUtilityService.ProcessResponse(argResponse);\r\n \r\n if (oResponse !== undefined) {\r\n $Deferred.resolve(oResponse);\r\n } else {\r\n $Deferred.reject();\r\n }\r\n });\r\n \r\n return $Deferred.promise();\r\n }\r\n \r\n public AuthenticateDataSource(argLoadingAnimationContainer: JQuery | null = null): JQueryPromise> {\r\n const $Deferred = $.Deferred>();\r\n \r\n \r\n \r\n this.argHttpClient.post>(`api/User/Authenticate`, {}, { withCredentials: true }).subscribe((argResponse) => {\r\n \r\n const oResponse = argResponse;\r\n \r\n if (oResponse !== undefined && oResponse !== null) {\r\n $Deferred.resolve(oResponse);\r\n } else {\r\n $Deferred.reject();\r\n }\r\n }, (argError) => {\r\n \r\n switch (argError.status) {\r\n case 401:\r\n case 403:\r\n this.popupService.popupInfo = { title: 'Access denied', content: 'Es ist ein technisches Problem aufgetreten. Bitte wenden Sie sich an Ihren Ansprechpartner.', type: PopupType.ERROR };\r\n break;\r\n default:\r\n this.popupService.popupInfo = { title: 'Access denied', content: 'Es ist ein technisches Problem aufgetreten. Bitte wenden Sie sich an Ihren Ansprechpartner.', type: PopupType.ERROR };\r\n break;\r\n }\r\n });\r\n \r\n return $Deferred.promise();\r\n }\r\n \r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { BehaviorSubject } from 'rxjs';\r\nimport { UserController } from '../client/R23_Webforms.WebInterface.UserController';\r\n\r\n@Injectable()\r\nexport class AuthenticationService {\r\n // Private properties\r\n private _RefreshTokenTimeout: NodeJS.Timeout;\r\n private _UserSubject: BehaviorSubject;\r\n\r\n // Public properties\r\n public get CurrentUser(): R23_Webforms.Model.Membership.User | null {\r\n return this._UserSubject.value;\r\n }\r\n\r\n constructor(private argUserController: UserController) {\r\n this._UserSubject = new BehaviorSubject(null);\r\n }\r\n\r\n public Authenticate() {\r\n const $Deferred = $.Deferred();\r\n\r\n this.argUserController.Authenticate().then((argUser) => {\r\n this._UserSubject.next(argUser);\r\n\r\n $Deferred.resolve();\r\n });\r\n\r\n return $Deferred.promise();\r\n }\r\n\r\n //public Login(argUserLogin: R23_Webforms.Model.Membership.UserLogin, argLoadingAnimationContainer: JQuery | null = null) {\r\n // var $Deferred = $.Deferred();\r\n\r\n // var oRequest: R23_Webforms.Model.General.Request = {\r\n // Data: argUserLogin\r\n // };\r\n\r\n // this.argUserController.Login(oRequest, argLoadingAnimationContainer).then((argUser) => {\r\n // this._UserSubject.next(argUser);\r\n // this.StartRefreshTokenTimer();\r\n\r\n // $Deferred.resolve();\r\n // });\r\n\r\n // return $Deferred.promise();\r\n //}\r\n\r\n //public Logout(argLoadingAnimationContainer: JQuery | null = null) {\r\n // var $Deferred = $.Deferred();\r\n\r\n // this.argUserController.Logout(argLoadingAnimationContainer).then((argResponse) => {\r\n // this.StopRefreshTokenTimer();\r\n // this._UserSubject.next(null);\r\n\r\n // $Deferred.resolve();\r\n // });\r\n\r\n // return $Deferred.promise();\r\n //}\r\n\r\n //public RefreshToken(argLoadingAnimationContainer: JQuery | null = null) {\r\n // var $Deferred = $.Deferred();\r\n\r\n // this.argUserController.RefreshAccessToken(argLoadingAnimationContainer).then((argUser) => {\r\n // this._UserSubject.next(argUser);\r\n // this.StartRefreshTokenTimer();\r\n\r\n // $Deferred.resolve();\r\n // });\r\n\r\n // return $Deferred.promise();\r\n //}\r\n\r\n // Helper methods\r\n //private StartRefreshTokenTimer() {\r\n // if (this.CurrentUser != null && this.CurrentUser.AccessToken != null) {\r\n // const oAccessToken = JSON.parse(atob(this.CurrentUser.AccessToken.split('.')[1]));\r\n\r\n // // Set a timeout to refresh the token a minute before it expires\r\n // const oDateExpire = new Date(oAccessToken.exp * 1000);\r\n // const iTimeout = oDateExpire.getTime() - Date.now() - (60 * 1000);\r\n // this._RefreshTokenTimeout = setTimeout(() => this.RefreshToken(), iTimeout);\r\n // }\r\n //}\r\n\r\n //private StopRefreshTokenTimer() {\r\n // clearTimeout(this._RefreshTokenTimeout);\r\n //}\r\n}\r\n","import { AuthenticationService } from \"./services/Authentication.Service\";\r\n\r\nexport function AppInitializer(argAuthenticationService: AuthenticationService) {\r\n return () => new Promise((argResolve: any) => {\r\n // Attempt to refresh token on app start up to auto authenticate\r\n argAuthenticationService.Authenticate().then(() => {\r\n argResolve();\r\n });\r\n });\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';\r\nimport { Observable } from 'rxjs';\r\nimport { AuthenticationService } from './services/Authentication.Service';\r\n\r\n@Injectable()\r\nexport class JwtInterceptor implements HttpInterceptor {\r\n constructor(private argAuthenticationService: AuthenticationService) { }\r\n\r\n public intercept(argRequest: HttpRequest, argNext: HttpHandler): Observable> {\r\n // Add auth header with jwt if user is logged in\r\n const oCurrentUser = this.argAuthenticationService.CurrentUser;\r\n\r\n if (oCurrentUser && oCurrentUser.AccessToken) {\r\n argRequest = argRequest.clone({\r\n setHeaders: {\r\n Authorization: 'Bearer ' + oCurrentUser.AccessToken\r\n }\r\n });\r\n }\r\n\r\n return argNext.handle(argRequest);\r\n }\r\n}\r\n","export enum UIElementType {\r\n none = 0,\r\n TextEdit = 1,\r\n CheckEditLeftLabel = 2,\r\n DateEdit = 3,\r\n MemoEdit = 4,\r\n ComboBoxEdit = 5,\r\n LookupEdit = 6,\r\n TextWrapEdit = 7,\r\n ICD10Catalog = 8,\r\n ListBoxCheckBoxes = 9,\r\n Label = 10,\r\n Separator = 11,\r\n Table = 12,\r\n CheckEditRightLabel = 13,\r\n Link = 15,\r\n LookupEditTree = 16,\r\n LookupEditTreeCheckBoxes = 17,\r\n FunctionButton = 18,\r\n AutoID = 19,\r\n ComboBoxEditCheckBoxes = 20,\r\n LabelUnderlineRightAlignment = 21,\r\n Map = 22,\r\n Calculated = 23,\r\n DateEditFixedWidth = 24,\r\n ListBoxCheckBoxesWithAllSelect = 25,\r\n ListBoxCheckBoxesWithSearch = 26,\r\n LookupEditWithSearch = 27,\r\n Currency = 28,\r\n DecimalScale2 = 29,\r\n LookupEditShowValue = 30,\r\n LookupEditExtValueAndDisplayName = 31,\r\n DecimalScale4 = 32,\r\n Percent = 33,\r\n CheckEditRightLabelDescription = 34,\r\n DateEditWithTime = 35,\r\n FileUpload = 38\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Item } from '../interfaces/form/item'\r\nimport { UIElementType } from '../interfaces/form/enums/uielement-type-enum';\r\nimport { formatNumber, parseNumber } from 'devextreme/localization';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\n\r\n/**\r\n * This class is meant to contain string related operations that may be useful in the code overall.\r\n * Please, add here all the operations that are added to the code related to strings.\r\n */\r\nexport class StringUtilsService {\r\n\r\n public readonly euroSuffix = \" €\";\r\n public readonly percentageSuffix = \" %\";\r\n public readonly currencyFormat = \"#,###.##\" + this.euroSuffix;\r\n public readonly percentageFormat = \"#,###.##\" + this.percentageSuffix;\r\n public readonly fourDigitsDecimalFormat = \"#,###.####\";\r\n public readonly twoDigitsDecimalFormat = \"#,###.##\";\r\n\r\n /**\r\n * Converts a string stating yes or no to a boolean. This is useful\r\n * for converting presentation data to form logic.\r\n * @param yesNoString\r\n * @returns\r\n */\r\n convertYesNoStringToBoolean(yesNoString: string): boolean {\r\n if (yesNoString.toLowerCase() === 'true' || yesNoString.toLowerCase() === 'ja' || yesNoString.toLowerCase() === '1') {\r\n return true;\r\n } else {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Converts a booelan to a string stating yes or no. This is useful\r\n * for converting form logic to presentation data.\r\n * \r\n * @param booleanValue\r\n * @returns\r\n */\r\n convertBooleanToYesNoString(booleanValue: boolean): string {\r\n let returnedString = \"Nein\";\r\n if (booleanValue) {\r\n returnedString = \"Ja\";\r\n }\r\n return returnedString;\r\n }\r\n\r\n /**\r\n * Converts a string representing a date with or without time to an object that can be\r\n * used in date edit fields.\r\n * @param displayDateString\r\n */\r\n convertDateStringToDate(displayDateString: string): Date {\r\n const [dateString, timeString] = displayDateString.split(' ');\r\n const [day, month, year]: string[] = dateString.split('.');\r\n let hour, minute: string;\r\n if (timeString) {\r\n [hour, minute] = timeString.split(':');\r\n }\r\n\r\n return new Date(+year, +month - 1, +day, timeString ? parseInt(hour) : 0, timeString ? +minute : 0, 0, 0);\r\n }\r\n\r\n /**\r\n * Converts a number representing a date with or without time to an object that can be\r\n * used in date edit fields.\r\n * @param displayDateString\r\n */\r\n convertDateNumberToDate(displayDateNumber: number): Date {\r\n return new Date(displayDateNumber);\r\n }\r\n\r\n\r\n /**\r\n * Converts a date (and optionally time) object into a representable string\r\n * in German format.\r\n * @param dateData with the date to be converted\r\n * @param includeTime stating if the time of the day has to be included in the string\r\n */\r\n convertDateToDateString(dateData: Date, includeTime: boolean): string {\r\n let displayValue: string = dateData.toLocaleDateString(\"DE\", {\r\n day: '2-digit',\r\n month: '2-digit',\r\n year: 'numeric'\r\n });\r\n if (includeTime) {\r\n displayValue = displayValue.concat(\" \").concat(dateData.getHours().toString()).concat(\":\").concat(dateData.getMinutes().toString());\r\n }\r\n return displayValue;\r\n }\r\n\r\n /**\r\n * Converts a string containing the names of the chosen items of an element\r\n * in a table cell to a string containing the chosen items values.\r\n * @param itemsString\r\n * @param items\r\n * @returns\r\n */\r\n convertTableCellDisplayNamesToValues(itemsString: string, items: Item[]): string[] {\r\n const chosenItemsDisplay: string[] = itemsString.split(\" | \");\r\n const chosenItemsValue: string[] = [];\r\n if (chosenItemsDisplay) {\r\n chosenItemsDisplay.forEach((chosenItemDisplay) => {\r\n const chosenItem = items.find((item) => item.DisplayName === chosenItemDisplay);\r\n if (chosenItem) { \r\n chosenItemsValue.push(chosenItem.Value);\r\n }\r\n })\r\n }\r\n if (chosenItemsValue.length) {\r\n // Angular needs to wrap array values for form controls into another array for not\r\n // confusing the array values with form group initialization\r\n return chosenItemsValue;\r\n } else {\r\n return [];\r\n }\r\n }\r\n\r\n /**\r\n * Converts an array of items into a display ready string suitable for the cells in the table elements.\r\n * @param items\r\n * @returns\r\n */\r\n convertItemsArrayToItemsDisplayName(items: Item[]): string {\r\n if (items.length) {\r\n return items.map((item) => { return item.DisplayName }).join(\"
\");\r\n } else {\r\n return \"\";\r\n }\r\n }\r\n\r\n /**\r\n * Converts a string containing the selected items of a selection input element from the table\r\n * format to the PDF format.\r\n * @param itemsInTableFormat\r\n * @returns\r\n */\r\n convertItemsArrayTableDisplayNamesToPDF(itemsInTableFormat: string): string {\r\n return itemsInTableFormat.replaceAll(\"
\", \"\\n\")\r\n }\r\n\r\n /**\r\n * Converts a string containing the selected items of a selection input element from the excel\r\n * format to the display table format.\r\n * @param itemsInTableFormat\r\n * @returns\r\n */\r\n convertItemExcelDisplayNamesToTable(itemsInTableFormat: string): string {\r\n return itemsInTableFormat.replaceAll(\" | \", \"
\");\r\n }\r\n\r\n /**\r\n * Extracts the minimum and maximum number conditions out of a plausibility range available in the conditions\r\n * attribute of a PlausiRange validator.\r\n * @param condition\r\n */\r\n getMinAndMaxInPlausibilityRange(conditions: string): { min: number, max: number } {\r\n const conditionsArray = conditions.split(\",\");\r\n const minAndMaxObject: { min: number, max: number } = { min: null, max: null };\r\n conditionsArray.forEach((condition) => {\r\n if (condition.indexOf(\"-\") != -1) {\r\n const minAndMaxArray = condition.split(\"-\");\r\n minAndMaxObject.min = +minAndMaxArray[0];\r\n minAndMaxObject.max = +minAndMaxArray[1]\r\n } else if (condition.startsWith(\">\")) {\r\n minAndMaxObject.min = +condition.substring(condition.indexOf(\">\") + 1);\r\n } else if (condition.startsWith(\"<\")){\r\n minAndMaxObject.max = +condition.substring(condition.indexOf(\"<\") + 1);\r\n }\r\n });\r\n return minAndMaxObject;\r\n }\r\n\r\n\r\n /**\r\n * For currency and percentage fields, deletes the units suffix (with\r\n * the € and the % symbols) so the value for the elemenent input don't contain it.\r\n * @param stringNumber\r\n */\r\n public formatNumberStringIntoValue(numberString: string): string {\r\n if (numberString.indexOf(this.euroSuffix) !== -1) {\r\n return numberString.substring(0, numberString.indexOf(this.euroSuffix));\r\n } else if (numberString.indexOf(this.percentageSuffix) !== -1) {\r\n return numberString.substring(0, numberString.indexOf(this.percentageSuffix));\r\n } else {\r\n return numberString;\r\n }\r\n }\r\n\r\n /**\r\n * Returns a format in which the number has to be formatted, depending on the input element type.\r\n * @param currency boolean stating whether the currency symbol must be printed or not\r\n * @param percentage boolean stating whether the percentage symbol must be printed or not\r\n * @param decimalDigits number stating whether the decimal numbers are 2 or 4\r\n * @returns formatting string ready for setting as display value and being performed by formatNumber() devextreme localization\r\n */\r\n public getNumberTextFormat(currency: boolean, percentage: boolean, decimalDigits: number): string {\r\n if (currency) {\r\n return this.currencyFormat;\r\n } else if (percentage) {\r\n return this.percentageFormat;\r\n } else if (decimalDigits == 4) {\r\n return this.fourDigitsDecimalFormat;\r\n } else if (decimalDigits == 2) {\r\n return this.twoDigitsDecimalFormat;\r\n } else {\r\n return this.twoDigitsDecimalFormat;\r\n }\r\n }\r\n\r\n /**\r\n *\r\n * Formats a number ready for the dxDataGrid component. The result is meant to be used as display value.\r\n * @param elementType UIElementType\r\n * @param numberValue\r\n * @returns displayValue of the number.\r\n */\r\n public getNumberDisplayValue(elementType: UIElementType, numberValue: number):string {\r\n const decimalDigits = UIElementType.DecimalScale4 ? 4 : UIElementType.DecimalScale2 ? 2 : null;\r\n return formatNumber(numberValue, this.getNumberTextFormat(\r\n elementType === UIElementType.Currency,\r\n elementType === UIElementType.Percent,\r\n decimalDigits)\r\n );\r\n }\r\n\r\n /**\r\n * Gets the value of a number form a dxDataGrid ready string.\r\n * @param elementType\r\n * @param numberDisplayValue\r\n * @returns\r\n */\r\n public getNumberValueFromDisplayValue(elementType: UIElementType, numberDisplayValue: string): number {\r\n const decimalDigits = UIElementType.DecimalScale4 ? 4 : UIElementType.DecimalScale2 ? 2 : null;\r\n return parseNumber(numberDisplayValue, this.getNumberTextFormat(\r\n elementType === UIElementType.Currency,\r\n elementType === UIElementType.Percent,\r\n decimalDigits));\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Observable, throwError } from 'rxjs';\r\nimport { ExportingEvent } from 'devextreme/ui/data_grid';\r\nimport { saveAs } from 'file-saver';\r\nimport { exportDataGrid } from 'devextreme/excel_exporter';\r\nimport { Element } from '../interfaces/form/element';\r\nimport { DxDataGridComponent } from 'devextreme-angular';\r\nimport { DxiColumnComponent } from 'devextreme-angular/ui/nested';\r\nimport { PopupInfo } from '../interfaces/popup-info';\r\nimport { PopupType } from '../interfaces/enum/popup-type';\r\nimport { StringUtilsService } from './string-utils.service';\r\nimport { PopupService } from './popup.service';\r\nimport { CellHyperlinkValue, CellValue, Row, Workbook } from 'exceljs';\r\nimport { UIElementType } from '../interfaces/form/enums/uielement-type-enum';\r\n\r\ntype ImportResult = {\r\n popupInfo: PopupInfo;\r\n importedItems: { controlValues: Record, displayValues: Record }[];\r\n}\r\n\r\n/**\r\n * Contains the tools necessary for working with excel sheets.\r\n */\r\n@Injectable()\r\nexport class ExcelService {\r\n\r\n constructor(private stringUtils: StringUtilsService, private popupService: PopupService) { }\r\n\r\n /**\r\n * Exports an excel sheet from a DxDataGrid element.\r\n * @param e\r\n * @param fileName: exported file name\r\n * @param tableElements with an Element array conforming the columns of the table to export\r\n */\r\n public exportTableFromDataGrid(e: ExportingEvent, fileName: string, tableElements: Element[]) {\r\n const cellBorder: any = {\r\n top: { style: 'thin', color: { argb: 'BDD7EE' } },\r\n left: { style: 'thin', color: { argb: 'BDD7EE' } },\r\n bottom: { style: 'thin', color: { argb: 'BDD7EE' } },\r\n right: { style: 'thin', color: { argb: 'BDD7EE' } }\r\n }\r\n import('exceljs').then((Excel) => {\r\n const workbook = new Excel.Workbook();\r\n const wsData = workbook.addWorksheet('Eingabeblatt');\r\n const wsDefinitions = workbook.addWorksheet('Definitionen');\r\n\r\n exportDataGrid({\r\n component: e.component,\r\n selectedRowsOnly: true,\r\n worksheet: wsData,\r\n customizeCell: function (options) {\r\n const { gridCell, excelCell } = options;\r\n const columnLetter = excelCell._column.letter;\r\n\r\n if (gridCell.rowType === 'header') {\r\n for (let j = 2; j < 202; j++) {\r\n const cell = wsData.getCell(columnLetter + j);\r\n cell.border = cellBorder;\r\n\r\n if (tableElements[gridCell.column.visibleIndex].IsRequired) {\r\n const cellFill: any = {\r\n type: 'pattern',\r\n pattern: 'solid',\r\n fgColor: { argb: 'FFFFCC' }\r\n };\r\n\r\n cell.fill = cellFill;\r\n }\r\n\r\n // Boolean\r\n if (tableElements[gridCell.column.visibleIndex].DataType === 'System.Boolean') {\r\n cell.dataValidation = {\r\n type: 'list',\r\n allowBlank: true,\r\n formulae: ['=Definitionen!$' + columnLetter + '$2:$' + columnLetter + '$' + 3]\r\n };\r\n }\r\n\r\n // Dropdownlist\r\n if (tableElements[gridCell.column.visibleIndex].Items && tableElements[gridCell.column.visibleIndex].Items.length > 0) {\r\n cell.dataValidation = {\r\n type: 'list',\r\n allowBlank: true,\r\n formulae: ['=Definitionen!$' + columnLetter + '$2:$' + columnLetter + '$' + (tableElements[gridCell.column.visibleIndex].Items.length + 1)]\r\n };\r\n }\r\n }\r\n }\r\n },\r\n }).then(() =>\r\n exportDataGrid({\r\n component: e.component,\r\n selectedRowsOnly: true,\r\n worksheet: wsDefinitions,\r\n customizeCell: function (options) {\r\n const { gridCell, excelCell } = options;\r\n\r\n if (gridCell.rowType === 'header') {\r\n excelCell.fill = { fgColor: { argb: 'F2F2F2' }, type: 'pattern', pattern: 'solid' };\r\n // Boolean\r\n if (tableElements[gridCell.column.visibleIndex].DataType === 'System.Boolean') {\r\n const columnLetter = excelCell._column.letter;\r\n // Set data for dropdownlist\r\n const definitionCellYes = wsDefinitions.getCell(columnLetter + 2);\r\n const definitionCellNo = wsDefinitions.getCell(columnLetter + 3);\r\n\r\n definitionCellYes.value = 'Ja';\r\n definitionCellNo.value = 'Nein';\r\n }\r\n // Menu edit element with several options\r\n else if (tableElements[gridCell.column.visibleIndex].Items && tableElements[gridCell.column.visibleIndex].Items.length > 0) {\r\n const columnLetter = excelCell._column.letter;\r\n // Set data for dropdownlist\r\n for (let k = 0; k < tableElements[gridCell.column.visibleIndex].Items.length; k++) {\r\n const item = tableElements[gridCell.column.visibleIndex].Items[k];\r\n const definitionCell = wsDefinitions.getCell(columnLetter + (k + 2));\r\n\r\n definitionCell.value = item.DisplayName;\r\n }\r\n }\r\n }\r\n excelCell.border = cellBorder;\r\n },\r\n })\r\n ).then(() => {\r\n this.adjustColumnWidth(wsData);\r\n this.adjustColumnWidth(wsDefinitions);\r\n workbook.xlsx.writeBuffer()\r\n .then(function (buffer: BlobPart) {\r\n\r\n saveAs(new Blob([buffer], { type: 'application/octet-stream' }), fileName.toString());\r\n })\r\n });\r\n })\r\n\r\n\r\n\r\n e.cancel = true;\r\n }\r\n\r\n /**\r\n * Imports a valid excel sheet into a datagrid.\r\n * @param file with the event uploaded file\r\n * @param dxDataGrid with the dxDataGrid to export the file to\r\n * @param tableGatheredColumns with the array of the elements that belong to the columns of the table\r\n * @return ImportResult object with the info for popups and/or the imported items\r\n */\r\n public importExcelToDataGrid(file: File, dxDataGrid: DxDataGridComponent, tableGatheredColumns: Element[]): Observable<{ controlValues: Record, displayValues: Record }[]> {\r\n const fileName = file.name;\r\n const fileExtension = fileName.substring(fileName.lastIndexOf('\\\\') + 1).split('.')[1];\r\n const fileReader = new FileReader();\r\n if (fileExtension === 'csv') {\r\n fileReader.readAsText(file);\r\n return new Observable((subscriber): void => {\r\n fileReader.onload = ((): void => {\r\n const importResult: ImportResult = this.importCsvFile(fileReader.result, dxDataGrid, tableGatheredColumns);\r\n if (importResult.popupInfo) {\r\n this.popupService.popupInfo = importResult.popupInfo;\r\n subscriber.error(new Error(\"Error importing table\"));\r\n }\r\n subscriber.next(importResult.importedItems);\r\n })\r\n })\r\n } else if (fileExtension === 'xls' || fileExtension === 'xlsx') {\r\n fileReader.readAsArrayBuffer(file);\r\n return new Observable((subscriber): void => {\r\n fileReader.onload = ((): void => {\r\n const buffer: ArrayBuffer = fileReader.result;\r\n import('exceljs').then((Excel) => {\r\n const wb = new Excel.Workbook();\r\n wb.xlsx.load(buffer).then((workbook: Workbook) => {\r\n const importResult = this.importXlsFile(workbook, dxDataGrid, tableGatheredColumns);\r\n if (importResult.popupInfo) {\r\n this.popupService.popupInfo = importResult.popupInfo;\r\n subscriber.error(new Error(\"Error importing table\"));\r\n }\r\n subscriber.next(importResult.importedItems);\r\n })\r\n })\r\n\r\n\r\n })\r\n })\r\n } else {\r\n this.popupService.popupInfo = { title: \"CSV-Import\", content: \"Es wurden keine Daten zum Importieren gefunden.\", type: PopupType.ERROR }\r\n return throwError(() => \"Error importing table\");\r\n }\r\n\r\n }\r\n\r\n\r\n\r\n /**\r\n * Imports a CSV file into a datagrid.\r\n * @param buffer with the readed information of the CSV file\r\n * @param dxDataGrid with the dxDataGrid element to export the file to\r\n * @param tableGatheredColumns with the array of the elements that belong to the columns of the table\r\n * @return array of imported items\r\n */\r\n private importCsvFile(buffer: string | ArrayBuffer, dxDataGrid: DxDataGridComponent, tableGatheredColumns: Element[]): ImportResult {\r\n const importedItems: { controlValues: Record, displayValues: Record }[] = [];\r\n let popupInfo: PopupInfo;\r\n let headerColumns: string[] = [];\r\n const rows = (buffer as string).split(\"\\r\\n\");\r\n if (rows.length > 1) {\r\n // Collect header columns\r\n headerColumns = rows[0].split(\";\");\r\n for (let i = 1; i < rows.length; i++) {\r\n let newItemValue: Record = {};\r\n let newItemDisplayValue: Record = {};\r\n const row = rows[i];\r\n const columns = row.split(\";\");\r\n if (columns.length !== headerColumns.length) {\r\n continue;\r\n }\r\n for (let j = 0; j < columns.length; j++) {\r\n const column = columns[j];\r\n\r\n const dataGridColumn: DxiColumnComponent = dxDataGrid.columnsChildren.find((col) => col.caption == headerColumns[j]);\r\n if (dataGridColumn) {\r\n const tableElement = tableGatheredColumns.find((tableElement) => tableElement.ElementID == dataGridColumn.dataField);\r\n\r\n const dataField = dataGridColumn.dataField;\r\n const dataType = dataGridColumn.dataType;\r\n newItemDisplayValue[dataField] = this.stringUtils.convertItemExcelDisplayNamesToTable(column);\r\n if (column) {\r\n if (tableElement.Items) {\r\n //Case of elements where an item (or several) can be chosen\r\n newItemValue[dataField] = this.stringUtils.convertTableCellDisplayNamesToValues(column, tableElement.Items);\r\n } else {\r\n switch (dataType) {\r\n case 'System.Boolean':\r\n newItemValue[dataField] = this.stringUtils.convertYesNoStringToBoolean(column);\r\n break;\r\n\r\n case 'System.DateTime':\r\n\r\n if (this.stringUtils.convertDateStringToDate(column).getDate()) {\r\n newItemValue[dataField] = this.stringUtils.convertDateStringToDate(column);\r\n }\r\n break;\r\n case 'System.Decimal':\r\n newItemValue[dataField] = this.stringUtils.getNumberValueFromDisplayValue(tableElement.UIElement, column);\r\n newItemDisplayValue[dataField] = this.stringUtils.getNumberDisplayValue(tableElement.UIElement, newItemValue[dataField] as number);\r\n break;\r\n default:\r\n newItemValue[dataField] = column;\r\n break;\r\n }\r\n }\r\n }\r\n } else {\r\n popupInfo = { title: \"CSV-Import\", content: \"Es wurde keine Spalte mit name \".concat(headerColumns[j]).concat(\" in der Tabelle gefunden.\"), type: PopupType.ERROR };\r\n newItemValue = null;\r\n newItemDisplayValue = null;\r\n break;\r\n }\r\n }\r\n importedItems.push({ controlValues: newItemValue, displayValues: newItemDisplayValue });\r\n console.log(importedItems);\r\n }\r\n }\r\n const importResult = { popupInfo: popupInfo, importedItems: importedItems };\r\n return importResult;\r\n\r\n }\r\n\r\n /**\r\n * Imports a .xls or .xlst file into a datagrid.\r\n * @param workbook with the imported workbook\r\n * @param dxDataGrid with the dxDataGrid element to export the file to\r\n * @param tableGatheredColumns with the array of the elements that belong to the columns of the table\r\n * @return array of imported items\r\n */\r\n private importXlsFile(workbook: Workbook, dxDataGrid: DxDataGridComponent, tableGatheredColumns: Element[]): ImportResult {\r\n // Load .xls/.xlsx\r\n const importedItems: { controlValues: Record, displayValues: Record }[] = [];\r\n let popupInfo: PopupInfo;\r\n const sheet = workbook.getWorksheet('Eingabeblatt');\r\n if (sheet) {\r\n const headerColumns: string[] = [];\r\n sheet.eachRow((row: Row, rowIndex: number) => {\r\n let newItemValue: Record = {};\r\n let newItemDisplayValue: Record = {};\r\n const columns = row.values as CellValue[];\r\n for (let j = 1; j < columns.length; j++) {\r\n if (rowIndex == 1 && columns[j]) {\r\n headerColumns[j - 1] = columns[j].valueOf() as string;\r\n } else {\r\n const dataGridColumn: DxiColumnComponent = dxDataGrid.columnsChildren.find((col) => col.caption == headerColumns[j - 1]);\r\n\r\n if (dataGridColumn) {\r\n const tableElement = tableGatheredColumns.find((tableElement) => tableElement.ElementID == dataGridColumn.dataField);\r\n let cellValue = columns[j];\r\n let controlValue;\r\n let displayValue: string;\r\n const dataField = dataGridColumn.dataField;\r\n const dataType = dataGridColumn.dataType;\r\n\r\n if (cellValue) {\r\n // Links\r\n if ((cellValue).text) {\r\n cellValue = (cellValue).text;\r\n }\r\n \r\n if (tableElement.Items) {\r\n //Case of elements where an item (or several) can be chosen\r\n controlValue = this.stringUtils.convertTableCellDisplayNamesToValues(cellValue as string, tableElement.Items);\r\n displayValue = cellValue.toString();\r\n } else {\r\n switch (dataType) {\r\n // Boolean\r\n case 'System.Boolean':\r\n controlValue = this.stringUtils.convertYesNoStringToBoolean(cellValue as string);\r\n displayValue = cellValue.toString();\r\n break;\r\n\r\n // Datetime\r\n case 'System.DateTime':\r\n if (typeof displayValue === 'string' || cellValue instanceof String) {\r\n controlValue = this.stringUtils.convertDateStringToDate(cellValue as string);\r\n displayValue = this.stringUtils.convertDateToDateString(controlValue, tableElement.UIElement === UIElementType.DateEditWithTime);\r\n }\r\n else {\r\n controlValue = this.stringUtils.convertDateNumberToDate(cellValue as number);\r\n displayValue = this.stringUtils.convertDateToDateString(controlValue, tableElement.UIElement === UIElementType.DateEditWithTime);\r\n }\r\n break;\r\n\r\n // Numbers\r\n case 'System.Decimal':\r\n controlValue = cellValue;\r\n displayValue = this.stringUtils.getNumberDisplayValue(tableElement.UIElement, controlValue as number);\r\n break;\r\n default:\r\n controlValue = cellValue.toString();\r\n displayValue = cellValue.toString();\r\n break;\r\n }\r\n }\r\n\r\n newItemValue[dataField] = controlValue;\r\n newItemDisplayValue[dataField] = this.stringUtils.convertItemExcelDisplayNamesToTable(displayValue);\r\n }\r\n\r\n } else {\r\n popupInfo = { title: \"Excel-Import\", content: \"Es wurde keine Spalte mit name \".concat(headerColumns[j - 1]).concat(\" in der Tabelle gefunden.\"), type: PopupType.ERROR };\r\n newItemValue = null;\r\n newItemDisplayValue = null;\r\n break;\r\n }\r\n }\r\n }\r\n if (rowIndex > 1) {\r\n importedItems.push({ controlValues: newItemValue, displayValues: newItemDisplayValue });\r\n }\r\n })\r\n }\r\n const importResult = { popupInfo: popupInfo, importedItems: importedItems };\r\n return importResult;\r\n }\r\n\r\n\r\n /**\r\n * LEGACY FUNCTIONS\r\n */\r\n\r\n /**\r\n * Adjusts the with of the columns to be longer than the content.\r\n * @param worksheet with the Excel.Worksheet to adjust\r\n */\r\n public adjustColumnWidth(worksheet: any) {\r\n worksheet.columns.forEach((column: any) => {\r\n const lengths = column.values.map((v: any) => v.toString().length + 5) // 5 offset;\r\n const maxLength = Math.max(...lengths.filter((x: any) => { return typeof x === 'number' }));\r\n column.width = maxLength;\r\n });\r\n }\r\n}\r\n","export enum ValidationFunctionType {\r\n Unkown = 0,\r\n PlausiRange = 1,\r\n UIEnable = 2,\r\n Update = 3,\r\n UIVisible = 4,\r\n InvokeJob = 5,\r\n UpdateWithSystemFunction = 7,\r\n UIFilter = 8,\r\n UpdateWithElementFunction = 9,\r\n InvokeElementFunction = 10,\r\n InvokeSystemFunction = 11,\r\n InteractiveUpdate = 12,\r\n UIFilterSurvNetSchema = 13,\r\n PlausiDateNotInFuture = 14,\r\n PlausiRequired = 15\r\n}\r\n","import { Directive } from '@angular/core';\r\nimport { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';\r\n\r\n@Directive({\r\n selector: '[appDateValidator]'\r\n})\r\nexport class DateValidatorDirective {\r\n\r\n static dateInTheFuture(): ValidatorFn | null {\r\n const today: Date = new Date();\r\n return (control: AbstractControl): ValidationErrors | null => {\r\n const forbidden = new Date(control.value) > today;\r\n return forbidden ? { dateInTheFuture: { value: control.value } } : null;\r\n };\r\n }\r\n\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Receipt } from '../interfaces/form/receipt';\r\nimport { ReceiptTable } from '../interfaces/form/receipt-table';\r\nimport { ReceiptTableRow } from '../interfaces/form/receipt-table-row';\r\nimport { StringUtilsService } from './string-utils.service';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\n/**\r\n This service is in charge of performing the operations related to the Receipt information, and also holding\r\nthe data for being shared in between components\r\n */\r\nexport class ReceiptService {\r\n\r\n constructor(private stringUtils: StringUtilsService) { }\r\n\r\n // To be set after form submit with the form data\r\n private _submittedReceiptData: Receipt[];\r\n\r\n\r\n public get submittedReceiptData(): Receipt[] {\r\n return this._submittedReceiptData;\r\n }\r\n\r\n public set submittedReceiptData(receiptData: Receipt[]) {\r\n this._submittedReceiptData = receiptData;\r\n }\r\n\r\n\r\n /**\r\n * Creates an empty instance of receipt data.\r\n */\r\n public createReceiptData(formName: string) {\r\n this.submittedReceiptData = [];\r\n const creationDate = new Date();\r\n this.submittedReceiptData.push({\r\n DisplayName: this.stringUtils.convertDateToDateString(creationDate, true),\r\n Type: 'CreationDate',\r\n Value: creationDate\r\n });\r\n this.submittedReceiptData.push({\r\n DisplayName: formName,\r\n Type: 'FormName',\r\n Value: formName\r\n });\r\n }\r\n\r\n /**\r\n * Add a name and value pair for the representation of form edit fields outside tables.\r\n * @param name\r\n * @param value\r\n */\r\n public addEditElementValue(name: string, value: string) {\r\n this.submittedReceiptData.push({\r\n DisplayName: name,\r\n Type: 'Editor',\r\n Value: value\r\n });\r\n }\r\n\r\n /**\r\n * Creates a table for a receipt. Returns the table instance so the rows can be added\r\n * to that specific table later on.\r\n * @returns created table\r\n */\r\n public createTable(): ReceiptTable {\r\n return {\r\n Rows: []\r\n };\r\n }\r\n\r\n /**\r\n * Adds the specified receipt table with the specified name to the receipt data.\r\n * @param table\r\n * @param name\r\n */\r\n public addTable(table: ReceiptTable, tableName: string) {\r\n this.submittedReceiptData.push({\r\n DisplayName: tableName,\r\n Table: table,\r\n Type: 'Table'\r\n })\r\n }\r\n\r\n /**\r\n * Creates a table row for a receipt table. Returns the row instance so the columns can be added\r\n * to that specific row later on.\r\n * @returns created row\r\n */\r\n public createTableRow(): ReceiptTableRow {\r\n return {\r\n Columns: []\r\n };\r\n }\r\n\r\n /**\r\n * Adds the specified row to the specified receipt table.\r\n * @param table\r\n * @param row\r\n * @returns\r\n */\r\n public addTableRowToTable(table: ReceiptTable, row: ReceiptTableRow): ReceiptTable {\r\n table.Rows.push(row);\r\n return table;\r\n }\r\n\r\n /**\r\n * Creates and adds a cell to a receipt table row with the specified value. Returns the row instance\r\n * so more columns can be added to that specific instance later on.\r\n * @param row to add the column in\r\n * @param value with the cell content\r\n * @returns row after adding the cell\r\n */\r\n public createAndAddTableCell(row: ReceiptTableRow, value: string): ReceiptTableRow {\r\n row.Columns.push({\r\n Value: value,\r\n });\r\n return row;\r\n }\r\n\r\n /**\r\n * Edits the value of a receipt table cell, given the row, the index of the column and the value.\r\n * @param row\r\n * @param columnIndex\r\n * @param value\r\n */\r\n public editTableCell(row: ReceiptTableRow, columnIndex: number, value: string) {\r\n row.Columns[columnIndex] = { Value: value };\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { UntypedFormBuilder, UntypedFormGroup, UntypedFormArray, Validators, AbstractControl, UntypedFormControl } from '@angular/forms';\r\nimport { BehaviorSubject, Subject } from 'rxjs';\r\nimport { DataInput } from '../../interfaces/form/data-input';\r\nimport { Modul } from '../../interfaces/form/modul';\r\nimport { LayoutItem } from '../../interfaces/form/layout-item';\r\nimport { Element } from '../../interfaces/form/element';\r\nimport { UIElementType } from '../../interfaces/form/enums/uielement-type-enum';\r\nimport { ElementOutput } from '../../interfaces/form/element-output';\r\nimport { DataOutput } from '../../interfaces/form/data-output';\r\nimport { ReceiptTable } from '../../interfaces/form/receipt-table';\r\nimport { ReceiptTableRow } from '../../interfaces/form/receipt-table-row';\r\nimport { ReceiptService } from '../receipt.service';\r\nimport { ValidationFunctionType } from '../../interfaces/form/enums/validation-function-type-enum';\r\nimport { DateValidatorDirective } from './custom-validators/date-validator.directive';\r\nimport { formatMessage } from 'devextreme/localization';\r\nimport { StringUtilsService } from '../string-utils.service';\r\n\r\n/**\r\n * This service is meant to handle the main reactive form structure created for each dynamic form.\r\n */\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class ReactiveFormService {\r\n\r\n // Maximum number in which the receipt table is printed in separated columns mode.\r\n private MAX_COLUMNS_IN_RECEIPT_TABLE = 5;\r\n\r\n //Contains the whole reactive form structure\r\n private _reactiveForm: UntypedFormGroup;\r\n\r\n //States whether the form contains any required field so the form must be blocked if the don't have a value\r\n private _hasValidationFields: boolean;\r\n\r\n //Stores the last element ID added in the form structure. This is useful mantaining asynchronous control,\r\n //for example, notifying when the latest element of the form has been rendered.\r\n public lastElementIdAdded: string;\r\n\r\n //Broadcasts the status of the last element being already rendered or not\r\n public lastElementRendered: BehaviorSubject;\r\n\r\n constructor(private fb: UntypedFormBuilder, private receiptService: ReceiptService, private stringUtilsService: StringUtilsService) {\r\n }\r\n\r\n /**\r\n * Get the current status of the reactive form.\r\n */\r\n public getReactiveForm(): UntypedFormGroup {\r\n return this._reactiveForm;\r\n }\r\n\r\n /**\r\n * Getter of the attribute indicating if the form has any field that is validated on submit.\r\n */\r\n get hasValidationFields() {\r\n return this._hasValidationFields;\r\n }\r\n\r\n /**\r\n * Creates a new form for the current customer. At this point contains\r\n * only an array for the placig there the modules\r\n */\r\n public createAppReactiveForm(): UntypedFormGroup {\r\n this.lastElementRendered = new BehaviorSubject(false);\r\n this._reactiveForm = this.fb.group({\r\n formName: new UntypedFormControl(),\r\n modulesArray: this.fb.array([\r\n\r\n ])\r\n });\r\n this._hasValidationFields = false;\r\n return this._reactiveForm;\r\n }\r\n\r\n /**\r\n * With the received input data for a customer, fills the modules array.\r\n * @param argDataInput\r\n */\r\n public initializeAppReactiveForm(argDataInput: DataInput) {\r\n this._reactiveForm.get(\"formName\").setValue(argDataInput.PageTitel);\r\n argDataInput.Module.forEach((currentModule, moduleIndex) => {\r\n // For modules with a layout attribute, a form array with its layout items is generated\r\n if (currentModule.Layout) {\r\n this.modulesArray.push(\r\n this.fb.group({\r\n moduleIndex: moduleIndex,\r\n layoutItemsArray: this.fb.array([])\r\n })\r\n )\r\n this.generateLayoutItems(currentModule.Layout.LayoutItems, moduleIndex, currentModule, \"\", currentModule.Layout.Orientation !== \"Vertical\");\r\n }\r\n })\r\n }\r\n\r\n /**\r\n * With the received module data, fills the layout items array that will contain the form controls and the render information\r\n * for all the edit fields.\r\n * @param layoutItems\r\n * @param moduleIndex\r\n * @param module\r\n * @param argLayoutItemTitle\r\n */\r\n private generateLayoutItems(layoutItems: LayoutItem[], moduleIndex: number, module: Modul = null, argLayoutItemTitle: string, horizontal: boolean) {\r\n layoutItems.forEach((layoutItem) => {\r\n const layoutItemTitle = layoutItem.Header ? layoutItem.Header : argLayoutItemTitle;\r\n if (layoutItem.Type === \"Element\") {\r\n const element: Element = module.Elements.find(\r\n function (element) {\r\n return (element.ElementID === layoutItem.ElementID);\r\n });\r\n // Only that don't belong to tables are loaded here. The ones belonging\r\n // to tables, are rendered from the table component\r\n if (element.UIElement !== UIElementType.Table) {\r\n this.addFormControlForElement(element, null, moduleIndex, false, null, layoutItem.Label);\r\n } else {\r\n this.addFormGroupForTable(element, layoutItemTitle, moduleIndex);\r\n }\r\n } else {\r\n this.generateLayoutItems(layoutItem.LayoutItems, moduleIndex, module, layoutItemTitle, layoutItem.Orientation !== \"Vertical\");\r\n }\r\n })\r\n }\r\n\r\n\r\n /**\r\n * Adds a form control element for an editable field.\r\n * @param element with the Element for which the form control should be created\r\n * @param value with he value of the element that should be assigned to the form control in initialization\r\n * @param moduleIndex with the current module\r\n * @param avoidSubmitting stating whether the current element's value is to be submitted with the form. For example,\r\n * in the tables only the row values should be submitted, and not the values of the input form fields for adding a row\r\n * that were not submitted.\r\n * @param belongsToTableId only to be sent if the added form control belongs to a table row add/edit field\r\n * @param label with the LayoutItem printable label for the input element to be displayed. If null, the element display name\r\n * will be printed.\r\n * @returns index of the added element in its array\r\n */\r\n public addFormControlForElement(element: Element, value: string, moduleIndex: number, avoidSubmitting: boolean, belongsToTableId: string, label: string): number {\r\n let formControlIndex = 0;\r\n const parentFormArray = this.getLayoutItemsArrayFromModuleNumber(moduleIndex);\r\n if (parentFormArray) {\r\n // Check if the element had been added to the reactive form before\r\n const elementFormControlIndex = parentFormArray.controls.map(function (control) {\r\n return control.get('id')?.value\r\n }).indexOf(element.ElementID);\r\n if (elementFormControlIndex < 0) {\r\n // In case it wasn't there, a new form group is created for element\r\n formControlIndex = parentFormArray.length;\r\n parentFormArray.push(\r\n this.fb.group({\r\n value: [value],\r\n displayValue: \"\",\r\n id: element.ElementID,\r\n avoidSubmitting: avoidSubmitting,\r\n displayName: element.DisplayName,\r\n visible: true,\r\n belongsToTableId: belongsToTableId ? belongsToTableId : null,\r\n label: label,\r\n validationMessages: null,\r\n })\r\n )\r\n this.createValidatorsListForElement(element, parentFormArray.at(parentFormArray.controls.length - 1));\r\n // Keeping record of the last element added to the form. Only elements that will be rendered on form\r\n // loading, meaning non-submittable elements (elements for editing a table column) are not included\r\n if (!avoidSubmitting) {\r\n this.lastElementIdAdded = element.ElementID;\r\n }\r\n } else {\r\n // In case it was there, the form control associated to the value is edited with the previous value or empty\r\n // if it didn't exist\r\n formControlIndex = elementFormControlIndex;\r\n parentFormArray.controls[formControlIndex].get('value').setValue(value ? value : '');\r\n }\r\n }\r\n return formControlIndex;\r\n }\r\n\r\n /**\r\n * Applies the element's own validations, meaning the validations that don't affect to other elements.\r\n * @param element\r\n * @param elementFormControl\r\n */\r\n private createValidatorsListForElement(element: Element, elementFormControl: AbstractControl) {\r\n // Validation of type \"required\"\r\n if (element.IsRequired) {\r\n this.addRequiredToFormControl(elementFormControl);\r\n }\r\n // Other validations available in the Validations field of the element\r\n if (element.Validations) {\r\n const validationMessages: { validationFn: string, message: string }[] = elementFormControl.get(\"validationMessages\").value ?? [];\r\n this.setFormHasValidationRules();\r\n element.Validations.forEach((validation) => {\r\n switch (validation.FunctionType) {\r\n case (ValidationFunctionType.PlausiDateNotInFuture): {\r\n elementFormControl.get(\"value\").addValidators(DateValidatorDirective.dateInTheFuture());\r\n validationMessages.push({\r\n validationFn: \"dateInTheFuture\",\r\n message: validation.Message ? validation.Message : \"Das Datum kann nicht in der Zukunft eingestellt werden\",\r\n });\r\n break;\r\n }\r\n case (ValidationFunctionType.PlausiRange): {\r\n const minAndMaxObject = this.stringUtilsService.getMinAndMaxInPlausibilityRange(validation.Condition);\r\n elementFormControl.get(\"value\").addValidators(Validators.min(minAndMaxObject.min));\r\n validationMessages.push({\r\n validationFn: \"min\",\r\n message: validation.Message ? validation.Message : `Die eingegebene Zahl muss gr��er als ${minAndMaxObject.min} sein`,\r\n });\r\n elementFormControl.get(\"value\").addValidators(Validators.max(minAndMaxObject.max));\r\n validationMessages.push({\r\n validationFn: \"max\",\r\n message: validation.Message ? validation.Message : `Die eingegebene Zahl muss kleiner als ${minAndMaxObject.max} sein`,\r\n });\r\n break;\r\n }\r\n\r\n }\r\n })\r\n elementFormControl.get(\"validationMessages\").setValue(validationMessages);\r\n }\r\n }\r\n\r\n /**\r\n * Sets the attribute stating that there are elements in the form that need to be validated.\r\n */\r\n private setFormHasValidationRules() {\r\n if (!this._hasValidationFields) {\r\n this._hasValidationFields = true;\r\n }\r\n }\r\n\r\n /**\r\n * States if a element is to be rendered or not, after the form validation has been loaded.\r\n * @param element\r\n * @returns\r\n */\r\n public isElementVisible(element: Element): boolean {\r\n let elementVisible = true;\r\n if (element.UIElement !== UIElementType.Table) {\r\n const currentElementFormGroup: UntypedFormGroup = this.searchElementFormGrouplInReactiveFormByElementId(element.ElementID, false);\r\n if (!currentElementFormGroup || !currentElementFormGroup.get('visible').value) {\r\n elementVisible = false;\r\n }\r\n }\r\n return elementVisible;\r\n }\r\n\r\n /**\r\n * Changes the value in a form control element.\r\n * @param element with the Element corresponding to the form control\r\n * @param newValue with the new value to be set\r\n * @param moduleIndex with the current module\r\n */\r\n public changeFormControlValue(element: Element, newValue: string) {\r\n const controlFormGroup = this.searchElementFormGrouplInReactiveFormByElementId(element.ElementID, false);\r\n if (controlFormGroup) {\r\n controlFormGroup.get('value').setValue(newValue);\r\n controlFormGroup.get('id').setValue(element.ElementID);\r\n }\r\n }\r\n\r\n\r\n /**\r\n * Creates an empty form group for a table.\r\n * @param element with the Table element of the input data for which the group is added\r\n * @param layoutItemTitle with the title of table coming from the LayoutItem object\r\n * @param moduleIndex with the current module idex\r\n * @returns FormGroup of the added table\r\n */\r\n public addFormGroupForTable(element: Element, layoutItemTitle: string, moduleIndex: number): UntypedFormGroup {\r\n const parentFormArray = this.getLayoutItemsArrayFromModuleNumber(moduleIndex);\r\n const formControlIndex = parentFormArray.length;\r\n parentFormArray.push(\r\n this.fb.group({\r\n id: element.ElementID,\r\n tableId: element.ElementTableID,\r\n itemsArray: this.fb.array([]),\r\n layoutItemTitle: layoutItemTitle,\r\n })\r\n )\r\n // Keeping record of the last element added to the form.\r\n this.lastElementIdAdded = element.ElementID;\r\n return parentFormArray.at(formControlIndex) as UntypedFormGroup;\r\n }\r\n\r\n /**\r\n * Each row that is added to the table must be reflected in the reactive forms structure, adding\r\n * a form array with the rows, and each row with a nested form array for the cell values.\r\n * @param data: null if the values to be added are from the add/edit row form. Double record of {value - id, value-id} pairs if it comes form\r\n * an exteral source, being each pair the values and display values tied to the ID of the form element.\r\n * @param key\r\n * @param elementTableId\r\n * @param moduleIndex\r\n * @return boolean stating whether the add was added/passed validation or not\r\n */\r\n public addRowToTable(data: { controlValues: Record, displayValues: Record }, key: string, elementTableId: string, moduleIndex: number): UntypedFormGroup[] {\r\n if (data) {\r\n // Case that the information for the new row comes from an external source, and not directly from the add/edit row form\r\n // In this case, the form controls of the add/edit row form will be filled with the external source values, so the\r\n // new row validation and/or adition are executed with the same code as when adding/editing from the form\r\n for (const property in data.controlValues) {\r\n if (property !== '__KEY__') {\r\n const rowEditFormElement: UntypedFormGroup = this.searchElementFormGrouplInReactiveFormByElementId(property, false);\r\n if (rowEditFormElement) {\r\n rowEditFormElement.get('value').setValue(data.controlValues[property]);\r\n rowEditFormElement.get('displayValue').setValue(data.displayValues[property]);\r\n }\r\n }\r\n }\r\n }\r\n const itemsFormArray = this.searchElementFormGrouplInReactiveFormByElementId(elementTableId, true).get('itemsArray') as UntypedFormArray;\r\n const itemIndex = itemsFormArray.controls.length;\r\n (itemsFormArray).push(\r\n this.fb.group({\r\n itemId: key,\r\n keysArray: this.fb.array([]),\r\n })\r\n )\r\n const rowAddFailingFields = this.applyInputValuesToRow(elementTableId, moduleIndex, itemsFormArray, itemIndex);\r\n if (rowAddFailingFields.length > 0) {\r\n itemsFormArray.removeAt(itemIndex);\r\n }\r\n return rowAddFailingFields;\r\n }\r\n\r\n /**\r\n * Gets the row display values of the currently opened add/edit row form.\r\n * @param elementTableId\r\n * @param moduleIndex\r\n */\r\n public getRowDisplayValues(elementTableId: string, moduleIndex: number): Record {\r\n const editElements = this.searchTableEditElementFormGroupsByTableId(elementTableId, moduleIndex);\r\n const newItemDisplayValues: Record = {};\r\n editElements.forEach((column) => {\r\n if (!column.get(\"value\")?.disabled && column.get(\"visible\")?.value) {\r\n newItemDisplayValues[column.get('id').value] = column.get('displayValue').value;\r\n }\r\n })\r\n return newItemDisplayValues;\r\n }\r\n\r\n /**\r\n * Prepares teh form structure for editing an existing row by popuplating the add/edit row edit fields\r\n * with the selected row value.\r\n * @param elementTableId\r\n * @param moduleIndex\r\n * @param rowIndex\r\n */\r\n public prepareEditRowData(elementTableId: string, moduleIndex: number, rowIndex: number) {\r\n const itemsFormArray = this.searchElementFormGrouplInReactiveFormByElementId(elementTableId, true).get('itemsArray') as UntypedFormArray;\r\n const itemFormGroup = itemsFormArray.at(rowIndex) as UntypedFormGroup;\r\n const keysFormArray = itemFormGroup.get(\"keysArray\") as UntypedFormArray;\r\n this.applyRowValuesToInput(elementTableId, moduleIndex, keysFormArray);\r\n }\r\n\r\n /**\r\n * It copies all the values in a row to the counterpants in the add/edit row edit fields. This may be used\r\n * for preparing the row edition fields with the current values of the row under edit.\r\n * @param elementTableId\r\n * @param moduleIndex\r\n * @param itemsFormArray\r\n * @param rowIndex\r\n */\r\n private applyRowValuesToInput(elementTableId: string, moduleIndex: number, rowKeysArrayWithValues: UntypedFormArray) {\r\n const tableEditElemens: UntypedFormGroup[] = this.searchTableEditElementFormGroupsByTableId(elementTableId, moduleIndex);\r\n this.clearEditRowValuesFromTable(elementTableId, moduleIndex);\r\n rowKeysArrayWithValues.controls.forEach((tableCellGroup) => {\r\n const editElement = tableEditElemens.find((tableEditElement) =>\r\n tableEditElement.get('id').value === tableCellGroup.get('id').value\r\n )\r\n if (editElement) {\r\n editElement.get('value').setValue(tableCellGroup.get('value').value);\r\n }\r\n })\r\n }\r\n\r\n /**\r\n * Edits the values of a row from the reactive form structure corresponding to a table.\r\n * @param editedRowIndex\r\n * @param elementTableId\r\n * @param moduleIndex\r\n * @return boolean stating whether the submitted data passed the validation\r\n */\r\n public editRowValuesFromTable(editedRowIndex: number, elementTableId: string, moduleIndex: number): UntypedFormGroup[] {\r\n const itemsFormArray = this.searchElementFormGrouplInReactiveFormByElementId(elementTableId, true).get('itemsArray') as UntypedFormArray;\r\n const rowEditFailingFields: UntypedFormGroup[] = this.applyInputValuesToRow(elementTableId, moduleIndex, itemsFormArray, editedRowIndex);\r\n return rowEditFailingFields;\r\n }\r\n\r\n /**\r\n * For a row represented in this form structure as itemsFormArray, applies the current values in the\r\n * add/edit table row fields. This may be used for adding/editing rows.\r\n * @param elementTableId\r\n * @param moduleIndex\r\n * @param itemsFormArray\r\n * @param itemIndex\r\n * @return boolean stating whether the row values were applied, depending on them passing the validation or not\r\n */\r\n private applyInputValuesToRow(elementTableId: string, moduleIndex: number, itemsFormArray: UntypedFormArray, itemIndex: number): UntypedFormGroup[] {\r\n const rowInputFormGroups: UntypedFormGroup[] = this.searchTableEditElementFormGroupsByTableId(elementTableId, moduleIndex);\r\n const invalidInputs = rowInputFormGroups.filter(input => !input.valid);\r\n\r\n if (!invalidInputs.length) {\r\n (itemsFormArray.controls[itemIndex].get('keysArray') as UntypedFormArray).clear();\r\n rowInputFormGroups.forEach((elementGroup) => {\r\n if (!elementGroup.get('value')?.disabled && elementGroup.get('visible')?.value) {\r\n // Case of not disabled and not hidden objects\r\n (itemsFormArray.controls[itemIndex].get('keysArray') as UntypedFormArray).push(\r\n this.fb.group({\r\n value: [elementGroup.get('value')?.value],\r\n displayValue: elementGroup.get('displayValue')?.value,\r\n displayName: elementGroup.get('displayName').value,\r\n id: elementGroup.get('id')?.value,\r\n })\r\n )\r\n } else {\r\n (itemsFormArray.controls[itemIndex].get('keysArray') as UntypedFormArray).push(\r\n this.fb.group({\r\n value: null,\r\n displayValue: null,\r\n displayName: elementGroup.get('displayName').value,\r\n id: elementGroup.get('id')?.value,\r\n })\r\n )\r\n }\r\n })\r\n }\r\n return invalidInputs;\r\n }\r\n\r\n\r\n /**\r\n * Clears the value of all the table add/edit row edit fields.\r\n * @param elementTableId\r\n * @param moduleIndex\r\n */\r\n public clearEditRowValuesFromTable(elementTableId: string, moduleIndex: number) {\r\n const tableEditElemens: UntypedFormGroup[] = this.searchTableEditElementFormGroupsByTableId(elementTableId, moduleIndex);\r\n tableEditElemens.forEach((tableEditElement) => {\r\n tableEditElement.get('value').setValue(null);\r\n tableEditElement.get('displayValue').setValue(null);\r\n });\r\n }\r\n\r\n /**\r\n * Deletes a row from the reactive form structure corresponding to the data entered in a table.\r\n * @param deletedRowIndex\r\n * @param formArrayIndex\r\n * @param elementTableId\r\n */\r\n public deleteRowFromTable(deletedRowIndex: number, elementTableId: string) {\r\n const itemsFormArray = this.searchElementFormGrouplInReactiveFormByElementId(elementTableId, true).get('itemsArray') as UntypedFormArray;\r\n itemsFormArray.removeAt(deletedRowIndex);\r\n }\r\n\r\n /**\r\n * Gets a form group belonging to a cell from the entered data in a table.\r\n * @param tableElementID\r\n * @param rowIndex\r\n * @param columnIndex\r\n * @returns\r\n */\r\n getTableCellFormGroup(tableElementID: string, rowIndex: number, columnIndex: number): UntypedFormGroup {\r\n let cellFormGroup: UntypedFormGroup = null;\r\n const tableElement: UntypedFormGroup = this.searchElementFormGrouplInReactiveFormByElementId(tableElementID, true);\r\n if (tableElement) {\r\n const itemsFormGroup: UntypedFormGroup = (tableElement.get('itemsArray') as UntypedFormArray).at(rowIndex) as UntypedFormGroup;\r\n cellFormGroup = (itemsFormGroup.get('keysArray') as UntypedFormArray).at(columnIndex) as UntypedFormGroup;\r\n }\r\n return cellFormGroup;\r\n }\r\n\r\n /**\r\n * Getter method for the form array of the modules inside the form control main group.\r\n */\r\n get modulesArray() {\r\n return this._reactiveForm.get('modulesArray') as UntypedFormArray;\r\n }\r\n\r\n /**\r\n * For the given module specified by the index, the form array of first-level children layout items si returned.\r\n * @param moduleIndex\r\n * @returns\r\n */\r\n getLayoutItemsArrayFromModuleNumber(moduleIndex: number): UntypedFormArray {\r\n return this.modulesArray.controls[moduleIndex].get('layoutItemsArray') as UntypedFormArray;\r\n }\r\n\r\n /**\r\n * Searchs the form group corresponding to an element or table element in the reactive form structure.\r\n * @param elementId with either the elementId or the tableElementId of the element\r\n * @param isTable is a table (true) or an element (false)\r\n * @returns\r\n */\r\n searchElementFormGrouplInReactiveFormByElementId(elementId: string, isTable: boolean): UntypedFormGroup {\r\n let foundFormGroup: AbstractControl = null;\r\n const modulesArray: UntypedFormArray = this.modulesArray;\r\n if (modulesArray) {\r\n modulesArray.controls.forEach((moduleFormGroup, moduleIndex) => {\r\n if (!foundFormGroup) {\r\n const layoutItemsArray: UntypedFormArray = this.getLayoutItemsArrayFromModuleNumber(moduleIndex);\r\n if (layoutItemsArray) {\r\n if (!isTable) {\r\n foundFormGroup = layoutItemsArray.controls.find((layoutItemGroup) =>\r\n layoutItemGroup.get(\"id\") && layoutItemGroup.get(\"id\").value === elementId\r\n )\r\n } else {\r\n foundFormGroup = layoutItemsArray.controls.find((layoutItemGroup) =>\r\n layoutItemGroup.get(\"tableId\") && layoutItemGroup.get(\"tableId\").value === elementId\r\n )\r\n }\r\n }\r\n }\r\n })\r\n }\r\n return foundFormGroup as UntypedFormGroup;\r\n }\r\n\r\n /**\r\n * In a module, searchs for all the edit column element used when adding/editing a row from a table.\r\n * @param elementTableId of the table\r\n * @param moduleIndex\r\n * @returns\r\n */\r\n searchTableEditElementFormGroupsByTableId(elementTableId: string, moduleIndex: number): UntypedFormGroup[] {\r\n const foundEditElementGroups: UntypedFormGroup[] = [];\r\n this.getLayoutItemsArrayFromModuleNumber(moduleIndex).controls.forEach((layoutItem) => {\r\n if (layoutItem.get('belongsToTableId') && layoutItem.get('belongsToTableId').value === elementTableId) {\r\n foundEditElementGroups.push(layoutItem as UntypedFormGroup);\r\n }\r\n })\r\n return foundEditElementGroups;\r\n }\r\n\r\n /**\r\n * In the reactive form structure, searchs the form group belonging to an input element of a table column\r\n * @param elementTableID\r\n * @param elementID\r\n */\r\n searchTableEditElementFormGroupByElementIDAndTableId(elementTableID: string, elementID: string): UntypedFormGroup {\r\n let foundInputFormGroup: UntypedFormGroup;\r\n this.modulesArray.controls.forEach((moduleFormGroup, moduleIndex) => {\r\n if (!foundInputFormGroup) {\r\n const tableFormInputs: UntypedFormGroup[] = this.searchTableEditElementFormGroupsByTableId(elementTableID, moduleIndex);\r\n foundInputFormGroup = tableFormInputs.find((formInputGroup) =>\r\n formInputGroup.get(\"id\").value === elementID\r\n )\r\n }\r\n })\r\n return foundInputFormGroup;\r\n }\r\n\r\n /**\r\n * Prevents an element from being rendered in the form.\r\n * @param elementId\r\n * @param elementBelongsToTable indicating whether the input element belongs to a table add/edit row form\r\n */\r\n hideElementFormGroup(elementId: string, elementBelongsToTableId: string) {\r\n let formGroup: UntypedFormGroup;\r\n if (!elementBelongsToTableId) {\r\n formGroup = this.searchElementFormGrouplInReactiveFormByElementId(elementId, false);\r\n } else {\r\n formGroup = this.searchTableEditElementFormGroupByElementIDAndTableId(elementBelongsToTableId, elementId);\r\n }\r\n if (formGroup) {\r\n formGroup.get('avoidSubmitting').setValue(true);\r\n formGroup.get('visible').setValue(false);\r\n }\r\n }\r\n\r\n /**\r\n * Renders an element in the form.\r\n * @param elementId\r\n * @param elementBelongsToTable indicating whether the input element belongs to a table add/edit row form\r\n */\r\n showElementFormGroup(elementId: string, elementBelongsToTableId: string) {\r\n let formGroup: UntypedFormGroup;\r\n if (!elementBelongsToTableId) {\r\n formGroup = this.searchElementFormGrouplInReactiveFormByElementId(elementId, false);\r\n } else {\r\n formGroup = this.searchTableEditElementFormGroupByElementIDAndTableId(elementBelongsToTableId, elementId);\r\n }\r\n if (formGroup) {\r\n formGroup.get('avoidSubmitting').setValue(false);\r\n formGroup.get('visible').setValue(true);\r\n }\r\n }\r\n\r\n /**\r\n * Enables/disables the value (always correponding to the input value) FormControl in the element form group.\r\n * @param elementId\r\n * @param enable stating whether the form control is to be enabled or disabled\r\n * @param elementBelongsToTableId indicating the table ID if the input element belongs to a table add/edit row form\r\n * @return boolean indicating of action was taken or it wasnt' necessary\r\n */\r\n enableElementValueFormControl(elementId: string, enable: boolean, elementBelongsToTableId: string): boolean {\r\n let formGroup: UntypedFormGroup;\r\n if (!elementBelongsToTableId) {\r\n formGroup = this.searchElementFormGrouplInReactiveFormByElementId(elementId, false);\r\n } else {\r\n formGroup = this.searchTableEditElementFormGroupByElementIDAndTableId(elementBelongsToTableId, elementId);\r\n }\r\n if (formGroup) {\r\n if (enable === formGroup.get('value').disabled) {\r\n if (enable) {\r\n formGroup.get('value').enable();\r\n } else {\r\n formGroup.get('value').disable();\r\n }\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Sets the required validation on a value form control of a form element's form group. \r\n * @param elementId\r\n * @param required\r\n * @param elementBelongsToTableId indicating whether the input element belongs to a table add/edit row form\r\n * @return boolean indicating of action was taken or it wasnt' necessary\r\n */\r\n controlElementRequiredAttribute(elementId: string, required: boolean, elementBelongsToTableId: string): boolean {\r\n let formGroup: UntypedFormGroup;\r\n if (!elementBelongsToTableId) {\r\n formGroup = this.searchElementFormGrouplInReactiveFormByElementId(elementId, false);\r\n } else {\r\n formGroup = this.searchTableEditElementFormGroupByElementIDAndTableId(elementBelongsToTableId, elementId);\r\n }\r\n if (formGroup) {\r\n if (required) {\r\n return this.addRequiredToFormControl(formGroup);\r\n } else {\r\n return this.deleteRequiredFromFormControl(formGroup);\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Adds the required validator to the value form control and also the validation message\r\n * to the ValidationMessages form control of a form element form group.\r\n * @param formGroup\r\n * @return boolean indicating of action was taken or it wasnt' necessary\r\n */\r\n private addRequiredToFormControl(formGroup: AbstractControl) {\r\n let actionTaken = false;\r\n if (!formGroup.get(\"value\").hasValidator(Validators.required)) {\r\n actionTaken = true;\r\n formGroup.get(\"value\").addValidators(Validators.required);\r\n const validationMessages = formGroup.get(\"validationMessages\").value ?? [];\r\n validationMessages.push({\r\n validationFn: \"required\",\r\n message: formatMessage(\"validation-required-formatted\", formGroup.get(\"label\").value ?? formGroup.get(\"displayName\").value)\r\n });\r\n formGroup.get(\"validationMessages\").setValue(validationMessages);\r\n this.setFormHasValidationRules();\r\n }\r\n return actionTaken;\r\n }\r\n\r\n /**\r\n * Removes the required validator from the value form control and also the validation message\r\n * from the ValidationMessages form control of a form element form group.\r\n * @param formGroup\r\n * @return boolean indicating of action was taken or it wasnt' necessary\r\n */\r\n private deleteRequiredFromFormControl(formGroup: AbstractControl): boolean {\r\n let actionTaken = false;\r\n if (formGroup.get(\"value\").hasValidator(Validators.required)) {\r\n actionTaken = true;\r\n formGroup.get(\"value\").removeValidators(Validators.required);\r\n let validationMessages: { validationFn: string, message: string }[] = formGroup.get(\"validationMessages\").value;\r\n if (validationMessages && validationMessages.length) {\r\n validationMessages = validationMessages.filter((vm) => vm.validationFn !== \"required\");\r\n formGroup.get(\"validationMessages\").setValue(validationMessages);\r\n }\r\n }\r\n return actionTaken;\r\n }\r\n\r\n /**\r\n * Updates the value (always correponding to the input value) FormControl in the element form group with the given value.\r\n * @param elementId\r\n * @param value\r\n * @param elementBelongsToTableId indicating whether the input element belongs to a table add/edit row form\r\n * @return boolean indicating of action was taken or it wasnt' necessary\r\n */\r\n updateElementFormControlValue(elementId: string, value: unknown, elementBelongsToTableId: string): boolean {\r\n let actionTaken = false;\r\n let formGroup: UntypedFormGroup;\r\n if (!elementBelongsToTableId) {\r\n formGroup = this.searchElementFormGrouplInReactiveFormByElementId(elementId, false);\r\n } else {\r\n formGroup = this.searchTableEditElementFormGroupByElementIDAndTableId(elementBelongsToTableId, elementId);\r\n }\r\n if (formGroup) {\r\n formGroup.get('value').setValue(value);\r\n actionTaken = true;\r\n }\r\n return actionTaken;\r\n }\r\n\r\n /**\r\n * To be called by the last rendered element (see related attributes in the variable declarations of this service).\r\n * It broadcasts that the form is fully loaded to the listeners interested in this event. \r\n */\r\n public notifyLastElementLoaded() {\r\n this.lastElementRendered.next(true);\r\n }\r\n\r\n /**\r\n * To be called when leaving the form, it broadcasts that the form isn't loaded anymore. \r\n */\r\n public notifyFormExit() {\r\n this.lastElementRendered.complete;\r\n }\r\n\r\n /**\r\n * Given the reactive form data from this service, it packs the data of the form ready for being sent\r\n * to the back-end in a DataOutput interface.\r\n *\r\n * @outputDataContainer DataOutput element where the data must be placed\r\n * @returns the data ready for being sent to the service\r\n */\r\n public packElementsOutputData(outputDataContainer: DataOutput): DataOutput {\r\n this.receiptService.createReceiptData(this._reactiveForm.get(\"formName\").value);\r\n this.modulesArray.controls.forEach((value, index) => {\r\n const layoutItemsFormArray: UntypedFormArray = this.getLayoutItemsArrayFromModuleNumber(index);\r\n layoutItemsFormArray.controls.forEach((value) => {\r\n if (value.get('value') && !value.get('avoidSubmitting')?.value && !value.get('value')?.disabled && value.get('visible')?.value) {\r\n // Case of editor element\r\n const elementOutput: ElementOutput = {\r\n ElementID: value.get('id').value,\r\n Value: value.get('value').value\r\n };\r\n outputDataContainer.Elements.push(elementOutput);\r\n this.receiptService.addEditElementValue(value.get('displayName')?.value, value.get('displayValue').value);\r\n } else if (value.get('itemsArray')) {\r\n //Case of tables, first a loop is performed over each table item\r\n const itemElementsOutputArray: ElementOutput[] = [];\r\n let receiptTable: ReceiptTable = this.receiptService.createTable();\r\n\r\n const itemsFormArray = value.get('itemsArray') as UntypedFormArray;\r\n console.log(1, itemsFormArray);\r\n itemsFormArray.controls.forEach((value, rowIndex) => {\r\n const keyElementsOutputArray: ElementOutput[] = [];\r\n const keysArray = value.get('keysArray') as UntypedFormArray;\r\n //Adding headers to the receipt as first row\r\n if (rowIndex === 0) {\r\n this.submitTableHeaders(keysArray, receiptTable);\r\n }\r\n const receiptTableRow: ReceiptTableRow = this.receiptService.createTableRow();\r\n this.submitTableRowCells(keysArray, receiptTableRow, keyElementsOutputArray);\r\n\r\n receiptTable = this.receiptService.addTableRowToTable(receiptTable, receiptTableRow);\r\n const itemOutput: ElementOutput = {\r\n Elements: keyElementsOutputArray,\r\n ElementID: value.get('itemId').value,\r\n };\r\n itemElementsOutputArray.push(itemOutput);\r\n\r\n })\r\n const tableOutput: ElementOutput = {\r\n ElementID: value.get('id').value,\r\n Elements: itemElementsOutputArray,\r\n };\r\n outputDataContainer.Elements.push(tableOutput);\r\n this.receiptService.addTable(receiptTable, value.get('layoutItemTitle').value);\r\n\r\n }\r\n })\r\n })\r\n\r\n return outputDataContainer;\r\n }\r\n\r\n /**\r\n * Performs the submit operations corresponding to the table headers.\r\n * @param keysArray\r\n * @param receiptTable\r\n * @returns\r\n */\r\n private submitTableHeaders(keysArray: UntypedFormArray, receiptTable: ReceiptTable) {\r\n //if (keysArray.length <= this.MAX_COLUMNS_IN_RECEIPT_TABLE) {\r\n // The headers are only printed for the tables with >= 5 columns\r\n let receiptTableHeadersRow: ReceiptTableRow = this.receiptService.createTableRow();\r\n keysArray.controls.forEach((value, index) => {\r\n if (index < this.MAX_COLUMNS_IN_RECEIPT_TABLE) {\r\n receiptTableHeadersRow = this.receiptService.createAndAddTableCell(\r\n receiptTableHeadersRow, value.get('displayName')?.value);\r\n }\r\n })\r\n this.receiptService.addTableRowToTable(receiptTable, receiptTableHeadersRow);\r\n //}\r\n }\r\n\r\n /**\r\n * Performs the submit operations corresponding to the table row cells.\r\n * @param keysArray\r\n * @param receiptTableRow\r\n * @param keyElementsOutputArray\r\n */\r\n private submitTableRowCells(keysArray: UntypedFormArray, receiptTableRow: ReceiptTableRow, keyElementsOutputArray: ElementOutput[]) {\r\n keysArray.controls.forEach((value, columnIndex) => {\r\n const keyOutput: ElementOutput = {\r\n ElementID: value.get('id').value,\r\n Value: value.get('value').value,\r\n };\r\n keyElementsOutputArray.push(keyOutput);\r\n\r\n if (columnIndex < this.MAX_COLUMNS_IN_RECEIPT_TABLE) {\r\n let printingValue = value.get('displayValue') ? value.get('displayValue').value : \" - \";\r\n if (printingValue?.indexOf(\"
\") > -1) {\r\n printingValue = this.stringUtilsService.convertItemsArrayTableDisplayNamesToPDF(printingValue);\r\n }\r\n\r\n this.receiptService.createAndAddTableCell(receiptTableRow, printingValue);\r\n }\r\n });\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { UntypedFormControl, UntypedFormGroup, ValidationErrors } from '@angular/forms';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class ValidationSummaryService {\r\n\r\n /**\r\n * Given the current status of the form group sent as a parameter, this method returns an array\r\n * with the validation messages to be print in a validation summary.\r\n * @param formGroup\r\n */\r\n public createValidationMessagesForFormGroup(formGroup: UntypedFormGroup): { message: string, elementId: string }[] {\r\n const validationMessages: { message: string, elementId: string }[] = [];\r\n Object.keys(formGroup.controls).forEach((formFieldGrouplKey) => {\r\n const formFieldErrors: ValidationErrors = formGroup.get(formFieldGrouplKey).get(\"value\").errors;\r\n if (formFieldErrors) {\r\n const fieldValidationMessage = this.createSummaryError(formFieldErrors, formGroup.get(formFieldGrouplKey).get(\"messages\").value);\r\n if (fieldValidationMessage) {\r\n validationMessages.push({ message: fieldValidationMessage, elementId: formFieldGrouplKey });\r\n }\r\n }\r\n })\r\n return validationMessages;\r\n }\r\n\r\n /**\r\n * For form controls that don't have the name to appear in the validation messages,\r\n * given the current status of the form controls sent as a parameter in the FormControl/name pairs array,\r\n * this method returns an array with the validation messages to be printed in a validation summary and their IDs.\r\n * @param formGroup\r\n */\r\n public createValidationMessagesForFormControlsAndNames(formControlNamesArray: { name: string, id: string, formControl: UntypedFormControl, elementValidationMessages: { validationFn: string, message: string }[] }[]): { message: string, elementId: string }[] {\r\n const validationMessages: { message: string, elementId: string }[] = [];\r\n formControlNamesArray.forEach((formElement) => {\r\n const formFieldErrors: ValidationErrors = formElement.formControl.errors;\r\n if (formFieldErrors) {\r\n const fieldValidationMessage = this.createSummaryError(formFieldErrors, formElement.elementValidationMessages);\r\n if (fieldValidationMessage) {\r\n validationMessages.push({ message: fieldValidationMessage, elementId: formElement.id });\r\n }\r\n }\r\n })\r\n return validationMessages;\r\n }\r\n\r\n /**\r\n * Given a validation error and a key of a form control, creates a printable validation message.\r\n * @param formFieldErrors\r\n * @param formFieldKey\r\n */\r\n public createSummaryError(formFieldErrors: ValidationErrors, validationMessages: { validationFn: string, message: string }[]): string {\r\n let fieldValidationMessage: string;\r\n Object.keys(formFieldErrors).forEach((fieldError) => {\r\n fieldValidationMessage = validationMessages.find(m => m.validationFn === fieldError)?.message;\r\n })\r\n return fieldValidationMessage;\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { ReactiveFormService } from './reactive-form.service';\r\nimport { DataInput } from '../../interfaces/form/data-input';\r\nimport { LayoutItem } from '../../interfaces/form/layout-item';\r\nimport { Element } from '../../interfaces/form/element';\r\nimport { Validation } from '../../interfaces/form/validation';\r\nimport { ValidationFunctionType } from '../../interfaces/form/enums/validation-function-type-enum';\r\nimport { AbstractControl, UntypedFormControl } from '@angular/forms';\r\nimport { ValidationSummaryService } from '../validation-summary.service';\r\nimport { Subject } from 'rxjs';\r\nimport { UIElementType } from '../../interfaces/form/enums/uielement-type-enum';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\n/**\r\n * This class implements all the services that are perform in order to\r\n * apply the form elements logic functions sent in the Validations attribute of the elements.\r\n */\r\nexport class ElementValidationService {\r\n\r\n // Summary of the validation of the overall form\r\n public validationMessages: { message: string, elementId: string }[] = [];\r\n\r\n // Summary of the validation of the currently opened table. NOTE: must be cleared on table open\r\n public tableValidationMessages: { message: string, elementId: string }[] = [];\r\n\r\n //Broadcasts a potential change in any attribute of the form control whose ID is broadcasted and\r\n //that belongs to the form structure\r\n public formElementChanged: Subject<{ elementId: string, functionType: ValidationFunctionType }> = new Subject();\r\n\r\n constructor(private formService: ReactiveFormService, private validationSummaryService: ValidationSummaryService) { }\r\n\r\n /**\r\n * The logic functions sent in the Validations attribute of a given element are applied by calling this method.\r\n * @param element with the element where the validation is applied\r\n * @param value with the value of the component representing the element\r\n * @param belongsToTableId indicating whether the table ID if element is placed in a table layout item. Null for\r\n * module elements outside tables\r\n */\r\n applyElementValidations(element: Element, value: unknown[], belongsToTableId: string) {\r\n element.Validations.forEach((validation) => {\r\n if (validation.TargetElementID && validation.Condition) {\r\n this.applyValidation(validation, this.prepareValueString(value, element.UIElement), belongsToTableId);\r\n }\r\n })\r\n }\r\n\r\n\r\n /**\r\n * Transform the unknown type input value to a string ready to be compared against the element's\r\n * validation conditions.\r\n * @param value\r\n * @param elementInputType\r\n * @returns\r\n */\r\n private prepareValueString(value: unknown[], elementInputType: UIElementType): string[] {\r\n let valuesString: string[] = [];\r\n if (value) {\r\n valuesString = value.map((v:string) => {\r\n if (v != null) {\r\n return String(v);\r\n } else {\r\n return \"null\";\r\n }\r\n });\r\n } else {\r\n if (elementInputType === UIElementType.CheckEditLeftLabel ||\r\n elementInputType === UIElementType.CheckEditRightLabel ||\r\n elementInputType === UIElementType.CheckEditRightLabelDescription) {\r\n // Case of a checkbox with null value, it is considered as false in the validation\r\n valuesString = [\"false\"];\r\n } else {\r\n valuesString = [\"null\"];\r\n }\r\n \r\n }\r\n return valuesString;\r\n }\r\n\r\n /**\r\n * Transforms the value from an UPDATE validation type into a valid format, when required.\r\n * @param value\r\n * @returns\r\n */\r\n private prepareStringValue(value: unknown): unknown {\r\n let transformedValue: unknown; \r\n if (value) {\r\n\r\n if (value.toString().toLowerCase() === \"null\") {\r\n transformedValue = null;\r\n } else if (value.toString().toLowerCase() === \"false\") {\r\n transformedValue = false;\r\n } else if (value.toString().toLowerCase() === \"true\") {\r\n transformedValue = true;\r\n } else {\r\n transformedValue = value;\r\n }\r\n \r\n }\r\n return transformedValue;\r\n }\r\n\r\n /**\r\n * Applies a logic function. Assumes that the logic function in the Validations array element has a condition,\r\n * otherwise it could lead to errors.\r\n * @param validation\r\n * @param valuesString string version of the chosen element input value\r\n * @param belongsToTable indicating whether the table ID if element is placed in a table layout item. Null for\r\n * module elements outside tables\r\n */\r\n private applyValidation(validation: Validation, valuesString: string[], belongsToTableId: string) {\r\n const triggerAction = this.isActionToBeTriggered(validation, valuesString);\r\n\r\n switch (validation.FunctionType) {\r\n case ValidationFunctionType.UIVisible:\r\n if (triggerAction) {\r\n this.formService.showElementFormGroup(validation.TargetElementID, belongsToTableId);\r\n } else {\r\n this.formService.hideElementFormGroup(validation.TargetElementID, belongsToTableId);\r\n }\r\n break;\r\n case ValidationFunctionType.UIEnable:\r\n if (this.formService.enableElementValueFormControl(validation.TargetElementID, triggerAction, belongsToTableId)) {\r\n // Broadcast that there was a change for the form elements to be aware and take action if needed\r\n this.formElementChanged.next({ elementId: validation.TargetElementID, functionType: ValidationFunctionType.UIEnable });\r\n }\r\n break;\r\n case ValidationFunctionType.PlausiRequired:\r\n if (this.formService.controlElementRequiredAttribute(validation.TargetElementID, triggerAction, belongsToTableId)) {\r\n // Broadcast that there was a change for the form elements to be aware and take action if needed\r\n this.formElementChanged.next({ elementId: validation.TargetElementID, functionType: ValidationFunctionType.PlausiRequired });\r\n }\r\n break;\r\n case ValidationFunctionType.Update:\r\n case ValidationFunctionType.InteractiveUpdate: {\r\n if (triggerAction) {\r\n if (this.formService.updateElementFormControlValue(validation.TargetElementID, this.prepareStringValue(validation.Value), belongsToTableId)) {\r\n // Broadcast that there was a change for the form elements to be aware and take action if needed.\r\n // For Webforms, InteractiveUpdate and Update are the same, soy both are set as Update\r\n this.formElementChanged.next({ elementId: validation.TargetElementID, functionType: ValidationFunctionType.Update });\r\n }\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Determines if an action is to be triggered according to the current value of the elemnt and the conditions for its validation.\r\n * @param validation\r\n * @param valuesString\r\n * @returns\r\n */\r\n private isActionToBeTriggered(validation: Validation, valuesString: string[]): boolean {\r\n // const testCondition = \"!1, 2, NULL, !(3,4,5), !7, 8\";\r\n const conditions = validation.Condition.split(',').map((cond) => {\r\n let transformedCondition = cond.toLowerCase();\r\n if (transformedCondition.startsWith(\"not \")) {\r\n // Sometimes negated conditions come as \"NOT \"\r\n transformedCondition = transformedCondition.replace(\"not \", \"!\");\r\n }\r\n return transformedCondition;\r\n });\r\n \r\n // This flag is created for indicating that there's a negation group !(a, b, c)\r\n let isInNegatedGroup = false;\r\n // This flag will be activated when the value meets any condition (either positive or negative)\r\n // and therefore the evaluation must be stopped\r\n let metCondition = false;\r\n // This flag will be activated when the condition met is positive and therefore action is to be executed\r\n let triggerAction = true;\r\n\r\n for (let condition of conditions) {\r\n // Case of the first element of a negated group in a condition\r\n if (condition.startsWith(\"!(\")) {\r\n isInNegatedGroup = true;\r\n condition = condition.substring(condition.indexOf(\"!(\") + 2);\r\n if (condition.endsWith(\")\")) {\r\n condition = condition.substring(0, condition.indexOf(\")\") - 1);\r\n isInNegatedGroup = false;\r\n }\r\n const conditionChosen = this.isConditionChosen(condition, valuesString);\r\n if (conditionChosen) {\r\n metCondition = true;\r\n triggerAction = false;\r\n }\r\n // Case of a single negated element\r\n } else if (condition.startsWith(\"!\")) {\r\n condition = condition.substring(1);\r\n const conditionChosen = this.isConditionChosen(condition, valuesString);\r\n if (conditionChosen) {\r\n metCondition = true;\r\n triggerAction = false;\r\n }\r\n // Case of an element in a negated group that it is not the first one\r\n } else if (isInNegatedGroup) {\r\n if (condition.endsWith(\")\")) {\r\n condition = condition.substring(0, condition.indexOf(\")\"));\r\n isInNegatedGroup = false;\r\n }\r\n const conditionChosen = this.isConditionChosen(condition, valuesString);\r\n if (conditionChosen) {\r\n triggerAction = false;\r\n metCondition = true;\r\n }\r\n // Case of a not negated, simple condition\r\n } else {\r\n triggerAction = this.isConditionChosen(condition, valuesString);\r\n if (triggerAction) {\r\n metCondition = true;\r\n }\r\n }\r\n if (metCondition) {\r\n break;\r\n }\r\n }\r\n return triggerAction;\r\n }\r\n\r\n /**\r\n * Determines if an input value deals with a condition element of a validation\r\n * @param condition\r\n * @param value\r\n * @returns\r\n */\r\n private isConditionChosen(condition: string, value: string[]): boolean {\r\n return value.find((v) =>\r\n v.toString() === condition.trim()\r\n ) !== undefined\r\n }\r\n\r\n /**\r\n * Updates the validation summary for a form or a table add/edit row form. In case of tables, requires\r\n * the table ID to which the input element belongs and the module index.\r\n * @param belongsToTableId\r\n * @param moduleIndex\r\n */\r\n updateValidationSummary(belongsToTableId: string, moduleIndex: number) {\r\n if (belongsToTableId) {\r\n if (this.tableValidationMessages.length > 0) {\r\n this.setValidationSummaryForTableId(belongsToTableId, moduleIndex);\r\n }\r\n } else if (this.validationMessages.length > 0) {\r\n this.setValidationSummary();\r\n }\r\n }\r\n\r\n /**\r\n * It sets a set of messages for each field that requires validation and this validation has failed.\r\n */\r\n public setValidationSummary() {\r\n const formControlsToBeValidated: { name: string, id: string, formControl: UntypedFormControl, elementValidationMessages: { validationFn: string, message: string }[] }[] = [];\r\n if (this.formService.getReactiveForm()) {\r\n this.formService.modulesArray.controls.forEach((module, moduleIndex) => {\r\n this.formService.getLayoutItemsArrayFromModuleNumber(moduleIndex).controls.forEach((layoutItemGroup) => {\r\n const elementValue = layoutItemGroup.get('value') as UntypedFormControl;\r\n if (elementValue && !elementValue.valid && !elementValue.disabled && !layoutItemGroup.get('avoidSubmitting').value && layoutItemGroup.get('visible').value) {\r\n formControlsToBeValidated.push({\r\n name: layoutItemGroup.get('label').value, id: \"input-\" + layoutItemGroup.get('id').value,\r\n formControl: elementValue,\r\n elementValidationMessages: layoutItemGroup.get(\"validationMessages\").value\r\n });\r\n }\r\n })\r\n })\r\n }\r\n this.validationMessages = this.validationSummaryService.createValidationMessagesForFormControlsAndNames(formControlsToBeValidated);\r\n }\r\n\r\n\r\n /**\r\n * Gets the validation message corresponding to an specific element from the validation summary\r\n * messages list.\r\n * @param elementFormGroup with the form group corresponding to the input edit element\r\n * @returns\r\n */\r\n public getValidationMessageForElementFormGroup(elementFormGroup: AbstractControl): string {\r\n return this.validationSummaryService.createSummaryError((elementFormGroup.get('value') as UntypedFormControl).errors, elementFormGroup.get('validationMessages').value);\r\n }\r\n\r\n /**\r\n * It sets a set of messages for each field of the table passed in the parameters that requires validation\r\n * and this validation has failed.\r\n * @param tableid\r\n * @param moduleIndex\r\n */\r\n public setValidationSummaryForTableId(tableId: string, moduleIndex: number) {\r\n this.clearValidationSummaryForTable();\r\n const formControlsToBeValidated: { name: string, id: string, formControl: UntypedFormControl, elementValidationMessages: { validationFn: string, message: string }[] }[] = [];\r\n const tableEditElementsFormGroups = this.formService.searchTableEditElementFormGroupsByTableId(tableId, moduleIndex);\r\n if (tableEditElementsFormGroups) {\r\n tableEditElementsFormGroups.forEach((layoutItemGroup) => {\r\n const elementValue = layoutItemGroup.get('value') as UntypedFormControl;\r\n if (elementValue && !elementValue.valid && !elementValue.disabled && layoutItemGroup.get('avoidSubmitting').value && layoutItemGroup.get('visible').value) {\r\n formControlsToBeValidated.push({\r\n name: layoutItemGroup.get('label').value,\r\n id: \"input-\" + layoutItemGroup.get('id').value,\r\n formControl: elementValue,\r\n elementValidationMessages: layoutItemGroup.get(\"validationMessages\").value\r\n });\r\n }\r\n })\r\n }\r\n this.tableValidationMessages = this.validationSummaryService.createValidationMessagesForFormControlsAndNames(formControlsToBeValidated);\r\n }\r\n\r\n /**\r\n * Clears the validation messages for the currently opened table. This function must be executed when\r\n * opening the add/edit row form of a table.\r\n */\r\n public clearValidationSummaryForTable() {\r\n this.tableValidationMessages = [];\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { ElementValidationService } from './element-validation.service';\r\nimport { Element } from '../../interfaces/form/element';\r\nimport { UntypedFormGroup } from '@angular/forms';\r\nimport { ValidationInformation } from '../../interfaces/form/elements/validation-information';\r\nimport { ElementChangeInformation } from '../../interfaces/form/elements/element-change-information';\r\nimport { ValidationFunctionType } from '../../interfaces/form/enums/validation-function-type-enum';\r\nimport { InputInformation } from '../../interfaces/form/elements/input-information';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\n\r\n/**\r\n * This service centralizes the operations made by the form elements\r\n * in different stages of the lifecycle (initialization, value change\r\n * validation status changes...)\r\n */\r\nexport class FormElementOperationsService {\r\n\r\n constructor(private validationService: ElementValidationService) { }\r\n\r\n /**\r\n * Obtains information for the form element to be properly rendered on initialization. Applies the logic\r\n * and validation functions for the current value.\r\n * @param element\r\n * @param elementFormGroup\r\n * @param inputValue\r\n * @returns information for input validation rendering\r\n */\r\n public initializeValidation(element: Element, elementFormGroup: UntypedFormGroup, inputValue: unknown): InputInformation {\r\n const elementRenderingInformation = {};\r\n elementRenderingInformation.validationInformation = this.checkValue(elementFormGroup);\r\n // When a table add/edit form is initialized, the validations must be applied for the initial input value\r\n if (element.Validations) {\r\n this.validationService.applyElementValidations(element, [inputValue], elementFormGroup.get(\"belongsToTableId\").value);\r\n }\r\n return elementRenderingInformation;\r\n }\r\n\r\n /**\r\n * After an form element's input value has changed, it updates the form structure, triggers the\r\n * element validation and also applies the validation and logic functions over the other elements,\r\n * if proceeding.\r\n * @param element\r\n * @param elementFormGroup\r\n * @param moduleIndex\r\n * @param inputValue\r\n * @param inputDisplayValue\r\n * @returns information for the validation rendering\r\n */\r\n public processValueChangeValidation(element: Element, elementFormGroup: UntypedFormGroup,\r\n moduleIndex: number, inputValue: unknown, inputDisplayValue: string): ValidationInformation {\r\n elementFormGroup.get('value').setValue(inputValue);\r\n elementFormGroup.get('value').markAsTouched();\r\n elementFormGroup.get('displayValue').setValue(inputDisplayValue);\r\n const validationInformation = this.checkValue(elementFormGroup);\r\n this.validationService.updateValidationSummary(elementFormGroup.get(\"belongsToTableId\")?.value, moduleIndex);\r\n if (element.Validations) { \r\n if (!Array.isArray(inputValue)) {\r\n this.validationService.applyElementValidations(element, [inputValue], elementFormGroup.get(\"belongsToTableId\").value);\r\n } else {\r\n this.validationService.applyElementValidations(element, inputValue, elementFormGroup.get(\"belongsToTableId\").value);\r\n }\r\n }\r\n return validationInformation;\r\n }\r\n\r\n /**\r\n * After an element has changed as a result of other element's logic/validation function, the\r\n * corresponding set of actions is performed here. \r\n * @param data\r\n * @param elementFormGroup\r\n * @param inputValue\r\n * @param inputDisplayValue\r\n * @returns\r\n */\r\n public processElementChangeValidation(data: ElementChangeInformation, elementFormGroup: UntypedFormGroup,\r\n inputValue: unknown): InputInformation {\r\n const elementRenderingInformation = {};\r\n if (data.elementFunctionChangeInformation.functionType === ValidationFunctionType.PlausiRequired) {\r\n elementFormGroup.get('value').setValue(inputValue);\r\n elementFormGroup.get('value').markAsTouched();\r\n } else if (data.elementFunctionChangeInformation.functionType === ValidationFunctionType.Update) {\r\n elementRenderingInformation.updatedAfterOperation = true;\r\n elementRenderingInformation.updatedValueAfterOperation = elementFormGroup.get('value')?.value;\r\n }\r\n elementRenderingInformation.validationInformation = this.checkValue(elementFormGroup);\r\n this.validationService.updateValidationSummary(elementFormGroup.get(\"belongsToTableId\")?.value, data.moduleIndex);\r\n return elementRenderingInformation\r\n }\r\n\r\n /**\r\n * Checks the validity of the current value of the reactive form structure for this element\r\n * and updates the validation information for the component to show it.\r\n * @returns\r\n */\r\n public checkValue(elementFormGroup: UntypedFormGroup): ValidationInformation {\r\n const validationInformation = {};\r\n validationInformation.valid = elementFormGroup.valid;\r\n // If the value isn't valid, update the validation message for the input element\r\n validationInformation.validationMessage = {\r\n message: validationInformation.valid ? null : this.validationService.getValidationMessageForElementFormGroup(elementFormGroup)\r\n };\r\n return validationInformation;\r\n }\r\n\r\n}\r\n","import { Component, OnInit, Input } from '@angular/core';\r\nimport { Element } from '../../../../interfaces/form/element';\r\nimport { ElementValidationService } from '../../../../services/form/element-validation.service';\r\nimport { ValueChangedEvent } from 'devextreme/ui/text_box';\r\nimport { UntypedFormGroup } from '@angular/forms';\r\nimport { FormElementOperationsService } from '../../../../services/form/form-element-operations.service';\r\nimport { ElementChangeInformation } from '../../../../interfaces/form/elements/element-change-information';\r\nimport { ElementFunctionChangeInformation } from '../../../../interfaces/form/elements/element-function-change-information';\r\nimport { InputInformation } from '../../../../interfaces/form/elements/input-information';\r\n\r\n@Component({\r\n selector: 'app-text-edit',\r\n templateUrl: './text-edit.component.html',\r\n styleUrls: ['./text-edit.component.less'],\r\n})\r\n/**\r\n * This component implements the logic related to the text edit fields.\r\n */\r\nexport class TextEditComponent implements OnInit {\r\n\r\n @Input() element: Element;\r\n @Input() inputFormGroup: UntypedFormGroup;\r\n @Input() moduleIndex: number;\r\n @Input() labelPosition: string;\r\n\r\n public inputValue: string;\r\n\r\n public renderingInformation: InputInformation;\r\n\r\n\r\n constructor(private validationService: ElementValidationService, private elementOperations: FormElementOperationsService) { }\r\n\r\n ngOnInit(): void {\r\n this.inputValue = typeof this.inputFormGroup.get(\"value\")?.value === 'string' ? this.inputFormGroup.get(\"value\")?.value : \"\";\r\n this.inputFormGroup.get('displayValue').setValue(this.inputValue);\r\n this.renderingInformation = this.elementOperations.initializeValidation(this.element, this.inputFormGroup,\r\n this.inputValue);\r\n this.subscribeToElementChanges();\r\n }\r\n\r\n /**\r\n * With each input change, updates the value in the reactive form structure and checks the\r\n * validity of the chosen value, updating also the validation message.\r\n * @param enteredValue\r\n */\r\n valueChanged(enteredValue: ValueChangedEvent) {\r\n this.renderingInformation.validationInformation = this.elementOperations.processValueChangeValidation(\r\n this.element, this.inputFormGroup, this.moduleIndex, enteredValue.value, enteredValue.value);\r\n }\r\n\r\n /**\r\n * Each time that the status in this form element is changed by another element with either\r\n * validations of logic functions, the change is produced in the element form group of the reactive\r\n * form structure, then broadcasted and finally listened here, where the info is updated.\r\n */\r\n private subscribeToElementChanges() {\r\n this.validationService.formElementChanged.subscribe((data: ElementFunctionChangeInformation) => {\r\n if (data.elementId === this.element.ElementID) {\r\n const elementChangeInfo = {} as ElementChangeInformation;\r\n elementChangeInfo.elementFunctionChangeInformation = data;\r\n elementChangeInfo.element = this.element;\r\n elementChangeInfo.moduleIndex = this.moduleIndex;\r\n this.renderingInformation = this.elementOperations.processElementChangeValidation(\r\n elementChangeInfo, this.inputFormGroup, this.inputValue);\r\n if (this.renderingInformation.updatedAfterOperation) {\r\n this.inputValue = this.renderingInformation.updatedValueAfterOperation as string;\r\n this.inputFormGroup.get('displayValue').setValue(this.inputValue);\r\n }\r\n }\r\n })\r\n }\r\n\r\n\r\n}\r\n","
\r\n \r\n
\r\n","import { Component, OnInit, Input } from '@angular/core';\r\nimport { Element } from '../../../../interfaces/form/element';\r\nimport { ElementValidationService } from '../../../../services/form/element-validation.service';\r\nimport { StringUtilsService } from '../../../../services/string-utils.service';\r\nimport { ValueChangedEvent } from 'devextreme/ui/date_box';\r\nimport { UntypedFormGroup } from '@angular/forms';\r\nimport { FormElementOperationsService } from '../../../../services/form/form-element-operations.service';\r\nimport { ElementFunctionChangeInformation } from '../../../../interfaces/form/elements/element-function-change-information';\r\nimport { ElementChangeInformation } from '../../../../interfaces/form/elements/element-change-information';\r\nimport { InputInformation } from '../../../../interfaces/form/elements/input-information';\r\n\r\n@Component({\r\n selector: 'app-date-edit',\r\n templateUrl: './date-edit.component.html',\r\n styleUrls: ['./date-edit.component.less']\r\n})\r\n\r\n/**\r\n* Component belonging to the date input form elements.\r\n*/\r\nexport class DateEditComponent implements OnInit {\r\n\r\n @Input() element: Element;\r\n @Input() moduleIndex: number;\r\n @Input() labelPosition: string;\r\n @Input() inputFormGroup: UntypedFormGroup;\r\n @Input() fixedWidth: number;\r\n @Input() includeTime: boolean;\r\n\r\n public dateValue: Date;\r\n\r\n public renderingInformation: InputInformation;\r\n\r\n public dateBoxWidth: string;\r\n public dateBoxType: string;\r\n public dateDisplayFormat: string;\r\n\r\n constructor(private validationService: ElementValidationService, private stringUtils: StringUtilsService, private elementOperations: FormElementOperationsService) {\r\n // Making the component context available in the validity check function callback\r\n this.isValid = this.isValid.bind(this); \r\n }\r\n\r\n /**\r\n * Initialization method. Formats the input component according to the inputs.\r\n */\r\n ngOnInit(): void {\r\n if (this.fixedWidth) {\r\n this.dateBoxWidth = this.fixedWidth ? String(this.fixedWidth) : 'auto';\r\n this.dateBoxType = \"date\";\r\n }\r\n if (!this.includeTime) {\r\n this.dateDisplayFormat = \"dd.MM.yyyy\";\r\n this.dateBoxType = \"date\";\r\n } else {\r\n this.dateDisplayFormat = \"dd.MM.yyyy HH:mm\";\r\n this.dateBoxType = \"datetime\";\r\n }\r\n const value = this.inputFormGroup.get('value').value;\r\n this.updateDateInputValue(value);\r\n this.updateDateDisplayValue();\r\n this.renderingInformation = this.elementOperations.initializeValidation(this.element, this.inputFormGroup,\r\n this.dateValue);\r\n this.subscribeToElementChanges();\r\n }\r\n\r\n\r\n /**\r\n * With each input change, updates the value in the reactive form structure and checks the\r\n * validity of the chosen value, updating also the validation message.\r\n * This method is necessary because of a DevExtreme limitation that prevents the \"valid\" attribute\r\n * from working with reactive forms validation.\r\n * @param e\r\n * @returns\r\n */\r\n isValid(e: any): boolean {\r\n if (e.value !== undefined) { \r\n this.inputFormGroup.get('value').setValue(e.value);\r\n }\r\n return this.elementOperations.checkValue(this.inputFormGroup).valid;\r\n }\r\n\r\n /**\r\n * After a value was changed in the input, updates the display value in the reactive form structure\r\n * and also updates the validation summary with the potential errors that the value could have.\r\n * @param event\r\n */\r\n valueChanged(event: ValueChangedEvent) {\r\n this.dateValue = event.value;\r\n this.renderingInformation.validationInformation = this.elementOperations.processValueChangeValidation(\r\n this.element, this.inputFormGroup, this.moduleIndex, this.dateValue, this.dateValue ? this.stringUtils.convertDateToDateString(event.value, this.includeTime) : \"\");\r\n }\r\n\r\n /**\r\n * Each time that the status in this form element is changed by another element with either\r\n * validations of logic functions, the change is produced in the element form group of the reactive\r\n * form structure, then broadcasted and finally listened here, where the info is updated.\r\n */\r\n private subscribeToElementChanges() {\r\n this.validationService.formElementChanged.subscribe((data: ElementFunctionChangeInformation) => {\r\n if (data.elementId === this.element.ElementID) {\r\n const elementChangeInfo = {} as ElementChangeInformation;\r\n elementChangeInfo.elementFunctionChangeInformation = data;\r\n elementChangeInfo.element = this.element;\r\n elementChangeInfo.moduleIndex = this.moduleIndex;\r\n this.renderingInformation = this.elementOperations.processElementChangeValidation(\r\n elementChangeInfo, this.inputFormGroup, this.dateValue);\r\n if (this.renderingInformation.updatedAfterOperation) {\r\n this.updateDateInputValue(this.renderingInformation.updatedValueAfterOperation);\r\n this.updateDateDisplayValue();\r\n }\r\n }\r\n })\r\n }\r\n\r\n /**\r\n * Updates the date input value with the value passed in the parameter.\r\n * @param value\r\n */\r\n private updateDateInputValue(value: unknown) {\r\n if (value && String(value).trim().length) {\r\n this.dateValue = new Date(value as string);\r\n } else {\r\n this.dateValue = null;\r\n }\r\n }\r\n\r\n /**\r\n * From the current value in the date input, the displayValue form control\r\n * is updated.\r\n */\r\n private updateDateDisplayValue() {\r\n if (this.dateValue) {\r\n this.inputFormGroup.get('displayValue').setValue(this.stringUtils.convertDateToDateString(this.dateValue, this.includeTime));\r\n } else {\r\n this.inputFormGroup.get('displayValue').setValue(null);\r\n }\r\n }\r\n}\r\n","
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n","export enum ElementItemsSortMode {\r\n Alphabetic = 0,\r\n SortNr = 1,\r\n}","import { Injectable } from '@angular/core';\r\nimport { Item } from '../interfaces/form/item';\r\nimport { ElementItemsSortMode } from '../interfaces/form/enums/element-items-sort-mode-enum';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\n\r\n/**\r\n * This class is in charge of centralizìng the operations related to the\r\n * Item array belonging to an Element object.\r\n */\r\nexport class ItemService {\r\n\r\n /**\r\n * Sort the selectable items of an element by their sort attribute.\r\n * @param itemsToSort\r\n * @returns\r\n */\r\n public sortItemsBySortAttribute(itemsToSort: Item[], itemsSortMode: ElementItemsSortMode): Item[] {\r\n if (itemsSortMode === ElementItemsSortMode.SortNr) {\r\n return itemsToSort.sort((a, b) => {\r\n if (a.Sort > b.Sort) {\r\n return 1\r\n } else if (a.Sort < b.Sort) {\r\n return -1\r\n } else {\r\n return 0\r\n }\r\n\r\n })\r\n } else if (itemsSortMode === ElementItemsSortMode.Alphabetic) {\r\n return itemsToSort.sort(function (a, b) {\r\n return a.DisplayName.toLowerCase().localeCompare(b.DisplayName.toLowerCase());\r\n })\r\n } else {\r\n return itemsToSort;\r\n }\r\n }\r\n}\r\n","import { Component, OnInit, Input, ViewChild } from '@angular/core';\r\nimport { Element } from '../../../../interfaces/form/element';\r\nimport { Item } from '../../../../interfaces/form/item';\r\nimport { DxTreeViewComponent} from 'devextreme-angular';\r\nimport { ElementValidationService } from '../../../../services/form/element-validation.service';\r\nimport { StringUtilsService } from '../../../../services/string-utils.service';\r\nimport { ValueChangedEvent } from 'devextreme/ui/drop_down_box';\r\nimport dxTreeView, { ItemSelectionChangedEvent } from 'devextreme/ui/tree_view';\r\nimport { ItemService } from '../../../../services/item.service';\r\nimport { UntypedFormGroup } from '@angular/forms';\r\nimport { FormElementOperationsService } from '../../../../services/form/form-element-operations.service';\r\nimport { ElementFunctionChangeInformation } from '../../../../interfaces/form/elements/element-function-change-information';\r\nimport { ElementChangeInformation } from '../../../../interfaces/form/elements/element-change-information';\r\nimport { InputInformation } from '../../../../interfaces/form/elements/input-information';\r\n\r\n@Component({\r\n selector: 'app-lookup-edit',\r\n templateUrl: './lookup-edit.component.html',\r\n styleUrls: ['./lookup-edit.component.less']\r\n})\r\n/**\r\n* Component belonging to the drop down box form elements that use a DxTreeView for listing.\r\n*/\r\nexport class LookupEditComponent implements OnInit {\r\n\r\n @ViewChild(DxTreeViewComponent, { static: false }) treeView: DxTreeViewComponent;\r\n\r\n @Input() element: Element;\r\n @Input() inputFormGroup: UntypedFormGroup;\r\n @Input() moduleIndex: number;\r\n @Input() labelPosition: string;\r\n @Input() checkBoxes: boolean;\r\n @Input() search: boolean;\r\n\r\n public sortedItems: Item[] = [];\r\n private _selectedItem: string[];\r\n\r\n public renderingInformation: InputInformation;\r\n\r\n public isDropDownBoxOpened = false;\r\n public selectionMode: string;\r\n public showCheckBoxesMode: string;\r\n\r\n constructor(private validationService: ElementValidationService, private stringUtils: StringUtilsService,\r\n private itemService: ItemService, private elementOperations: FormElementOperationsService) { }\r\n\r\n /**\r\n * Intialization method that sets ready the options for the user to choose.\r\n * The component is then configured based on the inputs.\r\n */\r\n ngOnInit(): void {\r\n if (this.checkBoxes) {\r\n this.selectionMode = \"multiple\";\r\n this.showCheckBoxesMode = \"normal\";\r\n } else {\r\n this.selectionMode = \"single\";\r\n this.showCheckBoxesMode = \"none\";\r\n }\r\n const elementItems: Item[] = this.element.Items as Item[];\r\n if (elementItems.length) {\r\n this.sortedItems = this.itemService.sortItemsBySortAttribute(elementItems, this.element.ElementItemsSortMode);\r\n // If there is an initial value, take it from the form control value and set it in the item values array\r\n const elementValue = this.inputFormGroup.get(\"value\")?.value;\r\n if (elementValue) {\r\n this._selectedItem = (Array.isArray(elementValue) ? elementValue : [elementValue]) as string[];\r\n this.inputFormGroup.get(\"value\").setValue(this._selectedItem);\r\n this.inputFormGroup.get('displayValue').setValue(this.getDisplayValue());\r\n }\r\n }\r\n this.renderingInformation = this.elementOperations.initializeValidation(this.element, this.inputFormGroup,\r\n this.selectedItem);\r\n this.subscribeToElementChanges();\r\n}\r\n\r\n /**\r\n * Getter method of the selection.\r\n */\r\n get selectedItem(): string[] {\r\n return this._selectedItem;\r\n }\r\n\r\n /**\r\n * Setter method of the selection.\r\n */\r\n set selectedItem(value: string[]) {\r\n this._selectedItem = value;\r\n }\r\n\r\n /**\r\n * If the value attribute of the drop down box changes because the user changed the selection,\r\n * the DevExtreme component requires the selection of the tree view to be updated.\r\n * @param e\r\n */\r\n onDropDownBoxValueChanged(e: ValueChangedEvent) {\r\n this.updateSelection(this.treeView && this.treeView.instance);\r\n }\r\n\r\n /**\r\n * Updates the tree view selection.\r\n * @param treeView\r\n * @returns\r\n */\r\n updateSelection(treeView: dxTreeView) {\r\n if (!treeView) return;\r\n\r\n if (!this.selectedItem) {\r\n treeView.unselectAll();\r\n }\r\n this.renderingInformation.validationInformation = this.elementOperations.processValueChangeValidation(\r\n this.element, this.inputFormGroup, this.moduleIndex, this._selectedItem, this.getDisplayValue());\r\n }\r\n\r\n\r\n /**\r\n * Event listener when the user performs a selection. The selecion is assigned and the list of options is hidden.\r\n * @param args\r\n */\r\n changeLookupEditValue(args: ItemSelectionChangedEvent) {\r\n this._selectedItem = args.component.getSelectedNodeKeys();\r\n if (this.selectionMode === \"single\") {\r\n this.isDropDownBoxOpened = false;\r\n }\r\n \r\n }\r\n\r\n /**\r\n * Gets the display value form control of this input element's form group.\r\n * @param valuesArray\r\n */\r\n private getDisplayValue():string {\r\n let displayValue: string = null;\r\n if (this.selectedItem) {\r\n const userSelectedItems: Item[] = [];\r\n this.selectedItem.forEach(((item) => {\r\n const foundSelectedItem: Item = this.sortedItems.find((elementItem) => elementItem.Value === item);\r\n userSelectedItems.push(foundSelectedItem);\r\n }));\r\n if (this.checkBoxes) {\r\n displayValue = this.stringUtils.convertItemsArrayToItemsDisplayName(userSelectedItems);\r\n } else if (userSelectedItems.length) {\r\n displayValue = userSelectedItems[0].DisplayName;\r\n }\r\n } else {\r\n displayValue = \"\";\r\n }\r\n return displayValue;\r\n }\r\n\r\n /**\r\n * Each time that the status in this form element is changed by another element with either\r\n * validations of logic functions, the change is produced in the element form group of the reactive\r\n * form structure, then broadcasted and finally listened here, where the info is updated.\r\n */\r\n private subscribeToElementChanges() {\r\n this.validationService.formElementChanged.subscribe((data: ElementFunctionChangeInformation) => {\r\n if (data.elementId === this.element.ElementID) {\r\n const elementChangeInfo = {} as ElementChangeInformation;\r\n elementChangeInfo.elementFunctionChangeInformation = data;\r\n elementChangeInfo.element = this.element;\r\n elementChangeInfo.moduleIndex = this.moduleIndex;\r\n this.renderingInformation = this.elementOperations.processElementChangeValidation(\r\n elementChangeInfo, this.inputFormGroup, this._selectedItem);\r\n if (this.renderingInformation.updatedAfterOperation) {\r\n this._selectedItem = Array.isArray(this.renderingInformation.updatedValueAfterOperation) ?\r\n this.renderingInformation.updatedValueAfterOperation : [this.renderingInformation.updatedValueAfterOperation];\r\n this.inputFormGroup.get('value').setValue(this._selectedItem);\r\n this.inputFormGroup.get('displayValue').setValue(this.getDisplayValue());\r\n }\r\n }\r\n })\r\n }\r\n}\r\n","
\r\n \r\n \r\n \r\n \r\n
\r\n","import { Component, OnInit, Input } from '@angular/core';\r\nimport DataSource from 'devextreme/data/data_source';\r\nimport { Element } from '../../../../interfaces/form/element';\r\nimport { Item } from '../../../../interfaces/form/item';\r\nimport { ElementValidationService } from '../../../../services/form/element-validation.service';\r\nimport { CustomItemCreatingEvent, SelectionChangedEvent } from 'devextreme/ui/select_box';\r\nimport { ItemService } from '../../../../services/item.service';\r\nimport { UntypedFormGroup } from '@angular/forms';\r\nimport { FormElementOperationsService } from '../../../../services/form/form-element-operations.service';\r\nimport { ElementFunctionChangeInformation } from '../../../../interfaces/form/elements/element-function-change-information';\r\nimport { ElementChangeInformation } from '../../../../interfaces/form/elements/element-change-information';\r\nimport { InputInformation } from '../../../../interfaces/form/elements/input-information';\r\n\r\n@Component({\r\n selector: 'app-combo-box-edit',\r\n templateUrl: './combo-box-edit.component.html',\r\n styleUrls: ['./combo-box-edit.component.less']\r\n})\r\n/**\r\n * This component implements the logic for the combo box edit component.\r\n */\r\nexport class ComboBoxEditComponent implements OnInit {\r\n\r\n @Input() element: Element;\r\n @Input() inputFormGroup: UntypedFormGroup;\r\n @Input() moduleIndex: number;\r\n @Input() labelPosition: string;\r\n\r\n public sortedItems: Item[] = [];\r\n public itemsDataSource: DataSource;\r\n private _selectedItem: Item;\r\n\r\n public renderingInformation: InputInformation;\r\n\r\n constructor(private validationService: ElementValidationService, private itemService: ItemService, private elementOperations: FormElementOperationsService) { }\r\n\r\n /**\r\n * Initialization method where the items are loaded and stored in a data source for the view to handle them.\r\n */\r\n ngOnInit(): void {\r\n const elementItems: Item[] = this.element.Items as Item[];\r\n if (elementItems.length) {\r\n this.sortedItems = this.itemService.sortItemsBySortAttribute(elementItems, this.element.ElementItemsSortMode);\r\n this.itemsDataSource = new DataSource({\r\n store: {\r\n data: this.sortedItems,\r\n type: 'array',\r\n key: 'DisplayName',\r\n },\r\n });\r\n this.setInputFromValue();\r\n this.inputFormGroup.get('displayValue').setValue(this.selectedItem ? this.selectedItem.DisplayName : null);\r\n }\r\n this.renderingInformation = this.elementOperations.initializeValidation(this.element, this.inputFormGroup,\r\n this.selectedItem ? this.selectedItem.Value : null);\r\n this.subscribeToElementChanges();\r\n }\r\n\r\n /**\r\n * Method called when the user enters a value that wasn't belonging to the intially selected Items.\r\n * @param data\r\n * @returns\r\n */\r\n onCustomItemCreate(data: CustomItemCreatingEvent) {\r\n if (!data.text) {\r\n data.customItem = null;\r\n return;\r\n }\r\n this.addCustomItem(data.text);\r\n }\r\n \r\n /**\r\n * Adds a custom item to the seletable items list of the component.\r\n * @param customItemValue\r\n */\r\n private addCustomItem(customItemValue: unknown) {\r\n const newItemId = this.createCustomItemValueFromDisplayValue(customItemValue);\r\n const newItem = {\r\n Value: newItemId,\r\n DisplayName: customItemValue,\r\n };\r\n\r\n this.itemsDataSource.store().insert(newItem)\r\n .then(() => this.itemsDataSource.load())\r\n .then(() => newItem)\r\n .catch((error) => {\r\n throw error;\r\n });\r\n }\r\n\r\n /**\r\n * When the user inserts a custom value, it is taken as display value and here it is created\r\n * an unique value for that entered custom value.\r\n * @param customItemDisplayName\r\n * @returns\r\n */\r\n private createCustomItemValueFromDisplayValue(customItemDisplayName: unknown): string {\r\n return (customItemDisplayName as string) + this.sortedItems.length;\r\n }\r\n\r\n /**\r\n * Getter method of the selection.\r\n */\r\n get selectedItem(): Item {\r\n return this._selectedItem;\r\n }\r\n\r\n /**\r\n * Setter method of the selection.\r\n */\r\n set selectedItem(value: Item) {\r\n this._selectedItem = value;\r\n }\r\n\r\n /**\r\n * Event listener when the user performs a selection.\r\n * @param e\r\n */\r\n changeComboBoxEditValue(e: SelectionChangedEvent) {\r\n this.selectedItem = e.selectedItem;\r\n this.renderingInformation.validationInformation = this.elementOperations.processValueChangeValidation(\r\n this.element, this.inputFormGroup, this.moduleIndex, this.selectedItem ? this.selectedItem.Value : null,\r\n this.selectedItem ? this.selectedItem.DisplayName : null);\r\n }\r\n\r\n /**\r\n * Updates the input value according to the form of the element form control fromt he reative form structure.\r\n */\r\n private setInputFromValue() {\r\n const elementValue = this.inputFormGroup.get(\"value\")?.value;\r\n if (elementValue) {\r\n if (Array.isArray(elementValue)) {\r\n // It can happen (from excel import to table, for example) that the select values are\r\n // placed in an array\r\n this.selectedItem = this.sortedItems.find((item) =>\r\n (elementValue as string[]).indexOf(item.Value) !== -1\r\n )\r\n } else {\r\n this.selectedItem = this.sortedItems.find((item) =>\r\n item.Value === elementValue\r\n )\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Each time that the status in this form element is changed by another element with either\r\n * validations of logic functions, the change is produced in the element form group of the reactive\r\n * form structure, then broadcasted and finally listened here, where the info is updated.\r\n */\r\n private subscribeToElementChanges() {\r\n this.validationService.formElementChanged.subscribe((data: ElementFunctionChangeInformation) => {\r\n if (data.elementId === this.element.ElementID) {\r\n const elementChangeInfo = {} as ElementChangeInformation;\r\n elementChangeInfo.elementFunctionChangeInformation = data;\r\n elementChangeInfo.element = this.element;\r\n elementChangeInfo.moduleIndex = this.moduleIndex;\r\n this.renderingInformation = this.elementOperations.processElementChangeValidation(\r\n elementChangeInfo, this.inputFormGroup, this.selectedItem ? this.selectedItem.Value : null);\r\n if (this.renderingInformation.updatedAfterOperation) {\r\n this.setInputFromValue();\r\n this.inputFormGroup.get('displayValue').setValue(this.selectedItem ? this.selectedItem.DisplayName : null);\r\n }\r\n }\r\n })\r\n }\r\n\r\n}\r\n","
\r\n \r\n \r\n
\r\n","import { Component, OnInit, Input } from '@angular/core';\r\nimport { Element } from '../../../../interfaces/form/element';\r\nimport { ElementValidationService } from '../../../../services/form/element-validation.service';\r\nimport { StringUtilsService } from '../../../../services/string-utils.service';\r\nimport { ValueChangedEvent } from 'devextreme/ui/check_box';\r\nimport { UntypedFormGroup } from '@angular/forms';\r\nimport { FormElementOperationsService } from '../../../../services/form/form-element-operations.service';\r\nimport { ElementFunctionChangeInformation } from '../../../../interfaces/form/elements/element-function-change-information';\r\nimport { ElementChangeInformation } from '../../../../interfaces/form/elements/element-change-information';\r\nimport { InputInformation } from '../../../../interfaces/form/elements/input-information';\r\nimport { UIElementType } from '../../../../interfaces/form/enums/uielement-type-enum';\r\n\r\n@Component({\r\n selector: 'app-check-edit',\r\n templateUrl: './check-edit.component.html',\r\n styleUrls: ['./check-edit.component.less']\r\n})\r\nexport class CheckEditComponent implements OnInit {\r\n\r\n @Input() element: Element;\r\n @Input() inputFormGroup: UntypedFormGroup;\r\n @Input() moduleIndex: number;\r\n @Input() labelPosition: string;\r\n @Input() embeddedLabelPosition: string;\r\n\r\n public currentValue: boolean;\r\n\r\n public labelLeft: boolean;\r\n public labelEmbedded: boolean;\r\n\r\n public renderingInformation: InputInformation;\r\n\r\n constructor(private validationService: ElementValidationService, private stringUtils: StringUtilsService, private elementOperations: FormElementOperationsService) { }\r\n\r\n ngOnInit(): void {\r\n this.currentValue = this.inputFormGroup.get(\"value\")?.value ? true : false;\r\n this.inputFormGroup.get('displayValue').setValue(this.stringUtils.convertBooleanToYesNoString(this.currentValue));\r\n if (this.inputFormGroup.get('label')?.value && this.element.UIElement === UIElementType.CheckEditRightLabelDescription) {\r\n this.labelEmbedded = false;\r\n } else if (this.embeddedLabelPosition === \"left\") {\r\n this.labelEmbedded = true;\r\n this.labelLeft = true;\r\n } else {\r\n this.labelEmbedded = true;\r\n this.labelLeft = false;\r\n }\r\n this.renderingInformation = this.elementOperations.initializeValidation(this.element, this.inputFormGroup, this.currentValue);\r\n this.subscribeToElementChanges();\r\n }\r\n\r\n /**\r\n * On checkbox value change, emits the new value to the table component for representation\r\n * and triggers the validations.\r\n * @param e\r\n */\r\n valueChanged(e: ValueChangedEvent) {\r\n this.currentValue = e.value;\r\n this.renderingInformation.validationInformation = this.elementOperations.processValueChangeValidation(\r\n this.element, this.inputFormGroup, this.moduleIndex, e.value, this.stringUtils.convertBooleanToYesNoString(e.value));\r\n }\r\n\r\n /**\r\n * Each time that the status in this form element is changed by another element with either\r\n * validations of logic functions, the change is produced in the element form group of the reactive\r\n * form structure, then broadcasted and finally listened here, where the info is updated.\r\n */\r\n private subscribeToElementChanges() {\r\n this.validationService.formElementChanged.subscribe((data: ElementFunctionChangeInformation) => {\r\n if (data.elementId === this.element.ElementID) {\r\n const elementChangeInfo = {} as ElementChangeInformation;\r\n elementChangeInfo.elementFunctionChangeInformation = data;\r\n elementChangeInfo.element = this.element;\r\n elementChangeInfo.moduleIndex = this.moduleIndex;\r\n this.renderingInformation = this.elementOperations.processElementChangeValidation(\r\n elementChangeInfo, this.inputFormGroup, this.currentValue);\r\n if (this.renderingInformation.updatedAfterOperation) {\r\n this.currentValue = this.inputFormGroup.get(\"value\")?.value ? true : false;\r\n this.inputFormGroup.get('displayValue').setValue(this.stringUtils.convertBooleanToYesNoString(this.currentValue));\r\n }\r\n }\r\n })\r\n }\r\n}\r\n","
\r\n \r\n \r\n
\r\n","import { Pipe, PipeTransform } from '@angular/core';\r\n\r\n/*\r\n * Raise the value exponentially\r\n * Takes an exponent argument that defaults to 1. Due to\r\n * the JavaScript security restriction, the exponent is\r\n * limited to 16 (related to Number.MAX_SAFE_INTEGER from\r\n * JavaScript)\r\n * Usage:\r\n * value | mathPow:exponent\r\n * Example:\r\n * {{ 2 | mathPow:10 }}\r\n * formats to: 1024\r\n*/\r\n@Pipe({\r\n name: 'mathPow'\r\n})\r\nexport class MathPowPipe implements PipeTransform {\r\n\r\n transform(value: number, exponent = 1): number {\r\n if (exponent > 16) {\r\n exponent = 16;\r\n }\r\n return Math.pow(value, exponent);\r\n }\r\n\r\n}\r\n","import { Component, OnInit, Input, ViewChild, AfterViewInit } from '@angular/core';\r\nimport { Element } from '../../../../interfaces/form/element';\r\nimport { ElementValidationService } from '../../../../services/form/element-validation.service';\r\nimport { ValueChangedEvent } from 'devextreme/ui/number_box';\r\nimport { formatNumber, parseNumber } from 'devextreme/localization';\r\nimport { UntypedFormGroup } from '@angular/forms';\r\nimport { DxNumberBoxComponent } from 'devextreme-angular';\r\nimport Validator from \"devextreme/ui/validator\";\r\nimport { StringUtilsService } from '../../../../services/string-utils.service';\r\nimport { FormElementOperationsService } from '../../../../services/form/form-element-operations.service';\r\nimport { ElementFunctionChangeInformation } from '../../../../interfaces/form/elements/element-function-change-information';\r\nimport { ElementChangeInformation } from '../../../../interfaces/form/elements/element-change-information';\r\nimport { InputInformation } from '../../../../interfaces/form/elements/input-information';\r\n\r\n@Component({\r\n selector: 'app-number-box',\r\n templateUrl: './number-box.component.html',\r\n styleUrls: ['./number-box.component.less']\r\n})\r\n/**\r\n * Component dealing with the number related elements.\r\n */\r\nexport class NumberBoxComponent implements OnInit, AfterViewInit {\r\n\r\n @ViewChild('numberBoxValidator', { static: false }) public numberBoxInstance: DxNumberBoxComponent;\r\n\r\n @Input() element: Element;\r\n @Input() moduleIndex: number;\r\n @Input() inputFormGroup: UntypedFormGroup;\r\n @Input() labelPosition: string;\r\n @Input() currency: boolean;\r\n @Input() percentage: boolean;\r\n @Input() decimalDigits: number;\r\n\r\n public inputValue: number;\r\n\r\n public numberDisplayFormat: string;\r\n\r\n public renderingInformation: InputInformation;\r\n \r\n\r\n constructor(private validationService: ElementValidationService, private elementOperations: FormElementOperationsService, private stringUtils: StringUtilsService) {\r\n // Making the component context available in the validity check function callback\r\n this.isValid = this.isValid.bind(this);\r\n }\r\n\r\n /**\r\n * Initialization: setting input format depending on the component inputs.\r\n */\r\n ngOnInit(): void {\r\n this.numberDisplayFormat = this.stringUtils.getNumberTextFormat(this.currency, this.percentage, this.decimalDigits);\r\n this.setInputFromValue();\r\n this.inputFormGroup.get('displayValue').setValue(formatNumber(this.inputValue, this.numberDisplayFormat));\r\n this.renderingInformation = this.elementOperations.initializeValidation(this.element, this.inputFormGroup,\r\n this.inputValue);\r\n this.subscribeToElementChanges();\r\n }\r\n\r\n /**\r\n * After view initialization, the validator is taken here as instance for triggering the validation\r\n * from the beginning, just as the other elements. This case is special because of the uncompatibility\r\n * of the \"valid\" attribute with reactive forms (also happening in DateBox) and the fact that the validation\r\n * isn't automatically triggered after load (in DateBox this wasn't the case).\r\n */\r\n ngAfterViewInit() {\r\n const numberBoxValidator = Validator.getInstance(\r\n this.numberBoxInstance.instance.element()\r\n ) as Validator;\r\n numberBoxValidator?.validate();\r\n }\r\n\r\n /**\r\n * With each input change, updates the value in the reactive form structure and checks the\r\n * validity of the chosen value, updating also the validation message.\r\n * This method is necessary because of a DevExtreme limitation that prevents the \"valid\" attribute\r\n * from working with reactive forms validation.\r\n * @param e\r\n * @returns\r\n */\r\n isValid(e: any): boolean {\r\n this.inputFormGroup.get('value').setValue(e.value);\r\n return this.elementOperations.checkValue(this.inputFormGroup).valid;\r\n }\r\n\r\n /**\r\n * After a value was changed in the input, updates the display value in the reactive form structure\r\n * and also updates the validation summary with the potential errors that the value could have.\r\n * @param event\r\n */\r\n valueChanged(event: ValueChangedEvent) {\r\n this.inputValue = event.value;\r\n this.renderingInformation.validationInformation = this.elementOperations.processValueChangeValidation(\r\n this.element, this.inputFormGroup, this.moduleIndex, event.value, formatNumber(event.value, this.numberDisplayFormat));\r\n }\r\n\r\n /**\r\n * Updates the input value according to the form of the element form control fromt he reative form structure.\r\n */\r\n private setInputFromValue() {\r\n const value = this.inputFormGroup.get('value').value;\r\n if (value) {\r\n if (typeof value === 'number') {\r\n this.inputValue = value;\r\n } else {\r\n // For imported values from an excel, the value comes in a formatted string and must be parsed\r\n this.inputValue = parseNumber(value as string, this.numberDisplayFormat);\r\n }\r\n }\r\n }\r\n\r\n\r\n /**\r\n * Each time that the status in this form element is changed by another element with either\r\n * validations of logic functions, the change is produced in the element form group of the reactive\r\n * form structure, then broadcasted and finally listened here, where the info is updated.\r\n */\r\n private subscribeToElementChanges() {\r\n this.validationService.formElementChanged.subscribe((data: ElementFunctionChangeInformation) => {\r\n if (data.elementId === this.element.ElementID) {\r\n const elementChangeInfo = {} as ElementChangeInformation;\r\n elementChangeInfo.elementFunctionChangeInformation = data;\r\n elementChangeInfo.element = this.element;\r\n elementChangeInfo.moduleIndex = this.moduleIndex;\r\n this.renderingInformation = this.elementOperations.processElementChangeValidation(\r\n elementChangeInfo, this.inputFormGroup, this.inputValue);\r\n if (this.renderingInformation.updatedAfterOperation) {\r\n this.setInputFromValue();\r\n this.inputFormGroup.get('displayValue').setValue(formatNumber(this.inputValue, this.numberDisplayFormat));\r\n }\r\n }\r\n })\r\n }\r\n\r\n}\r\n","
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n","import { Injectable } from '@angular/core';\r\nimport { UIElementType } from '../../interfaces/form/enums/uielement-type-enum';\r\nimport { Element } from '../../interfaces/form/element';\r\nimport { UntypedFormGroup, Validators } from '@angular/forms';\r\nimport { LabelInformation } from '../../interfaces/form/elements/label-information';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\n\r\n/**\r\n * Provides functions that help rendering the form element labels.\r\n */\r\nexport class LabelService {\r\n\r\n /**\r\n * For a form input element, takes the necessary information for rendering the label\r\n * so it reflects the current status of the element (required * preffix, if the label is to\r\n * be rendered or not, etc)\r\n * @param element\r\n * @param elementFormGroup\r\n * @param labelPosition\r\n */\r\n getLabelInformation(element: Element, elementFormGroup: UntypedFormGroup, labelPosition: string): LabelInformation {\r\n const labelInformation = {} as LabelInformation;\r\n labelInformation.displayLabel = this.isLabelToBePrinted(element);\r\n labelInformation.labelClass = this.getLabelHtmlClass(elementFormGroup, labelPosition);\r\n return labelInformation;\r\n }\r\n\r\n /**\r\n * This method states for which elements the label should not be printed. These are:\r\n * - Tables\r\n * - Table column edit fields\r\n * - Label elements, where the labels will be printed in a separate component.\r\n * @param element with the element information\r\n */\r\n isLabelToBePrinted(element: Element): boolean {\r\n if (element.UIElement !== UIElementType.Table && element.UIElement !== UIElementType.Label\r\n && element.UIElement !== UIElementType.LabelUnderlineRightAlignment &&\r\n element.UIElement !== UIElementType.CheckEditLeftLabel && element.UIElement !== UIElementType.CheckEditRightLabel) {\r\n return true;\r\n } else {\r\n return false;\r\n }\r\n }\r\n\r\n\r\n /**\r\n * Creates the HTML class attributes for the label element of an element.\r\n * @param elementFormGroup\r\n * @param labelPosition\r\n * @returns\r\n */\r\n getLabelHtmlClass(elementFormGroup: UntypedFormGroup, labelPosition: string) {\r\n let labelClass = \"label\";\r\n if (labelPosition === \"Left\") {\r\n labelClass = labelClass.concat(\" label-left\");\r\n } else {\r\n labelClass = labelClass.concat(\" label-top\");\r\n }\r\n if (elementFormGroup.get(\"value\").hasValidator(Validators.required)) {\r\n labelClass = labelClass.concat(\" required\");\r\n }\r\n if (elementFormGroup.get(\"value\").disabled) {\r\n labelClass = labelClass.concat(\" disabled\");\r\n }\r\n return labelClass;\r\n }\r\n}\r\n","\r\n \r\n\r\n\r\n
\r\n \r\n
\r\n
\r\n","import { Component, Input, OnInit } from '@angular/core';\r\nimport { UntypedFormGroup } from '@angular/forms';\r\nimport { ElementValidationService } from '../../../../services/form/element-validation.service';\r\nimport { LabelService } from '../../../../services/form/label.service';\r\nimport { Element } from '../../../../interfaces/form/element';\r\nimport { ReactiveFormService } from '../../../../services/form/reactive-form.service';\r\nimport { ValidationFunctionType } from '../../../../interfaces/form/enums/validation-function-type-enum';\r\nimport { LabelInformation } from '../../../../interfaces/form/elements/label-information';\r\nimport { UIElementType } from '../../../../interfaces/form/enums/uielement-type-enum';\r\n\r\n@Component({\r\n selector: 'app-label',\r\n templateUrl: './label.component.html',\r\n styleUrls: ['./label.component.less']\r\n})\r\nexport class LabelComponent implements OnInit {\r\n\r\n @Input() labelText: string;\r\n @Input() element: Element;\r\n @Input() labelPosition: string;\r\n\r\n public inputFormGroup: UntypedFormGroup;\r\n\r\n public labelInformation: LabelInformation;\r\n\r\n constructor(public formService: ReactiveFormService, private validationService: ElementValidationService, private labelService: LabelService) { }\r\n\r\n ngOnInit(): void {\r\n if (this.element) {\r\n if (this.element.UIElement !== UIElementType.Table) { \r\n this.inputFormGroup = this.formService.searchElementFormGrouplInReactiveFormByElementId(this.element.ElementID, false) as UntypedFormGroup;\r\n this.labelInformation = this.labelService.getLabelInformation(this.element, this.inputFormGroup, this.labelPosition);\r\n this.subscribeToElementChanges();\r\n } else {\r\n this.inputFormGroup = this.formService.searchElementFormGrouplInReactiveFormByElementId(this.element.ElementTableID, true) as UntypedFormGroup;\r\n this.labelInformation = { displayLabel: true, labelClass: \"\" };\r\n }\r\n } \r\n }\r\n\r\n /**\r\n * Each time that the status in this form element is changed by another element with either\r\n * validations of logic functions, the change is produced in the element form group of the reactive\r\n * form structure, then broadcasted and finally listened here, where the info is updated.\r\n */\r\n private subscribeToElementChanges() {\r\n this.validationService.formElementChanged.subscribe((data: { elementId: string, functionType: ValidationFunctionType }) => {\r\n if (data.elementId === this.element.ElementID) {\r\n if (data.functionType === ValidationFunctionType.PlausiRequired || data.functionType === ValidationFunctionType.UIEnable) {\r\n // The label info is updated for a required element\r\n this.labelInformation = this.labelService.getLabelInformation(this.element, this.inputFormGroup, this.labelPosition);\r\n } \r\n \r\n }\r\n })\r\n }\r\n\r\n}\r\n","import { Component, OnInit, Input } from '@angular/core';\r\nimport { Element } from '../../../../interfaces/form/element';\r\nimport { Item } from '../../../../interfaces/form/item';\r\nimport { ElementValidationService } from '../../../../services/form/element-validation.service';\r\nimport { StringUtilsService } from '../../../../services/string-utils.service';\r\nimport { ValueChangedEvent } from 'devextreme/ui/tag_box';\r\nimport { ItemService } from '../../../../services/item.service';\r\nimport { UntypedFormGroup } from '@angular/forms';\r\nimport { FormElementOperationsService } from '../../../../services/form/form-element-operations.service';\r\nimport { ElementChangeInformation } from '../../../../interfaces/form/elements/element-change-information';\r\nimport { ElementFunctionChangeInformation } from '../../../../interfaces/form/elements/element-function-change-information';\r\nimport { InputInformation } from '../../../../interfaces/form/elements/input-information';\r\n\r\n@Component({\r\n selector: 'app-combo-box-edit-checkboxes',\r\n templateUrl: './combo-box-edit-checkboxes.component.html',\r\n styleUrls: ['./combo-box-edit-checkboxes.component.less']\r\n})\r\n/**\r\n * Component logic for combo box edit with checkboxes.\r\n */\r\nexport class ComboBoxEditCheckboxesComponent implements OnInit {\r\n\r\n @Input() element: Element;\r\n @Input() inputFormGroup: UntypedFormGroup;\r\n @Input() moduleIndex: number;\r\n @Input() labelPosition: string;\r\n\r\n public sortedItems: Item[] = [];\r\n public selectedItems: string[] = [];\r\n\r\n public renderingInformation: InputInformation;\r\n\r\n constructor(private validationService: ElementValidationService, private stringUtils: StringUtilsService,\r\n private itemService: ItemService, private elementOperations: FormElementOperationsService) { }\r\n\r\n /**\r\n * Initialization. Setting the selectable items.\r\n */\r\n ngOnInit(): void {\r\n const elementItems: Item[] = this.element.Items as Item[];\r\n if (elementItems.length) {\r\n this.sortedItems = this.itemService.sortItemsBySortAttribute(elementItems, this.element.ElementItemsSortMode);\r\n // If there is an initial value, take it from the form control value and set it in the item values array\r\n const elementValue = this.inputFormGroup.get(\"value\")?.value;\r\n if (elementValue) { \r\n this.selectedItems = (Array.isArray(elementValue) ? elementValue : [elementValue]) as string[];\r\n this.inputFormGroup.get(\"value\").setValue(this.selectedItems);\r\n this.inputFormGroup.get('displayValue').setValue(this.getDisplayValue(this.selectedItems));\r\n }\r\n }\r\n this.renderingInformation = this.elementOperations.initializeValidation(this.element, this.inputFormGroup,\r\n this.selectedItems);\r\n this.subscribeToElementChanges();\r\n }\r\n\r\n /**\r\n * Event listener when the user performs a selection.\r\n * @param e\r\n */\r\n changeComboBoxValue(e: ValueChangedEvent) {\r\n this.selectedItems = e.value;\r\n this.renderingInformation.validationInformation = this.elementOperations.processValueChangeValidation(\r\n this.element, this.inputFormGroup, this.moduleIndex, this.selectedItems, this.getDisplayValue(e.value));\r\n }\r\n\r\n /**\r\n * Forms the display value for the displayValue form control of this input element's form group.\r\n * @param valuesArray\r\n */\r\n private getDisplayValue(valuesArray: any[]): string {\r\n const emitItems: Item[] = [];\r\n valuesArray.forEach((value: string) => {\r\n emitItems.push(this.sortedItems.find((elementItem) => elementItem.Value === value));\r\n })\r\n return this.stringUtils.convertItemsArrayToItemsDisplayName(emitItems);\r\n }\r\n\r\n /**\r\n * Each time that the status in this form element is changed by another element with either\r\n * validations of logic functions, the change is produced in the element form group of the reactive\r\n * form structure, then broadcasted and finally listened here, where the info is updated.\r\n */\r\n private subscribeToElementChanges() {\r\n this.validationService.formElementChanged.subscribe((data: ElementFunctionChangeInformation) => {\r\n if (data.elementId === this.element.ElementID) {\r\n const elementChangeInfo = {} as ElementChangeInformation;\r\n elementChangeInfo.elementFunctionChangeInformation = data;\r\n elementChangeInfo.element = this.element;\r\n elementChangeInfo.moduleIndex = this.moduleIndex;\r\n this.renderingInformation = this.elementOperations.processElementChangeValidation(\r\n elementChangeInfo, this.inputFormGroup, this.selectedItems);\r\n if (this.renderingInformation.updatedAfterOperation) {\r\n this.selectedItems = Array.isArray(this.renderingInformation.updatedValueAfterOperation) ?\r\n this.renderingInformation.updatedValueAfterOperation : [this.renderingInformation.updatedValueAfterOperation];\r\n this.inputFormGroup.get('value').setValue(this.selectedItems);\r\n this.inputFormGroup.get('displayValue').setValue(this.getDisplayValue(this.selectedItems));\r\n }\r\n }\r\n })\r\n }\r\n}\r\n","
\r\n \r\n
\r\n","import { Component, OnInit, Input } from '@angular/core';\r\nimport { Element } from '../../../../interfaces/form/element';\r\nimport { Item } from '../../../../interfaces/form/item';\r\nimport { ElementValidationService } from '../../../../services/form/element-validation.service';\r\nimport { StringUtilsService } from '../../../../services/string-utils.service';\r\nimport { SelectionChangedEvent } from 'devextreme/ui/data_grid';\r\nimport { ValueChangedEvent } from 'devextreme/ui/drop_down_box';\r\nimport { ItemService } from '../../../../services/item.service';\r\nimport { UntypedFormGroup } from '@angular/forms';\r\nimport { FormElementOperationsService } from '../../../../services/form/form-element-operations.service';\r\nimport { ElementFunctionChangeInformation } from '../../../../interfaces/form/elements/element-function-change-information';\r\nimport { ElementChangeInformation } from '../../../../interfaces/form/elements/element-change-information';\r\nimport { InputInformation } from '../../../../interfaces/form/elements/input-information';\r\n\r\n@Component({\r\n selector: 'app-lookup-edit-datagrid',\r\n templateUrl: './lookup-edit-datagrid.component.html',\r\n styleUrls: ['./lookup-edit-datagrid.component.less']\r\n})\r\n\r\n /**\r\n * Component belonging to the drop down box form elements that use a DxDataGrid for listing.\r\n */\r\nexport class LookupEditDatagridComponent implements OnInit {\r\n\r\n @Input() element: Element;\r\n @Input() inputFormGroup: UntypedFormGroup;\r\n @Input() moduleIndex: number;\r\n @Input() labelPosition: string;\r\n @Input() checkBoxes: boolean;\r\n\r\n public sortedItems: Item[] = [];\r\n private _selectedItem: string[];\r\n\r\n public renderingInformation: InputInformation;\r\n\r\n public isDropDownBoxOpened = false;\r\n\r\n constructor(private validationService: ElementValidationService, private stringUtils: StringUtilsService,\r\n private itemService: ItemService, private elementOperations: FormElementOperationsService) { }\r\n\r\n ngOnInit(): void {\r\n const elementItems: Item[] = this.element.Items as Item[];\r\n if (elementItems.length) {\r\n this.sortedItems = this.itemService.sortItemsBySortAttribute(elementItems, this.element.ElementItemsSortMode);\r\n // If there is an initial value, take it from the form control value and set it in the item values array\r\n const elementValue = this.inputFormGroup.get(\"value\")?.value;\r\n if (elementValue) {\r\n this._selectedItem = elementValue as string[];\r\n this.inputFormGroup.get(\"value\").setValue(this._selectedItem);\r\n this.inputFormGroup.get('displayValue').setValue(this.getDisplayValue());\r\n }\r\n }\r\n this.renderingInformation = this.elementOperations.initializeValidation(this.element, this.inputFormGroup,\r\n this.selectedItem);\r\n this.subscribeToElementChanges();\r\n }\r\n \r\n /**\r\n * Event listener when the user performs a selection in the datagrid. The selecion is assigned and the list of options is hidden.\r\n * @param e\r\n */\r\n changeLookupEditValue(e: SelectionChangedEvent) {\r\n this.isDropDownBoxOpened = false;\r\n \r\n this._selectedItem = e.currentSelectedRowKeys;\r\n \r\n \r\n }\r\n\r\n /**\r\n * Event listener after a value is selected and the value of the drop down box changes consequently. The value submit\r\n * and validation rules application are performed here.\r\n * @param e\r\n */\r\n submitLookupEditValue(e: ValueChangedEvent) {\r\n this.renderingInformation.validationInformation = this.elementOperations.processValueChangeValidation(\r\n this.element, this.inputFormGroup, this.moduleIndex, this._selectedItem, this.getDisplayValue());\r\n }\r\n\r\n /**\r\n * Getter method of the selection.\r\n */\r\n get selectedItem(): string[] {\r\n return this._selectedItem;\r\n }\r\n\r\n /**\r\n * Setter method of the selection.\r\n */\r\n set selectedItem(value: string[]) {\r\n this._selectedItem = value;\r\n }\r\n\r\n\r\n /**\r\n * Gets the display value form control of this input element's form group.\r\n * @param valuesArray\r\n */\r\n private getDisplayValue() {\r\n let displayValue: string = null;\r\n if (this.selectedItem) {\r\n const userSelectedItems: Item[] = [];\r\n this.selectedItem.forEach(((item) => {\r\n const foundSelectedItem: Item = this.sortedItems.find((elementItem) => elementItem.Value === item);\r\n userSelectedItems.push(foundSelectedItem);\r\n }));\r\n if (this.checkBoxes) {\r\n displayValue = this.stringUtils.convertItemsArrayToItemsDisplayName(userSelectedItems);\r\n } else if (userSelectedItems.length) {\r\n displayValue = userSelectedItems[0].DisplayName;\r\n }\r\n } else {\r\n displayValue = \"\";\r\n }\r\n return displayValue;\r\n }\r\n\r\n /**\r\n * Each time that the status in this form element is changed by another element with either\r\n * validations of logic functions, the change is produced in the element form group of the reactive\r\n * form structure, then broadcasted and finally listened here, where the info is updated.\r\n */\r\n private subscribeToElementChanges() {\r\n this.validationService.formElementChanged.subscribe((data: ElementFunctionChangeInformation) => {\r\n if (data.elementId === this.element.ElementID) {\r\n const elementChangeInfo = {} as ElementChangeInformation;\r\n elementChangeInfo.elementFunctionChangeInformation = data;\r\n elementChangeInfo.element = this.element;\r\n elementChangeInfo.moduleIndex = this.moduleIndex;\r\n this.renderingInformation = this.elementOperations.processElementChangeValidation(\r\n elementChangeInfo, this.inputFormGroup, this._selectedItem);\r\n if (this.renderingInformation.updatedAfterOperation) {\r\n this._selectedItem = Array.isArray(this.renderingInformation.updatedValueAfterOperation) ?\r\n this.renderingInformation.updatedValueAfterOperation : [this.renderingInformation.updatedValueAfterOperation];\r\n this.inputFormGroup.get('value').setValue(this._selectedItem);\r\n this.inputFormGroup.get('displayValue').setValue(this.getDisplayValue());\r\n }\r\n }\r\n })\r\n }\r\n}\r\n","
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n","
\r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n","import { Component, OnInit, Input } from '@angular/core';\r\nimport { Element } from '../../../../interfaces/form/element';\r\nimport { Item } from '../../../../interfaces/form/item';\r\nimport { ElementValidationService } from '../../../../services/form/element-validation.service';\r\nimport { StringUtilsService } from '../../../../services/string-utils.service';\r\nimport { ItemService } from '../../../../services/item.service';\r\nimport { UntypedFormGroup } from '@angular/forms';\r\nimport { FormElementOperationsService } from '../../../../services/form/form-element-operations.service';\r\nimport { ElementFunctionChangeInformation } from '../../../../interfaces/form/elements/element-function-change-information';\r\nimport { ElementChangeInformation } from '../../../../interfaces/form/elements/element-change-information';\r\nimport { InputInformation } from '../../../../interfaces/form/elements/input-information';\r\n\r\n@Component({\r\n selector: 'app-list',\r\n templateUrl: './list.component.html',\r\n styleUrls: ['./list.component.less']\r\n})\r\nexport class ListComponent implements OnInit {\r\n\r\n\r\n @Input() element: Element;\r\n @Input() inputFormGroup: UntypedFormGroup;\r\n @Input() moduleIndex: number;\r\n @Input() labelPosition: string;\r\n @Input() search: boolean;\r\n @Input() displaySelectAll: boolean;\r\n\r\n constructor(private validationService: ElementValidationService, private stringUtils: StringUtilsService, private itemService: ItemService, private elementOperations: FormElementOperationsService) { }\r\n\r\n public sortedItems: Item[] = [];\r\n public selectedItems: Item[] = [];\r\n\r\n public renderingInformation: InputInformation;\r\n\r\n public selectionMode: string;\r\n\r\n /**\r\n * Init method where the list values are set.\r\n */\r\n ngOnInit(): void {\r\n const elementItems: Item[] = this.element.Items as Item[];\r\n if (elementItems.length) {\r\n this.sortedItems = this.itemService.sortItemsBySortAttribute(elementItems, this.element.ElementItemsSortMode);\r\n // If there is an initial value, take it from the form control value and set it in the items array\r\n this.setInputFromValue();\r\n this.inputFormGroup.get('displayValue').setValue(this.stringUtils.convertItemsArrayToItemsDisplayName(this.selectedItems));\r\n }\r\n if (this.displaySelectAll) {\r\n this.selectionMode = \"all\";\r\n } else {\r\n this.selectionMode = \"multiple\";\r\n }\r\n this.renderingInformation = this.elementOperations.initializeValidation(this.element, this.inputFormGroup,\r\n this.selectedItems.map((item: Item) => { return item.Value }));\r\n this.subscribeToElementChanges();\r\n }\r\n\r\n\r\n /**\r\n * Updates the input value according to the form of the element form control fromt he reative form structure.\r\n */\r\n private setInputFromValue() {\r\n const elementValue = this.inputFormGroup.get(\"value\")?.value;\r\n if (elementValue) {\r\n const selectedValues = elementValue as string[];\r\n selectedValues.forEach((selectedValue: string) => {\r\n this.selectedItems.push(this.sortedItems.find((sortedItem) => sortedItem.Value === selectedValue));\r\n })\r\n }\r\n }\r\n\r\n /**\r\n * Event listener when the user performs a selection.\r\n * @param e\r\n */\r\n changeListSelection(e: any) {\r\n const selectedValues = this.selectedItems.map((item: Item) => { return item.Value });\r\n const selectedDisplayNames = this.stringUtils.convertItemsArrayToItemsDisplayName(this.selectedItems);\r\n this.renderingInformation.validationInformation = this.elementOperations.processValueChangeValidation(\r\n this.element, this.inputFormGroup, this.moduleIndex, selectedValues, selectedDisplayNames);\r\n }\r\n\r\n /**\r\n * Each time that the status in this form element is changed by another element with either\r\n * validations of logic functions, the change is produced in the element form group of the reactive\r\n * form structure, then broadcasted and finally listened here, where the info is updated.\r\n */\r\n private subscribeToElementChanges() {\r\n this.validationService.formElementChanged.subscribe((data: ElementFunctionChangeInformation) => {\r\n if (data.elementId === this.element.ElementID) {\r\n const elementChangeInfo = {} as ElementChangeInformation;\r\n elementChangeInfo.elementFunctionChangeInformation = data;\r\n elementChangeInfo.element = this.element;\r\n elementChangeInfo.moduleIndex = this.moduleIndex;\r\n this.renderingInformation = this.elementOperations.processElementChangeValidation(\r\n elementChangeInfo, this.inputFormGroup,\r\n this.selectedItems.map((item: Item) => { return item.Value }));\r\n if (this.renderingInformation.updatedAfterOperation) {\r\n const newValueArray = Array.isArray(this.renderingInformation.updatedValueAfterOperation) ?\r\n this.renderingInformation.updatedValueAfterOperation : [this.renderingInformation.updatedValueAfterOperation];\r\n this.inputFormGroup.get('value').setValue(newValueArray);\r\n this.setInputFromValue();\r\n this.inputFormGroup.get('displayValue').setValue(this.stringUtils.convertItemsArrayToItemsDisplayName(this.selectedItems));\r\n }\r\n }\r\n })\r\n }\r\n}\r\n","import { Component, OnInit, Input } from '@angular/core';\r\nimport { Element } from '../../../../interfaces/form/element';\r\nimport { ElementValidationService } from '../../../../services/form/element-validation.service';\r\nimport { ValueChangedEvent } from 'devextreme/ui/text_area';\r\nimport { UntypedFormGroup } from '@angular/forms';\r\nimport { FormElementOperationsService } from '../../../../services/form/form-element-operations.service';\r\nimport { ElementChangeInformation } from '../../../../interfaces/form/elements/element-change-information';\r\nimport { ElementFunctionChangeInformation } from '../../../../interfaces/form/elements/element-function-change-information';\r\nimport { InputInformation } from '../../../../interfaces/form/elements/input-information';\r\n\r\n@Component({\r\n selector: 'app-text-wrap-edit',\r\n templateUrl: './text-wrap-edit.component.html',\r\n styleUrls: ['./text-wrap-edit.component.less']\r\n})\r\n/**\r\n* This component implements the logic related to the text wrap edit fields.\r\n*/\r\nexport class TextWrapEditComponent implements OnInit {\r\n\r\n @Input() element: Element;\r\n @Input() inputFormGroup: UntypedFormGroup;\r\n @Input() moduleIndex: number;\r\n @Input() labelPosition: string;\r\n\r\n inputValue: string;\r\n\r\n public renderingInformation: InputInformation;\r\n\r\n constructor(private validationService: ElementValidationService, private elementOperations: FormElementOperationsService) { }\r\n\r\n ngOnInit(): void {\r\n this.inputValue = typeof this.inputFormGroup.get(\"value\")?.value === 'string' ? this.inputFormGroup.get(\"value\")?.value : \"\";\r\n this.inputFormGroup.get('displayValue').setValue(this.inputValue);\r\n this.renderingInformation = this.elementOperations.initializeValidation(this.element, this.inputFormGroup,\r\n this.inputValue);\r\n this.subscribeToElementChanges();\r\n }\r\n\r\n /**\r\n * Emits as an output the new value of the text wrap edit field.\r\n * @param e\r\n */\r\n valueChanged(e: ValueChangedEvent) {\r\n this.renderingInformation.validationInformation = this.elementOperations.processValueChangeValidation(\r\n this.element, this.inputFormGroup, this.moduleIndex, e.value, e.value);\r\n }\r\n\r\n /**\r\n * Each time that the status in this form element is changed by another element with either\r\n * validations of logic functions, the change is produced in the element form group of the reactive\r\n * form structure, then broadcasted and finally listened here, where the info is updated.\r\n */\r\n private subscribeToElementChanges() {\r\n this.validationService.formElementChanged.subscribe((data: ElementFunctionChangeInformation) => {\r\n if (data.elementId === this.element.ElementID) {\r\n const elementChangeInfo = {} as ElementChangeInformation;\r\n elementChangeInfo.elementFunctionChangeInformation = data;\r\n elementChangeInfo.element = this.element;\r\n elementChangeInfo.moduleIndex = this.moduleIndex;\r\n this.renderingInformation = this.elementOperations.processElementChangeValidation(\r\n elementChangeInfo, this.inputFormGroup, this.inputValue);\r\n if (this.renderingInformation.updatedAfterOperation) {\r\n this.inputValue = this.renderingInformation.updatedValueAfterOperation as string;\r\n this.inputFormGroup.get('displayValue').setValue(this.inputValue);\r\n }\r\n }\r\n })\r\n }\r\n}\r\n","
\r\n \r\n
\r\n","
0\">\r\n
    \r\n
  • \r\n {{validationMessage.message}}\r\n
  • \r\n
\r\n
\r\n","import { Component, Input } from '@angular/core';\r\n\r\n@Component({\r\n selector: 'app-validation-summary',\r\n templateUrl: './validation-summary.component.html',\r\n styleUrls: ['./validation-summary.component.less']\r\n})\r\n/**\r\n * This class as a controller for the validation summary component. \r\n */\r\nexport class ValidationSummaryComponent {\r\n\r\n @Input() validationMessages: { message: string, elementId: string }[];\r\n @Input() addAnchorNavigation: boolean;\r\n\r\n /**\r\n * For instances of this component where the addAnchorNavigation has been set in the inputs,\r\n * listens to the click event in the list of failed inputs and scrolls to them.\r\n * @param id of the element to scroll to\r\n */\r\n public navigateToId(id: string) {\r\n console.log(\"Scroll to \" + id);\r\n // Scrolling implemented via standard javascript instead of using Angular's\r\n // ViewportScroller due to the latter not working as desired\r\n const scrollTarget = document.getElementById(id);\r\n if (scrollTarget) {\r\n scrollTarget.scrollIntoView({\r\n behavior: 'smooth',\r\n block: 'center',\r\n inline: 'center'\r\n });\r\n // Adding focus to the input element where we just scrolled to\r\n const inputElements = scrollTarget.getElementsByTagName(\"input\");\r\n if (inputElements) {\r\n for (let i = 0; i < inputElements.length; i++) {\r\n if (inputElements[i].classList.contains(\"dx-texteditor-input\")) {\r\n inputElements[i].focus();\r\n }\r\n }\r\n }\r\n }\r\n \r\n }\r\n}\r\n","
\r\n\r\n \r\n\r\n \r\n\r\n\r\n
\r\n \r\n
\r\n
\r\n","import { Component, OnInit, Input } from '@angular/core';\r\nimport { formatMessage } from 'devextreme/localization';\r\nimport { Element } from '../../../../interfaces/form/element';\r\nimport { ElementValidationService } from '../../../../services/form/element-validation.service';\r\nimport { BeforeSendEvent, UploadedEvent, ValueChangedEvent } from 'devextreme/ui/file_uploader';\r\nimport { AuthenticationService } from '../../../../services/Authentication.Service';\r\nimport { UntypedFormGroup } from '@angular/forms';\r\nimport { LabelService } from '../../../../services/form/label.service';\r\n\r\n@Component({\r\n selector: 'app-file-uploader',\r\n templateUrl: './file-uploader.component.html',\r\n styleUrls: ['./file-uploader.component.less']\r\n})\r\n/**\r\n * This file acts as a controler of the file uploaders in the form.\r\n */\r\nexport class FileUploaderComponent implements OnInit {\r\n\r\n private UPLOAD_CHUNK_SIZE = 10000;\r\n\r\n @Input() element: Element;\r\n @Input() inputFormGroup: UntypedFormGroup;\r\n @Input() moduleIndex: number;\r\n @Input() labelPosition: string;\r\n\r\n public displayLabel: boolean;\r\n public labelClass: string;\r\n\r\n public selectFileText: string;\r\n public dropFileText: string;\r\n public acceptTypes: string;\r\n public maxFileSize: number;\r\n public multiple: boolean;\r\n\r\n private belongsToTableId: string;\r\n\r\n public uploadedFiles: File[] = [];\r\n\r\n public errorSummaryMessages: { message: string, elementId: string }[] = [];\r\n\r\n constructor(private validationService: ElementValidationService, private argAuthenticationService: AuthenticationService, private labelService: LabelService) { }\r\n\r\n /**\r\n * Initialization method where the dxFileUploader component is configured.\r\n */\r\n ngOnInit(): void {\r\n this.selectFileText = formatMessage(\"dxFileUploader-selectFile\");\r\n this.dropFileText = formatMessage(\"dxFileUploader-dropFile\");\r\n this.belongsToTableId = this.inputFormGroup.get('belongsToTableId')?.value;\r\n this.acceptTypes = this.element.FileUploadExtensions ?? \"*\";\r\n this.maxFileSize = this.element.FileUploadMaxSize ? this.element.FileUploadMaxSize * 1000000 : 5000000;\r\n this.multiple = this.element.FileUploadMultiSelect;\r\n this.displayLabel = this.labelService.isLabelToBePrinted(this.element);\r\n this.labelClass = this.labelService.getLabelHtmlClass(this.inputFormGroup, this.labelPosition);\r\n // When a table add/edit form is initialized, the validations must be applied for the initial input value\r\n if (this.element.Validations && this.belongsToTableId) {\r\n this.validationService.applyElementValidations(this.element, this.uploadedFiles.map((file) => {\r\n return file.name;\r\n }), this.inputFormGroup.get(\"belongsToTableId\").value);\r\n }\r\n }\r\n\r\n /**\r\n * It handles the onBeforeLoad event from the dxFileUploader component and it is meant to customize\r\n * the POST request before being sent for uploading the selected files.\r\n * @param e\r\n */\r\n customizeUploadRequest(e: BeforeSendEvent) {\r\n // HttpClient isn't natively supported by Devextreme, therefor the interceptors aren't the recommended way\r\n // of adding the credentials for the current upload request and the same logic from the interceptor should\r\n // be applied here\r\n const currentUser = this.argAuthenticationService.CurrentUser;\r\n if (currentUser) {\r\n e.request.withCredentials = true;\r\n e.request.setRequestHeader('Authorization', 'Bearer ' + currentUser.AccessToken);\r\n }\r\n }\r\n\r\n /**\r\n * Function that is executed each time that a file is uploaded. Submits the data\r\n * to the reactive structure form and initializes validations.\r\n * @param e\r\n */\r\n submitUploadedFileInfo(e: UploadedEvent) {\r\n this.uploadedFiles.push(e.file);\r\n this.submitAndValidate();\r\n }\r\n\r\n /**\r\n * This function handles the selection changes (either the user selects a file for uploading or clicks\r\n * in the delete button). If the selected files are less in size than the previously selected, then a file\r\n * was selected for being deleted by the user.\r\n * @param e\r\n */\r\n deleteUploadedFile(e: ValueChangedEvent) {\r\n // If the previous array of selected files is larger than the current, potentially a file was deleted\r\n // by the user from the selection\r\n if (e.previousValue.length > e.value.length) {\r\n e.previousValue.forEach((file) => {\r\n const foundFile: File = e.value.find((uploadedFile) => {\r\n return file.name === uploadedFile.name;\r\n })\r\n // If a file isn't in the previous values, it means that it was deleted by the user\r\n if (!foundFile) {\r\n // Proceed here to delete the file in the corresponding service\r\n // ...\r\n this.uploadedFiles = this.uploadedFiles.filter((uploadedFile) => {\r\n return file.name !== uploadedFile.name\r\n });\r\n this.errorSummaryMessages = [];\r\n this.submitAndValidate();\r\n }\r\n })\r\n } else {\r\n if (e.value.length) {\r\n const newSelectedFiles: File[] = e.value.slice(e.previousValue.length);\r\n this.errorSummaryMessages = [];\r\n let filesUploadedCounter = 0;\r\n newSelectedFiles.forEach((selectedFile) => {\r\n const alreadyUploadedFile: File = this.uploadedFiles.find((uploadedFile) => {\r\n return uploadedFile.name === selectedFile.name;\r\n });\r\n // If a file was already uploaded, don't include it in the list\r\n if (alreadyUploadedFile) {\r\n const cancelButton = document.getElementsByClassName(\"dx-fileuploader-cancel-button\")[e.previousValue.length + filesUploadedCounter];\r\n const cancelUploadClickEvent = new Event('click');\r\n cancelButton.dispatchEvent(cancelUploadClickEvent);\r\n this.errorSummaryMessages.push({ message: alreadyUploadedFile.name + \" würde bereits hochgeladen\", elementId: this.element.ElementID });\r\n } else {\r\n filesUploadedCounter++;\r\n }\r\n })\r\n } \r\n \r\n }\r\n }\r\n\r\n /**\r\n * Sends back the value and display values for updating the reactive form and triggers the validations.\r\n */\r\n private submitAndValidate() {\r\n const fileNames: string[] = this.uploadedFiles.map((file) => {\r\n return file.name;\r\n });\r\n this.inputFormGroup.get('value').setValue(null);\r\n this.inputFormGroup.get('displayValue').setValue(fileNames.join(\"
\"));\r\n if (this.element.Validations) {\r\n this.validationService.applyElementValidations(this.element, fileNames, this.inputFormGroup.get(\"belongsToTableId\").value);\r\n }\r\n }\r\n}\r\n","
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n Unbekanntes UI Element: {{element.UIElement}}\r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n 0\">\r\n \r\n
{{element.ToolTip}}
\r\n
\r\n
\r\n","import { Component, OnInit, Input, AfterViewInit } from '@angular/core';\r\nimport { UntypedFormGroup } from '@angular/forms';\r\nimport { Element } from '../../../interfaces/form/element';\r\nimport { LayoutItem } from '../../../interfaces/form/layout-item';\r\nimport { UIElementType } from '../../../interfaces/form/enums/uielement-type-enum';\r\nimport { ReactiveFormService } from '../../../services/form/reactive-form.service';\r\nimport { ElementValidationService } from '../../../services/form/element-validation.service';\r\n\r\n@Component({\r\n selector: 'app-form-element-generator',\r\n templateUrl: './form-element-generator.component.html',\r\n styleUrls: ['./form-element-generator.component.less'],\r\n})\r\n/**\r\n* This creates, for the as-input-received element form group, the reactive form data structure\r\n* necessary for render an element as a form component. The form data is based in the actual element\r\n* received as an input, and also in certain parameters of the layout item form group where the generated\r\n* element form group will be placed.\r\n*/\r\nexport class FormElementGeneratorComponent implements OnInit, AfterViewInit {\r\n\r\n @Input() element: Element;\r\n @Input() layoutItem: LayoutItem;\r\n @Input() moduleIndex: number;\r\n\r\n public parentRootFormGroup: UntypedFormGroup;\r\n public elementFormGroup: UntypedFormGroup;\r\n\r\n inputValue: unknown;\r\n belongsToTableId: string;\r\n\r\n valueValid: boolean;\r\n validationMessage = {};\r\n\r\n\r\n constructor(public formService: ReactiveFormService, private validationService: ElementValidationService) { }\r\n\r\n\r\n /**\r\n * Initialization method. The label information is created and, shall the element have an initial value, it is set in the form structure.\r\n */\r\n ngOnInit(): void {\r\n this.parentRootFormGroup = this.formService.getReactiveForm();\r\n this.elementFormGroup = this.getElementFormGroup();\r\n this.inputValue = this.elementFormGroup.get('value')?.value;\r\n this.belongsToTableId = this.elementFormGroup.get('belongsToTableId')?.value;\r\n }\r\n\r\n /**\r\n * After the current element (and the children edit field) have been rendered,\r\n * check whether it is the last element rendered. If so, notify the reactive\r\n * form service so it can emit the form loaded event.\r\n */\r\n ngAfterViewInit() {\r\n if (this.element.ElementID === this.formService.lastElementIdAdded) {\r\n this.formService.notifyLastElementLoaded();\r\n }\r\n }\r\n\r\n /**\r\n * Getter method for making the UIElementType available in the template.\r\n */\r\n public get UIElementType() {\r\n return UIElementType;\r\n }\r\n\r\n /**\r\n * Gets the form group corresponding to the current element.\r\n * @returns\r\n */\r\n public getElementFormGroup(): UntypedFormGroup {\r\n return (this.formService.searchElementFormGrouplInReactiveFormByElementId(this.element.ElementID, false) as UntypedFormGroup);\r\n }\r\n}\r\n","import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';\r\nimport { PopupInfo } from '../../interfaces/popup-info';\r\nimport { PopupService } from '../../services/popup.service';\r\n\r\n@Component({\r\n selector: 'app-popup',\r\n templateUrl: './popup.component.html',\r\n styleUrls: ['./popup.component.less']\r\n})\r\nexport class PopupComponent implements OnInit {\r\n\r\n // Send only in case the popup texts are to be obtained from the input.\r\n // If this input has no value, the texts will be obtained from the popup service.\r\n @Input() popupInfoInput: PopupInfo;\r\n @Output() popupClosed = new EventEmitter();\r\n\r\n popupInfo: PopupInfo;\r\n popupIsVisible: boolean;\r\n\r\n constructor(private popupService: PopupService) { }\r\n\r\n /**\r\n * Applies on rendering the popup. If the popup data comes from an input, it will\r\n * take that data for rendering the popup. If not, it will take it from the popup service.\r\n */\r\n ngOnInit(): void {\r\n this.popupIsVisible = true;\r\n if (this.popupInfoInput) {\r\n this.popupInfo = this.popupInfoInput;\r\n } else {\r\n this.popupInfo = this.popupService.popupInfo;\r\n }\r\n }\r\n\r\n /**\r\n * Receives the event of the user clicking in the (x) button for closing the popup.\r\n * Closes the popup and emits the event to the instancing component so it can\r\n * take further action if required.\r\n */\r\n closePopup() {\r\n this.popupIsVisible = false;\r\n this.popupService.popupInfo = null;\r\n this.popupClosed.emit(true);\r\n }\r\n\r\n}\r\n","\r\n
\r\n {{popupInfo?.content}}\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n
\r\n","\r\n \r\n \r\n\r\n\r\n \r\n
\r\n \r\n
\r\n \r\n \r\n \r\n
\r\n

\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n","import { Component, Input, OnInit } from '@angular/core';\r\nimport { Layout } from '../../../interfaces/form/layout';\r\nimport { UntypedFormArray, UntypedFormGroup } from '@angular/forms';\r\nimport { ReactiveFormService } from '../../../services/form/reactive-form.service';\r\nimport { Element } from '../../../interfaces/form/element';\r\nimport { Table } from '../../../interfaces/form/table';\r\nimport { UIElementType } from '../../../interfaces/form/enums/uielement-type-enum';\r\nimport { LayoutItem } from '../../../interfaces/form/layout-item';\r\nimport { LayoutGrid } from '../../../interfaces/form/layout/layout-grid';\r\nimport { LayoutGridColumn } from '../../../interfaces/form/layout/layout-grid-column';\r\n\r\n@Component({\r\n selector: 'app-form-layout-generator',\r\n templateUrl: './form-layout-generator.component.html',\r\n styleUrls: ['./form-layout-generator.component.less']\r\n})\r\nexport class FormLayoutGeneratorComponent implements OnInit {\r\n\r\n @Input() moduleIndex: number;\r\n @Input() layout: Layout;\r\n @Input() elements: Element[];\r\n @Input() tables: Table[];\r\n\r\n public formControlStructure: UntypedFormGroup;\r\n\r\n public layoutGrid: LayoutGrid;\r\n\r\n // The found layout item-element mappings through the layout will be gathered\r\n // here for the view to have fast access to them.\r\n private layoutElementPairs: { elementId: string, layoutItem: LayoutItem }[] = [];\r\n\r\n\r\n constructor(private formService: ReactiveFormService) { }\r\n\r\n /**\r\n * Init method where the main form structure is received. With the layout data in hand,\r\n * it creates an object that contains the basic data for the HTML to render the\r\n * layout as specified in the view.\r\n */\r\n ngOnInit() {\r\n if (this.layout) {\r\n this.formControlStructure = this.formService.getReactiveForm();\r\n this.layoutGrid = this.createLayoutGrid(this.layout.LayoutItems, this.layout.Orientation !== \"Vertical\");\r\n this.generateLayoutGrid(this.layout.LayoutItems, this.layout.Orientation !== \"Vertical\", this.layoutGrid);\r\n }\r\n }\r\n\r\n /**\r\n * For any layout or layout item, it determines the maximum number of elements per row,\r\n * excepting the case of horizontal layouts/layout items containing other layout items,\r\n * which are not taken here into account (a new, nested grid will be generated for them)\r\n * @param layoutItems contained as immediate child of the layout or layout items\r\n * @param horizontal stating the parent layout/layout item orientation\r\n * @param layoutGrid with the layout grid that will contain the object tree of the layout\r\n * @returns the number of objects in a layout grid, not counting nested horizontal groups\r\n * of layout items\r\n */\r\n private getLayoutGridColumns(layoutItems: LayoutItem[], horizontal: boolean, layoutGrid: LayoutGrid): number {\r\n let returnColumnsNumber: number = layoutGrid.columnsNumber;\r\n layoutItems.forEach((layoutItem) => {\r\n if (layoutItem.Type === \"Element\") {\r\n if (horizontal) {\r\n returnColumnsNumber = layoutItems.length * layoutGrid.columnsNumber;\r\n }\r\n } else {\r\n let returnedColumnsNumber: number;\r\n if (!horizontal) {\r\n // The number of columns must be obtained just for vertical layouts\r\n // Horizontal layouts are ignored as they require a new, nested layout\r\n returnedColumnsNumber = this.getLayoutGridColumns(layoutItem.LayoutItems, layoutItem.Orientation !== \"Vertical\", layoutGrid);\r\n }\r\n if (returnedColumnsNumber > returnColumnsNumber) {\r\n returnColumnsNumber = returnedColumnsNumber;\r\n }\r\n }\r\n })\r\n return returnColumnsNumber;\r\n }\r\n\r\n /**\r\n * Generates an object tree that is easily to be interpretated by the HTML component.\r\n * @param layoutItems contained as immediate child of the layout or layout items\r\n * @param horizontal stating the parent layout/layout item orientation\r\n * @param parentGrid with the layout grid to analyze\r\n */\r\n private generateLayoutGrid(layoutItems: LayoutItem[], horizontal: boolean, parentGrid: LayoutGrid) {\r\n\r\n layoutItems.forEach((layoutItem) => {\r\n if (layoutItem && layoutItem.Type === \"LayoutGroup\") {\r\n\r\n if (horizontal) {\r\n // In case of a layoutgroup whose parent is horizontal, the column will contain\r\n // a new (nested) grid for its content\r\n const nestedGrid = this.createLayoutGrid(layoutItem.LayoutItems, layoutItem.Orientation !== \"Vertical\");\r\n this.addLayoutGridContainerColumn(layoutItem, layoutItems.length, parentGrid, nestedGrid);\r\n this.addLayoutItemHeader(layoutItem, nestedGrid);\r\n this.generateLayoutGrid(layoutItem.LayoutItems, layoutItem.Orientation !== \"Vertical\", nestedGrid);\r\n } else {\r\n // In case of a layoutgroup whose parent is vertical, no column is added to the grid\r\n this.addLayoutItemHeader(layoutItem, parentGrid);\r\n this.generateLayoutGrid(layoutItem.LayoutItems, layoutItem.Orientation !== \"Vertical\", parentGrid);\r\n }\r\n\r\n\r\n\r\n } else if (layoutItem && layoutItem.Type === \"Element\") {\r\n this.layoutElementPairs.push({ elementId: layoutItem.ElementID, layoutItem: layoutItem })\r\n if (layoutItem.LabelPosition === \"Left\") {\r\n this.addLabelLeftAndInputColumns(layoutItem, horizontal, layoutItems.length, parentGrid);\r\n } else {\r\n this.addLabelTopAndInputColumn(layoutItem, horizontal, layoutItems.length, parentGrid);\r\n }\r\n }\r\n\r\n });\r\n\r\n }\r\n\r\n /**\r\n * For the given module specified by the index, the form array of first-level children layout items si returned.\r\n * @param moduleIndex\r\n * @returns\r\n */\r\n getLayoutItemsArrayFromModuleNumber(moduleIndex: number): UntypedFormArray {\r\n return this.formService.getLayoutItemsArrayFromModuleNumber(moduleIndex);\r\n }\r\n\r\n /**\r\n * For a layout item of type 'Element', gets the corresponding Element in Module.\r\n * @param layoutItemElementId\r\n * @returns\r\n */\r\n getElementByElementId(layoutItemElementId: string): Element {\r\n return this.elements.find(\r\n function (element) {\r\n return (element.ElementID === layoutItemElementId)\r\n });\r\n }\r\n\r\n /**\r\n * Gets the element-containing layout from the given element id.\r\n * @param layoutItemElementId\r\n * @returns\r\n */\r\n getLayoutItemByElementId(layoutItemElementId: string): LayoutItem {\r\n return this.layoutElementPairs.find((li) =>\r\n li.elementId === layoutItemElementId\r\n )?.layoutItem;\r\n }\r\n\r\n /**\r\n * States whether an element is to be rendered or not, based on the loaded form with validations.\r\n * @param layoutItemElementId\r\n * @returns\r\n */\r\n isElementVisible(layoutItemElementId: string): boolean {\r\n let visible = false;\r\n const element = this.getElementByElementId(layoutItemElementId);\r\n if (element) {\r\n visible = this.formService.isElementVisible(element);\r\n }\r\n return visible;\r\n }\r\n\r\n\r\n /**\r\n * Getter method for making the UIElementType available in the template.\r\n */\r\n public get UIElementType() {\r\n return UIElementType;\r\n }\r\n\r\n /**\r\n * Creates a Layout Grid object for the layout or horizontal layout item.\r\n * @param layoutItems with the direct children of the layout/layout item\r\n * @param horizontal stating whether the layout/layout item is horizontal\r\n * @returns\r\n */\r\n private createLayoutGrid(layoutItems: LayoutItem[], horizontal: boolean): LayoutGrid {\r\n const newLayoutGrid: LayoutGrid = {\r\n columns: [],\r\n columnsNumber: 1\r\n };\r\n newLayoutGrid.columnsNumber = this.getLayoutGridColumns(layoutItems, horizontal, newLayoutGrid) * 2;\r\n return newLayoutGrid;\r\n\r\n }\r\n\r\n /**\r\n * A column is added in a way that indicates de HTML that it is meant to act as a\r\n * container for another nested grid.\r\n * @param layoutItem\r\n * @param siblingsNumber\r\n * @param parentGrid\r\n */\r\n private addLayoutGridContainerColumn(layoutItem: LayoutItem, siblingsNumber: number, parentGrid: LayoutGrid, nestedGrid: LayoutGrid) {\r\n const layoutGridColumn: LayoutGridColumn = {\r\n layoutTitle: null,\r\n colSpan: parentGrid.columnsNumber / siblingsNumber,\r\n elementId: null,\r\n cssClass: \"horizontal-layout-column\",\r\n layoutGrid: nestedGrid\r\n }\r\n parentGrid.columns.push(layoutGridColumn);\r\n }\r\n\r\n /**\r\n * Adds a layout grid column to the layout grid with the layout item title, if proceeding.\r\n * @param layoutItem with the layout item (from the input data) under evaluation\r\n * @param layoutGrid where the layout header column is to be added\r\n */\r\n private addLayoutItemHeader(layoutItem: LayoutItem, layoutGrid: LayoutGrid) {\r\n if (layoutItem.Header) {\r\n const layoutTitleColumn: LayoutGridColumn = {\r\n layoutTitle: layoutItem.Header,\r\n colSpan: layoutGrid.columnsNumber,\r\n elementId: null,\r\n cssClass: \"header-column\",\r\n layoutGrid: null\r\n };\r\n layoutGrid.columns.push(layoutTitleColumn);\r\n }\r\n }\r\n\r\n /**\r\n * For layout items of type Element where the label is placed in the left of the input,\r\n * one column is created for the label (if the label is to be printed) and another column\r\n * is added for the input.\r\n * @param layoutItem\r\n * @param horizontal\r\n * @param siblingsNumber\r\n * @param parentGrid\r\n */\r\n private addLabelLeftAndInputColumns(layoutItem: LayoutItem, horizontal: boolean, siblingsNumber: number, parentGrid: LayoutGrid) {\r\n let labelLayoutGridColumn = {};\r\n let inputLayoutGridColumn = {};\r\n if (horizontal) {\r\n labelLayoutGridColumn = {\r\n layoutTitle: null,\r\n colSpan: 1,\r\n elementId: layoutItem.ElementID,\r\n cssClass: \"label-column-horizontal\",\r\n layoutGrid: null\r\n };\r\n inputLayoutGridColumn = {\r\n layoutTitle: null,\r\n // If the label isn't to be printed, the input takes its place as well\r\n colSpan: layoutItem.Label ? (parentGrid.columnsNumber / siblingsNumber) - 1 : parentGrid.columnsNumber / siblingsNumber,\r\n elementId: layoutItem.ElementID,\r\n cssClass: \"input-column-horizontal\",\r\n layoutGrid: null\r\n };\r\n } else {\r\n labelLayoutGridColumn = {\r\n layoutTitle: null,\r\n colSpan: 1,\r\n elementId: layoutItem.ElementID,\r\n cssClass: \"label-column-vertical\",\r\n layoutGrid: null\r\n };\r\n inputLayoutGridColumn = {\r\n layoutTitle: null,\r\n // If the label isn't to be printed, the input takes its place as well\r\n colSpan: layoutItem.Label ? parentGrid.columnsNumber - 1 : parentGrid.columnsNumber,\r\n elementId: layoutItem.ElementID,\r\n cssClass: \"input-column-vertical\",\r\n layoutGrid: null\r\n };\r\n }\r\n if (layoutItem.Label) {\r\n // If the layout item's label is not null, the column for the label has to be added\r\n parentGrid.columns.push(labelLayoutGridColumn);\r\n }\r\n parentGrid.columns.push(inputLayoutGridColumn);\r\n }\r\n\r\n\r\n /**\r\n * For layout items of type Element where the label is placed in top of the input,\r\n * one column is created for both the label and the input.\r\n * @param layoutItem\r\n * @param horizontal\r\n * @param siblingsNumber\r\n * @param parentGrid\r\n */\r\n private addLabelTopAndInputColumn(layoutItem: LayoutItem, horizontal: boolean, siblingsNumber: number, parentGrid: LayoutGrid) {\r\n let labelInputLayoutGridColumn = {};\r\n if (horizontal) {\r\n labelInputLayoutGridColumn = {\r\n layoutTitle: null,\r\n colSpan: parentGrid.columnsNumber / siblingsNumber,\r\n elementId: layoutItem.ElementID,\r\n cssClass: \"label-input-column\",\r\n layoutGrid: null\r\n };\r\n } else {\r\n labelInputLayoutGridColumn = {\r\n layoutTitle: null,\r\n colSpan: parentGrid.columnsNumber,\r\n elementId: layoutItem.ElementID,\r\n cssClass: \"label-input-column\",\r\n layoutGrid: null\r\n };\r\n }\r\n parentGrid.columns.push(labelInputLayoutGridColumn);\r\n }\r\n}\r\n","\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n
\r\n
\r\n \r\n \r\n
\r\n \r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n
\r\n\r\n \r\n\r\n","import { Component, OnInit, AfterViewInit, Input, Output, ViewChild, ElementRef, EventEmitter } from '@angular/core';\r\nimport { ReactiveFormService } from '../../../services/form/reactive-form.service';\r\nimport { UntypedFormGroup } from '@angular/forms';\r\nimport { Element } from '../../../interfaces/form/element';\r\nimport { Table } from '../../../interfaces/form/table';\r\nimport { LayoutItem } from '../../../interfaces/form/layout-item';\r\nimport { ExcelService } from '../../../services/excel.service';\r\nimport { DxDataGridComponent } from 'devextreme-angular';\r\nimport { PopupType } from '../../../interfaces/enum/popup-type';\r\nimport { UIElementType } from '../../../interfaces/form/enums/uielement-type-enum';\r\nimport { PopupService } from '../../../services/popup.service';\r\nimport { RowInsertedEvent, RowInsertingEvent, RowRemovingEvent, RowUpdatedEvent, RowUpdatingEvent, ExportingEvent, EditingStartEvent, InitNewRowEvent } from 'devextreme/ui/data_grid';\r\nimport { Layout } from '../../../interfaces/form/layout';\r\nimport { ElementValidationService } from '../../../services/form/element-validation.service';\r\nimport * as uuid from 'uuid';\r\n\r\ntype GatheredTableElementInformation = {\r\n element: Element;\r\n caption: string;\r\n}\r\n\r\n@Component({\r\n selector: 'app-table-generator',\r\n templateUrl: './table-generator.component.html',\r\n styleUrls: ['./table-generator.component.less']\r\n})\r\n\r\n\r\n\r\n/**\r\n* This creates (as currently implemented, but can be changed) a new table in the form,\r\n* based on the module in which the table element was found\r\n*/\r\nexport class TableGeneratorComponent implements OnInit, AfterViewInit {\r\n\r\n\r\n @Input() tablesInModule: Table[];\r\n @Input() tableElement: Element;\r\n @Input() layoutItem: LayoutItem;\r\n @Input() moduleIndex: number;\r\n @Output() tableSubmit = new EventEmitter();\r\n\r\n // For the import button\r\n @ViewChild('fileUpload') fileUploadButton: ElementRef;\r\n // Instance of the dxDataGridComponent\r\n @ViewChild('dxDataGrid') dxDataGrid: DxDataGridComponent;\r\n\r\n public parentRootFormGroup!: UntypedFormGroup;\r\n public tableLayout: Layout;\r\n public tableTitle: string;\r\n\r\n // Table data source\r\n public dataElements: Record[] = [];\r\n\r\n // Stores the index for which a row is being edited/added\r\n private _editTableRowKey = \"\";\r\n\r\n // For the table columns\r\n public gatheredTableElements: GatheredTableElementInformation[] = [];\r\n\r\n // Object for adding the import table button to the DxDataGrid element\r\n public importButtonOptions = {\r\n text: \"Excel-Datei importieren\",\r\n icon: \"import\",\r\n onClick: () => {\r\n // Clicking in the import button of the dxDataGrid should fire the real input #fileUpload uploading the file (hidden by CSS)\r\n const event = new MouseEvent('click', { bubbles: true });\r\n this.fileUploadButton.nativeElement.dispatchEvent(event)\r\n },\r\n };\r\n\r\n public renderImportTableErrorPopup = false;\r\n \r\n // This class is applied to the add/edit row popup wrapper and it indicates if the form was submitted or not;\r\n public popupWrapperClass: string;\r\n\r\n constructor(private excelService: ExcelService, private formService: ReactiveFormService, public popupService: PopupService, public validationService: ElementValidationService) {\r\n \r\n }\r\n\r\n /**\r\n * Init method of the current table. The columns are retrieved and the form controls are added for each column edit field.\r\n */\r\n ngOnInit(): void {\r\n\r\n const table: Table = this.getTableForElement();\r\n if (table && table.Layout) {\r\n this.tableLayout = table.Layout;\r\n const tableFormGroup = this.formService.searchElementFormGrouplInReactiveFormByElementId(this.tableElement.ElementTableID, true);\r\n if (tableFormGroup) {\r\n this.tableTitle = tableFormGroup.get('layoutItemTitle').value;\r\n }\r\n const layoutItems = table.Layout.LayoutItems;\r\n this.getTableElements(table.Elements, layoutItems);\r\n // Add a form array consisting on a form group for each table column edit field that is not submittable\r\n // (only the entered rows will be submitted, not the values of those edit fields)\r\n this.gatheredTableElements.map((tableColumn) => {\r\n this.formService.addFormControlForElement(tableColumn.element, null, this.moduleIndex, true, this.tableElement.ElementTableID, null);\r\n })\r\n }\r\n this.popupWrapperClass = \"row-edit-form-clean\";\r\n }\r\n\r\n\r\n /**\r\n * After the current table has been rendered, check whether it is the last element rendered. If so, notify the reactive\r\n * form service so it can emit the form loaded event.\r\n */\r\n ngAfterViewInit() {\r\n if (this.tableElement.ElementID === this.formService.lastElementIdAdded) {\r\n this.formService.notifyLastElementLoaded();\r\n }\r\n }\r\n\r\n /**\r\n * Executed when the user opens the add row popup form. It indicates that the popup is opened in edit mode (by setting\r\n * to null the row key indicator) and cleans up the form, in case there was previous validation style or values.\r\n * @param e\r\n */\r\n prepareNewRow(e: InitNewRowEvent) {\r\n this._editTableRowKey = null;\r\n this.popupWrapperClass = \"row-edit-form-clean\";\r\n this.formService.clearEditRowValuesFromTable(this.tableElement.ElementTableID, this.moduleIndex);\r\n this.validationService.setValidationSummaryForTableId(this.tableElement.ElementTableID, this.moduleIndex);\r\n }\r\n\r\n /**\r\n * Captures an element addition to the current table and maintains the status of the rows and columns parentFormArrays.\r\n * @param e\r\n */\r\n onRowAdd(e: RowInsertingEvent) {\r\n this.popupWrapperClass = \"row-edit-form-submitted\";\r\n // The new item key is autogenerated by DxDataGrid and placed in e.data.__KEY__\r\n // Adding values to reactive form\r\n const rowEditFailingFields = this.formService.addRowToTable(null, e.data.__KEY__, this.tableElement.ElementTableID, this.moduleIndex);\r\n if (rowEditFailingFields.length) {\r\n e.cancel = true;\r\n this.validationService.setValidationSummaryForTableId(this.tableElement.ElementTableID, this.moduleIndex);\r\n }\r\n }\r\n\r\n /**\r\n * Once the new row is sucessfully added, reflects the edited data in the table layout.\r\n * @param e\r\n */\r\n onRowAdded(e: RowInsertedEvent) {\r\n this.updateRowDisplay(this.dataElements.length - 1);\r\n this.tableSubmit.emit(true); \r\n this.popupWrapperClass = \"row-edit-form-clean\";\r\n }\r\n\r\n /**\r\n * When a row is going to be edited, prepares the form control fields for editing that row with the\r\n * selected rows value.\r\n * @param e\r\n */\r\n prepareEditFields(e: EditingStartEvent) {\r\n this._editTableRowKey = e.key;\r\n this.popupWrapperClass = \"row-edit-form-clean\";\r\n this.formService.prepareEditRowData(this.tableElement.ElementTableID, this.moduleIndex, e.component.getRowIndexByKey(e.key));\r\n this.validationService.clearValidationSummaryForTable();\r\n }\r\n\r\n /**\r\n * Captures an element update in the current table and maintains the status of the parentFormArray.\r\n * @param e\r\n */\r\n onRowUpdate(e: RowUpdatingEvent) {\r\n const editedRowIndex = e.component.getRowIndexByKey(e.key);\r\n const rowEditFailingFields = this.formService.editRowValuesFromTable(editedRowIndex, this.tableElement.ElementTableID, this.moduleIndex);\r\n if (rowEditFailingFields.length) {\r\n e.cancel = true;\r\n this.validationService.setValidationSummaryForTableId(this.tableElement.ElementTableID, this.moduleIndex);\r\n }\r\n this.popupWrapperClass = \"row-edit-form-submitted\";\r\n }\r\n\r\n /**\r\n * Once the row is sucessfully edited, reflects the edited data in the table layout.\r\n * @param e\r\n */\r\n onRowUpdated(e: RowUpdatedEvent) {\r\n this.updateRowDisplay(e.component.getRowIndexByKey(e.key));\r\n this.popupWrapperClass = \"row-edit-form-clean\";\r\n }\r\n\r\n\r\n /**\r\n * After the user decides to save an edited row, it introduces an empty change for forzing the onRowUpdated/ing execution.\r\n * This is done this way because we are using a totally custom for for adding/editing rows. If the edit fields inside that\r\n * custom form are edited, dxDataGrid doesn't realize that there are changes in the fields, so it doesn't trigger those event handlers.\r\n * source: https://supportcenter.devexpress.com/ticket/details/t993714/datagrid-how-to-force-row-update-even-if-there-is-no-changes\r\n * @param e\r\n */\r\n forceUpdateDialog(e: any) {\r\n if (e.changes.length == 0 && this._editTableRowKey) {\r\n e.changes.push({\r\n type: \"update\",\r\n key: this._editTableRowKey,\r\n data: {}\r\n });\r\n }\r\n }\r\n\r\n\r\n /**\r\n * Captures an element removal to the current table and maintains the status of the parentFormArray.\r\n * @param e\r\n */\r\n onRowRemove(e: RowRemovingEvent) {\r\n //getRowIndexByKey() doesn't seem to be working so the following line is used for getting the deleted row index\r\n const deletedRowIndex = e.component.getDataSource().items().findIndex(item => item.__KEY__ === e.data.__KEY__);\r\n this.formService.deleteRowFromTable(deletedRowIndex, this.tableElement.ElementTableID);\r\n }\r\n\r\n /**\r\n * If an instantiated input custom component is sending a new value, this function must be called from\r\n * an event handler so it sets the value of a cell.\r\n * @param receivedValue\r\n * @param cellInfo\r\n */\r\n saveInputValueInCell(receivedValue: any, cellInfo: any) {\r\n cellInfo.setValue(receivedValue);\r\n }\r\n\r\n /**\r\n * States whether a column belonging to an add/edit row element must be rendered in the table. For example,\r\n * separators and labels cannot have a value, therefore it doesn't make sense to render it as table's column. \r\n * @param element\r\n * @returns\r\n */\r\n columnIsVisibleInTable(element: Element): boolean {\r\n if (element.UIElement !== UIElementType.Separator && element.UIElement !== UIElementType.Label\r\n && element.UIElement !== UIElementType.LabelUnderlineRightAlignment) {\r\n return true;\r\n } else {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Receives the exporting event of the dxDataGrid, customizes the exported file and saves it.\r\n * @param e\r\n */\r\n exportTable(e: ExportingEvent) {\r\n const fileName = (this.tableTitle ? this.tableTitle : \"Export\") + \".xlsx\"\r\n this.excelService.exportTableFromDataGrid(e, fileName, this.gatheredTableElements.map(function (gatheredElement) { return gatheredElement.element }));\r\n }\r\n\r\n /**\r\n * Receives the event of the user clicking in the import button of the dxDataGrid.\r\n * @param event with the event \r\n */\r\n importTable(event: Event) {\r\n const inputElement = event.target as HTMLInputElement;\r\n const fileList: FileList | null = inputElement.files;\r\n this.excelService.importExcelToDataGrid(fileList.item(0), this.dxDataGrid, this.gatheredTableElements.map((gatheredElement) => {\r\n return gatheredElement.element\r\n })).subscribe({\r\n next: importInfo => {\r\n this.fileUploadButton.nativeElement.value = \"\";\r\n if (importInfo) {\r\n const validRows: number[] = [];\r\n if (importInfo.length) {\r\n let failingColumns: string = null;\r\n const currentTableRows = this.dataElements.length;\r\n importInfo.forEach((value, rowIndex) => {\r\n if (!failingColumns) {\r\n // The imported item key is NOT autogenerated by DxDataGrid so a random UUID is generated.\r\n // This code needs to be later on double-check as currently I am not sure of the procedure\r\n const rowId = uuid.v4();\r\n const rowEditFailingFields = this.formService.addRowToTable(value, rowId, this.tableElement.ElementTableID, this.moduleIndex);\r\n if (!rowEditFailingFields.length) {\r\n validRows.push(currentTableRows + rowIndex);\r\n value.displayValues[\"__KEY__\"] = rowId;\r\n this.dataElements.push(value.displayValues);\r\n this.formService.clearEditRowValuesFromTable(this.tableElement.ElementTableID, this.moduleIndex);\r\n } else {\r\n failingColumns = rowEditFailingFields.map((field) => { return field.get(\"displayName\").value }).join(\", \");\r\n // Row Index (starting from 0 in this loop) + 1 (excel starts with 1) + 1 (header row in excel)\r\n this.popupService.popupInfo = {\r\n title: \"Excel-Import\",\r\n content: `Daten konnten nicht importiert werden. Zeile ${rowIndex + 2} aus der Excel -Datei beeinhaltet ungultige Daten (${failingColumns}).`,\r\n type: PopupType.ERROR\r\n }\r\n this.renderImportTableErrorPopup = true;\r\n \r\n\r\n }\r\n }\r\n })\r\n // Case an error was found, the rows added before have to be deleted from both the reactive\r\n // form structure and the data source of the table.\r\n if (failingColumns && failingColumns.length) {\r\n for (let i = currentTableRows + validRows.length - 1; i >= currentTableRows; i--) {\r\n this.formService.deleteRowFromTable(i, this.tableElement.ElementTableID);\r\n this.dataElements.splice(i, 1);\r\n }\r\n }\r\n }\r\n }\r\n },\r\n error: () => {\r\n this.renderImportTableErrorPopup = true;\r\n }\r\n })\r\n }\r\n\r\n /**\r\n * When a popup is closed, it resets the information to empty.\r\n * @param isPopupClosed\r\n */\r\n clearPopupInfo(isPopupClosed: boolean) {\r\n if (isPopupClosed) {\r\n this.renderImportTableErrorPopup = false;\r\n }\r\n }\r\n\r\n /**\r\n * Extract the pure attribute of type Element from the gathered elements needed for rendering the table.\r\n * @returns\r\n */\r\n extractElementsFromGatheredElements(): Element[] {\r\n return this.gatheredTableElements.map(el => el.element);\r\n }\r\n\r\n /**\r\n * Gets the table belonging to the module's table element.\r\n * @returns\r\n */\r\n private getTableForElement(): Table {\r\n\r\n if (this.tablesInModule) {\r\n return this.tablesInModule.find(table => { return table.ElementTableID === this.tableElement.ElementTableID });\r\n } else {\r\n return null;\r\n }\r\n }\r\n\r\n\r\n /**\r\n * Gathers the elements in the table array belonging to the layout items and pushes them in an array.\r\n * @param tableElements direct Element children of the Table object\r\n * @param layoutItems layout items inside the Table object\r\n * @returns\r\n */\r\n private getTableElements(tableElements: Element[], layoutItems: LayoutItem[]) {\r\n \r\n for (let i = 0; i < layoutItems.length; i++) {\r\n const currentLayoutItem = layoutItems[i];\r\n\r\n if (currentLayoutItem.Type === 'Element') {\r\n const foundTableElement = tableElements.find(element => { return element.ElementID == currentLayoutItem.ElementID });\r\n if (foundTableElement) {\r\n const gatheredTableElement = {} as GatheredTableElementInformation;\r\n gatheredTableElement.element = foundTableElement;\r\n gatheredTableElement.caption = foundTableElement.DisplayName + (foundTableElement.IsRequired ? '*' : '');\r\n this.gatheredTableElements.push(gatheredTableElement); \r\n }\r\n } else if (currentLayoutItem.Type == 'LayoutGroup') {\r\n this.getTableElements(tableElements, currentLayoutItem.LayoutItems);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Programmatically reflects the changes added in the add/edit form to the table rendered.\r\n * @param rowIndex\r\n */\r\n private updateRowDisplay(rowIndex: number) {\r\n const rowValuesRecord: Record =\r\n this.formService.getRowDisplayValues(this.tableElement.ElementTableID, this.moduleIndex);\r\n this.dataElements[rowIndex] = {};\r\n Object.entries(rowValuesRecord).forEach(([key, val]) => {\r\n this.dataElements[rowIndex][key] = val;\r\n })\r\n }\r\n}\r\n","import { Component, OnInit } from '@angular/core';\r\nimport { BrandingService } from '../../services/branding.service';\r\nimport { KeycloakService } from 'keycloak-angular';\r\n\r\n@Component({\r\n selector: 'app-home-page',\r\n templateUrl: './home-page.component.html',\r\n styleUrls: ['./home-page.component.less']\r\n})\r\nexport class HomePageComponent implements OnInit {\r\n // JQuery\r\n private $Element: JQuery;\r\n\r\n constructor(private brandingService: BrandingService, private keyCloakService: KeycloakService) { }\r\n\r\n public ngOnInit() {\r\n this.brandingService.setBranding(null);\r\n this.brandingService.setFooterLinks(null);\r\n this.brandingService.setTitle('R23 Webforms');\r\n }\r\n\r\n public async loginKeyCloak() {\r\n await this.keyCloakService.login({\r\n redirectUri: 'https://localhost:44457',\r\n });\r\n }\r\n}\r\n","
\r\n
\r\n
\r\n

404

\r\n

\r\n Der von Ihnen gewünschte Service ist nicht mehr verfügbar.
\r\n Bitte wenden Sie sich an Ihren Ansprechpartner.\r\n

\r\n \r\n
\r\n
\r\n
\r\n","export enum WebformTargetType {\r\n Unknown = 0,\r\n Category = 1,\r\n History = 2,\r\n ConfigCategory = 3,\r\n Note = 4,\r\n}","import { Injectable } from '@angular/core';\r\nimport { HttpClient } from \"@angular/common/http\";\r\nimport { HttpErrorResponse } from \"@angular/common/http\";\r\nimport { Observable, throwError } from 'rxjs';\r\nimport { catchError, map } from 'rxjs/operators';\r\nimport { PopupInfo } from '../interfaces/popup-info';\r\nimport { PopupType } from '../interfaces/enum/popup-type';\r\nimport { DataInput } from '../interfaces/form/data-input';\r\nimport { DataOutput } from '../interfaces/form/data-output';\r\nimport { GeneralDataResponse } from './objects/general-data-response';\r\nimport { PopupService } from '../services/popup.service';\r\n\r\n/**\r\n * This service contains all the client methods for consuming the back-end services\r\n * related to the form.\r\n */\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class FormClientService {\r\n\r\n constructor(private httpClient: HttpClient, private popupService: PopupService) { }\r\n\r\n /**\r\n * Gets the input data from backend for the given inputId.\r\n * @param request with the ID of the input to retrieve\r\n * @returns\r\n */\r\n public getDataById(request: R23_Webforms.Model.General.Request): Observable {\r\n return this.httpClient.post(`api/Form/GetDataById`, request, { withCredentials: true }).pipe(\r\n map((response) => {\r\n //Successful request\r\n return response.Data;\r\n }),\r\n catchError(\r\n // Wrong request\r\n this.handleError.bind(this)\r\n )\r\n );\r\n }\r\n\r\n /**\r\n * Saves the given DataOutput object in back-end.\r\n * @param request containing the DataOuput object with the form submitted data\r\n * @returns\r\n */\r\n public saveData(request: R23_Webforms.Model.General.Request): Observable {\r\n \r\n return this.httpClient.post(`api/Form/SaveData`, request, { withCredentials: true }).pipe(\r\n map((response) => {\r\n if (response.Data) {\r\n // Submit successful\r\n return response.Data;\r\n } else {\r\n // Request successful, submit error\r\n const popupInfo: PopupInfo = {\r\n title: \"Error\",\r\n content: \"Es ist ein technisches Problem aufgetreten. Bitte wenden Sie sich an Ihren Ansprechpartner.\",\r\n type: PopupType.ERROR\r\n }\r\n this.popupService.popupInfo = popupInfo;\r\n return false;\r\n }\r\n }),\r\n catchError(\r\n // Request error\r\n this.handleError.bind(this)\r\n )\r\n );\r\n }\r\n\r\n /**\r\n * Method in charge of handling request errors. Keep udating this method to match the requirements.\r\n * @param error\r\n */\r\n private handleError(error: HttpErrorResponse) {\r\n const popupInfo: PopupInfo = { title: null, content: null, type: null };\r\n if (error.status === 0) {\r\n popupInfo.title = \"Error\";\r\n popupInfo.content = \"Es ist ein technisches Problem aufgetreten. Bitte wenden Sie sich an Ihren Ansprechpartner.\";\r\n popupInfo.type = PopupType.ERROR;\r\n } else {\r\n switch (error.status) {\r\n case 401:\r\n case 403:\r\n popupInfo.title = \"Access denied\";\r\n popupInfo.content = \"Es ist ein technisches Problem aufgetreten. Bitte wenden Sie sich an Ihren Ansprechpartner.\";\r\n popupInfo.type = PopupType.ERROR;\r\n break;\r\n default:\r\n popupInfo.title = \"Error\";\r\n popupInfo.content = \"Es ist ein technisches Problem aufgetreten. Bitte wenden Sie sich an Ihren Ansprechpartner.\";\r\n popupInfo.type = PopupType.ERROR;\r\n break;\r\n }\r\n }\r\n this.popupService.popupInfo = popupInfo;\r\n\r\n throw throwError(() => \"Error in the request\");\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\n/**\r\n * This service is aimed to contain all the data (and provider methods of that data) that needs to be shared\r\n * in between different views (pages) and cannot be passed as routper parameters due to the inconvenience of\r\n * giving access to the user via URL parameters.\r\n */\r\nexport class ViewStateDataService {\r\n\r\n // states whether the user successfully submitted a form\r\n private _formSucess: boolean;\r\n\r\n /**\r\n * Getter method form formSuccess.\r\n * @returns\r\n */\r\n public getFormSuccess(): boolean {\r\n return this._formSucess === true;\r\n }\r\n\r\n /**\r\n * Setter method form formSuccess.\r\n * @returns\r\n */\r\n public setFormSuccess(formSuccess: boolean) {\r\n this._formSucess = formSuccess;\r\n }\r\n}\r\n","\r\n \r\n \r\n \r\n\r\n","import { Component, Input, Output, OnInit, EventEmitter } from '@angular/core';\r\nimport { DataInput } from '../../../interfaces/form/data-input';\r\nimport { WebformTargetType } from '../../../interfaces/form/enums/webform-target-type-enum';\r\nimport { Modul } from '../../../interfaces/form/modul';\r\nimport { DataOutput } from '../../../interfaces/form/data-output';\r\nimport { ReactiveFormService } from '../../../services/form/reactive-form.service'\r\nimport { ElementValidationService } from '../../../services/form/element-validation.service';\r\n \r\n@Component({\r\n selector: 'app-form-generator',\r\n templateUrl: './form-generator.component.html',\r\n styleUrls: ['./form-generator.component.less']\r\n})\r\n\r\n/**\r\n * This component renders the form for the given data input. In the class it is contained the\r\n * logic for building the main reactive form structure.\r\n */\r\nexport class FormGeneratorComponent implements OnInit {\r\n\r\n @Input() dataInput: DataInput;\r\n @Input() formSubmitted: EventEmitter;\r\n @Output() formDataReady = new EventEmitter();\r\n\r\n private dataInputId: string;\r\n private dataInputType: WebformTargetType;\r\n public receivedModules: Modul[];\r\n\r\n constructor(private formService: ReactiveFormService, private validationService: ElementValidationService) { }\r\n\r\n /**\r\n * Initialization method, only to be called once the dataInput component input has been initialized.\r\n */\r\n ngOnInit() {\r\n //Once the dataInput is received from the back-end, the form generation begins\r\n if (this.dataInput) {\r\n this.generateForm(this.dataInput);\r\n }\r\n \r\n this.formSubmitted.subscribe(() => this.packElementsOutputData());\r\n }\r\n\r\n /**\r\n * Generates the form for the given data input.\r\n * @param argDataInput\r\n */\r\n private generateForm(argDataInput: DataInput) {\r\n this.receivedModules = argDataInput.Module;\r\n this.dataInputId = argDataInput.Id;\r\n this.dataInputType = argDataInput.Type;\r\n this.formService.initializeAppReactiveForm(argDataInput);\r\n }\r\n\r\n /**\r\n * Given the reactive form data from formControl, it packs the data of the form ready for being sent\r\n * to the back-end in a DataOutput interface.\r\n * @returns\r\n */\r\n private packElementsOutputData() {\r\n let formElementsOutput: DataOutput = {\r\n Elements: [],\r\n Id: this.dataInputId,\r\n Type: this.dataInputType,\r\n };\r\n formElementsOutput = this.formService.packElementsOutputData(formElementsOutput);\r\n this.formDataReady.emit(formElementsOutput);\r\n }\r\n}\r\n","
\r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n\r\n\r\n
\r\n
\r\n\r\n
\r\n \r\n \r\n \r\n
\r\n\r\n \r\n \r\n
\r\n Die mit * gekennzeichneten Felder sind Pflichtfelder.\r\n
\r\n
\r\n
\r\n Unten finden Sie unsere geltende Datenschutzerklärung.\r\n
\r\n\r\n \r\n
\r\n Bitte beachten Sie, dass dieses Formular nach dem Absenden nicht mehr gültig ist.\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n
\r\n\r\n
\r\n","import { Component, ViewChild, EventEmitter, OnInit } from '@angular/core';\r\nimport { UntypedFormGroup } from '@angular/forms';\r\nimport { ActivatedRoute, ParamMap, Router } from '@angular/router';\r\nimport { DataInput } from '../../interfaces/form/data-input';\r\nimport { WebformTargetType } from '../../interfaces/form/enums/webform-target-type-enum';\r\nimport { DataOutput } from '../../interfaces/form/data-output';\r\nimport { ViewStateDataService } from '../../services/view-state-data.service';\r\nimport { ReactiveFormService } from '../../services/form/reactive-form.service';\r\nimport { BrandingService } from '../../services/branding.service';\r\nimport { Branding } from '../../interfaces/branding';\r\nimport { ElementValidationService } from '../../services/form/element-validation.service';\r\nimport { FormClientService } from '../../client/form-client.service';\r\n// eslint-disable-next-line @typescript-eslint/no-var-requires\r\nconst jCaptcha = require('js-captcha');\r\n\r\n@Component({\r\n selector: 'app-form-page',\r\n templateUrl: './form-page.component.html',\r\n styleUrls: ['./form-page.component.less']\r\n})\r\nexport class FormPageComponent implements OnInit {\r\n\r\n @ViewChild('formContainer') formContainer: any;\r\n\r\n formSubmitted = new EventEmitter();\r\n\r\n // Reactive form where all the form components will be added\r\n public formControl: UntypedFormGroup;\r\n\r\n // Public properties\r\n public areRequiredFieldsExist: boolean;\r\n\r\n public isSummaryVisible: boolean;\r\n public pageDescription: string;\r\n\r\n // Data\r\n public inputId: string;\r\n public dataInputResult: DataInput;\r\n private _branding: Branding;\r\n\r\n // Form Captcha\r\n public captcha: any;\r\n public renderCaptcha: boolean;\r\n\r\n // States whether the form has been fully loaded\r\n public formLoaded: boolean;\r\n\r\n //Form submit information\r\n public dataSubmitResult: boolean;\r\n\r\n // Boolean controlling the rendering of the error popups\r\n public renderGetDataPopup = false;\r\n public renderSaveDataPopup = false;\r\n\r\n constructor(private argRoute: ActivatedRoute, private formClientService: FormClientService,\r\n private argRouter: Router, private viewStateDataService: ViewStateDataService, public formService: ReactiveFormService,\r\n public validationService: ElementValidationService, private brandingService: BrandingService) { }\r\n\r\n\r\n public ngOnInit() {\r\n this.formControl = this.formService.createAppReactiveForm();\r\n this.viewStateDataService.setFormSuccess(false);\r\n\r\n // Getting inputID from the url parameters\r\n this.argRoute.paramMap.subscribe((argParams: ParamMap) => {\r\n this.inputId = argParams.get('inputid');\r\n });\r\n\r\n if (this.inputId) {\r\n const getDataRequest: R23_Webforms.Model.General.Request = {\r\n Id: this.inputId\r\n };\r\n this.formClientService.getDataById(getDataRequest).subscribe({\r\n // The data is ready from backend\r\n next: dataInput => {\r\n this.dataInputResult = dataInput;\r\n if (dataInput) {\r\n this.pageDescription = dataInput.PageDescription;\r\n this._branding = dataInput.Branding;\r\n this.brandingService.setBranding(dataInput.Branding);\r\n this.brandingService.setFooterLinks(dataInput.FooterLinks);\r\n this.brandingService.setTitle(dataInput.PageTitel);\r\n this.toggleSummary(dataInput.Type);\r\n }\r\n // When the form is fully loaded, the flag serving as reference for the template is set.\r\n // Also the captcha is added here.\r\n this.formService.lastElementRendered.subscribe((formLoaded) => {\r\n this.formLoaded = formLoaded;\r\n this.validationService.setValidationSummary();\r\n if (this.renderCaptcha && formLoaded) {\r\n this.initCaptcha();\r\n }\r\n })\r\n }, error: () => {\r\n this.renderGetDataPopup = true;\r\n }\r\n \r\n })\r\n\r\n }\r\n\r\n\r\n }\r\n\r\n /**\r\n * States whether the current form has any required field.\r\n * @returns boolean\r\n */\r\n public formHasValidation(): boolean {\r\n return this.formService.hasValidationFields;\r\n }\r\n\r\n /**\r\n * Validates the captcha (if applicable to the current form) and triggers the event informing the\r\n * child elements (at the moment, the form generator component) that the user clicked the submit button\r\n */\r\n public onSubmit() {\r\n console.log('onSubmit', this.captcha);\r\n if (this.captcha) {\r\n //the submit event is handled by the captcha validation method\r\n this.captcha.validate();\r\n } else {\r\n //the submit event is handled directly\r\n this.handleFormSubmit();\r\n }\r\n }\r\n\r\n /**\r\n * Once the child elements (at the moment, form generator component) has received the submit event,\r\n * packed all the data for submit, and triggered the data ready event, this method is called for\r\n * sending the data to the back-end \r\n * @param formData\r\n */\r\n public submitFormData(formData: DataOutput) {\r\n console.log(formData);\r\n const saveDataRequest: R23_Webforms.Model.General.Request = {\r\n Data: formData,\r\n Id: this.inputId\r\n };\r\n this.formClientService.saveData(saveDataRequest).subscribe({\r\n next: submitResult => {\r\n if(submitResult) {\r\n this.formService.notifyFormExit();\r\n this.argRouter.navigate(['/form-success']);\r\n } else {\r\n this.dataSubmitResult = submitResult;\r\n }\r\n },\r\n error: err => {\r\n this.renderSaveDataPopup = true;\r\n }\r\n })\r\n }\r\n\r\n /**\r\n * Handles the popup closed event from the popup component. When closed,\r\n * it also redirects to the root URL.\r\n * @param isPopupClosed\r\n */\r\n clearDataInputPopupInfo(isPopupClosed: boolean) {\r\n if (isPopupClosed) {\r\n this.dataInputResult = null;\r\n this.renderGetDataPopup = false;\r\n this.argRouter.navigate(['/']);\r\n }\r\n }\r\n /**\r\n * Handles the popup closed event from the popup component. When closed,\r\n * it also redirects to the root URL.\r\n * @param isPopupClosed\r\n */\r\n clearDataSubmitPopupInfo(isPopupClosed: boolean) {\r\n if (isPopupClosed) {\r\n this.renderSaveDataPopup = false;\r\n this.dataSubmitResult = null;\r\n }\r\n }\r\n\r\n\r\n /**\r\n * Initialization of the captcha. It must be performed by adding elements to the DOM in runtime due to the pure\r\n * JS nature of the captcha tool and Angular blocking