UNPKG

@ng-formworks/material

Version:

Angular ng-formworks - JSON Schema Form builder using Angular Material UI

1 lines 188 kB
{"version":3,"file":"ng-formworks-material.mjs","sources":["../../../../projects/ng-formworks-material/src/lib/material-design-cssframework.ts","../../../../projects/ng-formworks-material/src/lib/material-design-framework.component.ts","../../../../projects/ng-formworks-material/src/lib/material-design-framework.component.html","../../../../projects/ng-formworks-material/src/lib/widgets/flex-layout-root.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/flex-layout-section.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-add-reference.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-button.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-button-group.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-checkbox.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-checkboxes.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-chip-list.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-datepicker.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-file.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-input.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-number.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-tabs.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-one-of.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-radios.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-select.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-slider.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-stepper.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/material-textarea.component.ts","../../../../projects/ng-formworks-material/src/lib/widgets/public_api.ts","../../../../projects/ng-formworks-material/src/lib/material-design.framework.ts","../../../../projects/ng-formworks-material/src/lib/material-design-framework.module.ts","../../../../projects/ng-formworks-material/src/public_api.ts","../../../../projects/ng-formworks-material/src/ng-formworks-material.ts"],"sourcesContent":["\r\nexport const cssFrameworkCfgMaterialDesign:any={\r\n \"name\": \"material-design\",\r\n \"text\":\"Material Design\",\r\n \"scripts\": [],\r\n \"stylesheets\": [\r\n '//fonts.googleapis.com/icon?family=Material+Icons',\r\n '//fonts.googleapis.com/css?family=Roboto:300,400,500,700',\r\n ],\r\n \"widgetstyles\": {\r\n \"__themes__\": [\r\n {\"name\":\"material_default\",\"text\":\"Default Theme\"},\r\n {\"name\":\"azure-blue\",\"text\":\"Azure & Blue\"},\r\n {\"name\":\"rose-red\",\"text\":\"Rose & Red\"},\r\n {\"name\":\"cyan-orange\",\"text\":\"Cyan & Orange\"},\r\n {\"name\":\"magenta-violet\",\"text\":\"Magenta & Violet\"},\r\n {\"name\":\"indigo-pink\",\"text\":\"Indigo & Pink\"},\r\n {\"name\":\"purple-green\",\"text\":\"Purple & Green\"},\r\n {\"name\":\"deeppurple-amber\",\"text\":\"Deep Purple & Amber\"},\r\n {\"name\":\"pink-bluegrey\",\"text\":\"Pink & Blue-Grey\"},\r\n \r\n ]\r\n }\r\n}\r\n\r\n","import { ChangeDetectorRef, Component, OnChanges, OnDestroy, OnInit, inject, input } from '@angular/core';\r\nimport { FrameworkLibraryService, JsonSchemaFormService, isDefined } from '@ng-formworks/core';\r\nimport { CssframeworkService } from '@ng-formworks/cssframework';\r\nimport cloneDeep from 'lodash/cloneDeep';\r\nimport { Subscription } from 'rxjs';\r\nimport { cssFrameworkCfgMaterialDesign } from './material-design-cssframework';\r\n\r\n@Component({\r\n // tslint:disable-next-line:component-selector\r\n selector: 'material-design-framework',\r\n templateUrl: './material-design-framework.component.html',\r\n styleUrls: ['./material-design-framework.component.scss'],\r\n standalone: false\r\n})\r\nexport class MaterialDesignFrameworkComponent implements OnInit, OnChanges, OnDestroy {\r\n private cdr = inject(ChangeDetectorRef);\r\n private jsf = inject(JsonSchemaFormService);\r\n jsfFLService = inject(FrameworkLibraryService);\r\n cssFWService = inject(CssframeworkService);\r\n\r\n frameworkInitialized = false;\r\n inputType: string;\r\n options: any; // Options used in this framework\r\n widgetLayoutNode: any; // layoutNode passed to child widget\r\n widgetOptions: any; // Options passed to child widget\r\n formControl: any = null;\r\n parentArray: any = null;\r\n isOrderable = false;\r\n dynamicTitle: string = null;\r\n readonly layoutNode = input<any>(undefined);\r\n readonly layoutIndex = input<number[]>(undefined);\r\n readonly dataIndex = input<number[]>(undefined);\r\n\r\n theme: string = \"material-default-theme\";\r\n frameworkThemeSubs: Subscription;\r\n constructor() {\r\n\r\n\r\n\r\n }\r\n ngOnDestroy(): void {\r\n this.frameworkThemeSubs?.unsubscribe();\r\n this.frameworkThemeSubs = null;\r\n }\r\n\r\n get showRemoveButton(): boolean {\r\n const layoutNode = this.layoutNode();\r\n if (!layoutNode || !this.widgetOptions.removable ||\r\n this.widgetOptions.readonly || layoutNode.type === '$ref'\r\n ) {\r\n return false;\r\n }\r\n if (layoutNode.recursiveReference) {\r\n return true;\r\n }\r\n if (!layoutNode.arrayItem || !this.parentArray) {\r\n return false;\r\n }\r\n // If array length <= minItems, don't allow removing any items\r\n return this.parentArray.items.length - 1 <= this.parentArray.options.minItems ? false :\r\n // For removable list items, allow removing any item\r\n layoutNode.arrayItemType === 'list' ? true :\r\n // For removable tuple items, only allow removing last item in list\r\n this.layoutIndex()[this.layoutIndex().length - 1] === this.parentArray.items.length - 2;\r\n }\r\n\r\n ngOnInit() {\r\n const cssFWService = this.cssFWService;\r\n\r\n let activeFramework: any = this.jsfFLService.activeFramework;\r\n let fwcfg = activeFramework.config || {};\r\n let defaultTheme = cssFrameworkCfgMaterialDesign.widgetstyles?.__themes__[0];\r\n let defaultThemeName = cssFWService.activeRequestedTheme || defaultTheme.name;\r\n this.theme = this.options?.theme || defaultThemeName;\r\n this.frameworkThemeSubs = cssFWService.frameworkTheme$.subscribe(\r\n newTheme => {\r\n this.theme = newTheme;\r\n this.cdr.detectChanges();\r\n }\r\n )\r\n this.initializeFramework();\r\n }\r\n\r\n ngOnChanges(changes) {\r\n if (!this.frameworkInitialized) {\r\n this.initializeFramework();\r\n }\r\n if (this.dynamicTitle) {\r\n //this.updateTitle();\r\n }\r\n }\r\n\r\n initializeFramework() {\r\n const layoutNode = this.layoutNode();\r\n if (layoutNode) {\r\n this.options = cloneDeep(layoutNode.options || {});\r\n this.widgetLayoutNode = {\r\n ...layoutNode,\r\n options: cloneDeep(layoutNode.options || {})\r\n };\r\n this.widgetOptions = this.widgetLayoutNode.options;\r\n this.formControl = this.jsf.getFormControl(this);\r\n\r\n if (\r\n isDefined(this.widgetOptions.minimum) &&\r\n isDefined(this.widgetOptions.maximum) &&\r\n this.widgetOptions.multipleOf >= 1\r\n ) {\r\n layoutNode.type = 'range';\r\n }\r\n\r\n if (\r\n !['$ref', 'advancedfieldset', 'authfieldset', 'button', 'card',\r\n 'checkbox', 'expansion-panel', 'help', 'message', 'msg', 'section',\r\n 'submit', 'tabarray', 'tabs'].includes(layoutNode.type) &&\r\n /{{.+?}}/.test(this.widgetOptions.title || '')\r\n ) {\r\n this.dynamicTitle = this.options?.title;//this.widgetOptions.title;\r\n //this.updateTitle();\r\n }\r\n\r\n if (layoutNode.arrayItem && layoutNode.type !== '$ref') {\r\n this.parentArray = this.jsf.getParentNode(this);\r\n if (this.parentArray) {\r\n this.isOrderable =\r\n this.parentArray.type.slice(0, 3) !== 'tab' &&\r\n layoutNode.arrayItemType === 'list' &&\r\n !this.widgetOptions.readonly &&\r\n this.parentArray.options.orderable;\r\n }\r\n }\r\n\r\n this.frameworkInitialized = true;\r\n } else {\r\n this.options = {};\r\n }\r\n }\r\n\r\n updateTitle() {\r\n this.widgetLayoutNode.options.title=\r\n //let newTitle = \r\n this.jsf.parseText(\r\n this.dynamicTitle,\r\n this.jsf.getFormControlValue(this),\r\n this.jsf.getFormControlGroup(this).value,\r\n this.dataIndex()[this.dataIndex().length - 1]\r\n );\r\n //this.widgetLayoutNode.options ={ ...this.widgetLayoutNode.options, title: newTitle }\r\n //attempt to trigger change detection by changing widgetLayoutNode ref\r\n // const newLayoutNode = { ...this.widgetLayoutNode, options: { ...this.widgetLayoutNode.options, title: newTitle } };\r\n //this.widgetLayoutNode = newLayoutNode;\r\n }\r\n\r\n removeItem() {\r\n this.jsf.removeItem(this);\r\n }\r\n}\r\n","<div [class]=\"theme\">\n <div class=\"mat-app-background\">\n\n <!-- commented out to use sortable js\n <div [class.array-item]=\"widgetLayoutNode?.arrayItem && widgetLayoutNode?.type !== '$ref'\"\n [orderable]=\"isOrderable\"\n [dataIndex]=\"dataIndex()\"\n [layoutIndex]=\"layoutIndex()\"\n [layoutNode]=\"widgetLayoutNode\">\n -->\n\n <div [class.array-item]=\"widgetLayoutNode?.arrayItem && widgetLayoutNode?.type !== '$ref'\" [orderable]=\"false\" [dataIndex]=\"dataIndex()\" [layoutIndex]=\"layoutIndex()\" [layoutNode]=\"widgetLayoutNode\">\n @if (showRemoveButton) {\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"18\" width=\"18\" viewBox=\"0 0 24 24\" class=\"close-button\" (click)=\"removeItem()\">\n <path\n d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z\"/>\n </svg>\n }\n <select-widget-widget [dataIndex]=\"dataIndex()\" [layoutIndex]=\"layoutIndex()\" [layoutNode]=\"widgetLayoutNode\"></select-widget-widget>\n </div>\n @if (widgetLayoutNode?.arrayItem && widgetLayoutNode?.type !== '$ref') {\n <div class=\"spacer\"></div>\n }\n </div>\n </div>","import { CdkDrag, CdkDragDrop } from '@angular/cdk/drag-drop';\r\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';\r\nimport { JsonSchemaFormService } from '@ng-formworks/core';\r\nimport { memoize } from 'lodash';\r\nimport { Subscription } from 'rxjs';\r\n\r\n\r\n@Component({\r\n // tslint:disable-next-line:component-selector\r\n selector: 'flex-layout-root-widget',\r\n template: `\r\n <div cdkDropList (cdkDropListDropped)=\"drop($event)\"\r\n [class.flex-inherit]=\"true\"\r\n [cdkDropListSortPredicate]=\"sortPredicate\"\r\n >\r\n <!-- -for now left out\r\n cdkDragHandle directive, by itself, does not disable the\r\n default drag behavior of its parent cdkDrag element.\r\n You must explicitly disable dragging on the main element\r\n and re-enable it only when using the handle.\r\n -->\r\n @for (layoutItem of layout(); track layoutItem; let i = $index) {\r\n <div\r\n cdkDrag [cdkDragStartDelay]=\"{touch:1000,mouse:0}\"\r\n [cdkDragDisabled]=\"!isDraggable(layoutItem)\"\r\n [class.form-flex-item]=\"isFlexItem()\"\r\n [style.flex-grow]=\"getFlexAttribute(layoutItem, 'flex-grow')\"\r\n [style.flex-shrink]=\"getFlexAttribute(layoutItem, 'flex-shrink')\"\r\n [style.flex-basis]=\"getFlexAttribute(layoutItem, 'flex-basis')\"\r\n [style.align-self]=\"(layoutItem?.options || {})['align-self']\"\r\n [style.order]=\"layoutItem?.options?.order\"\r\n [attr.fxFlex]=\"layoutItem?.options?.fxFlex\"\r\n [attr.fxFlexOrder]=\"layoutItem?.options?.fxFlexOrder\"\r\n [attr.fxFlexOffset]=\"layoutItem?.options?.fxFlexOffset\"\r\n [attr.fxFlexAlign]=\"layoutItem?.options?.fxFlexAlign\"\r\n >\r\n <!-- workaround to disbale dragging of input fields -->\r\n <!--\r\n <div *ngIf=\"layoutItem?.dataType !='object'\" cdkDragHandle>\r\n <p></p>\r\n </div>\r\n -->\r\n <!--\r\n <select-framework-widget *ngIf=\"showWidget(layoutItem)\"\r\n [dataIndex]=\"layoutItem?.arrayItem ? (dataIndex() || []).concat(i) : (dataIndex() || [])\"\r\n [layoutIndex]=\"(layoutIndex() || []).concat(i)\"\r\n [layoutNode]=\"layoutItem\"></select-framework-widget>\r\n -->\r\n @if (showWidget(layoutItem)) {\r\n <select-framework-widget\r\n [dataIndex]=\"getSelectFrameworkInputs(layoutItem,i).dataIndex\"\r\n [layoutIndex]=\"getSelectFrameworkInputs(layoutItem,i).layoutIndex\"\r\n [layoutNode]=\"getSelectFrameworkInputs(layoutItem,i).layoutNode\">\r\n </select-framework-widget>\r\n }\r\n </div>\r\n }\r\n </div>`,\r\n styles: `\r\n .example-list {\r\n width: 500px;\r\n max-width: 100%;\r\n border: solid 1px #ccc;\r\n min-height: 60px;\r\n display: block;\r\n background: white;\r\n border-radius: 4px;\r\n overflow: hidden;\r\n}\r\n\r\n.example-box {\r\n padding: 20px 10px;\r\n border-bottom: solid 1px #ccc;\r\n color: rgba(0, 0, 0, 0.87);\r\n display: flex;\r\n flex-direction: row;\r\n align-items: center;\r\n justify-content: space-between;\r\n box-sizing: border-box;\r\n cursor: move;\r\n background: white;\r\n font-size: 14px;\r\n}\r\n\r\n.cdk-drag-preview {\r\n border: none;\r\n box-sizing: border-box;\r\n border-radius: 4px;\r\n box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),\r\n 0 8px 10px 1px rgba(0, 0, 0, 0.14),\r\n 0 3px 14px 2px rgba(0, 0, 0, 0.12);\r\n}\r\n\r\n.cdk-drag-placeholder {\r\n opacity: 0;\r\n}\r\n\r\n.cdk-drag-animating {\r\n transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\r\n}\r\n\r\n.example-box:last-child {\r\n border: none;\r\n}\r\n\r\n.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {\r\n transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\r\n}\r\n.flex-inherit{\r\n display:inherit;\r\n flex-flow:inherit;\r\n flex-wrap:inherit;\r\n flex-direction:inherit;\r\n width:100%\r\n}\r\n \r\n`,\r\n //changeDetection: ChangeDetectionStrategy.Default,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n standalone: false\r\n})\r\nexport class FlexLayoutRootComponent implements OnInit, OnDestroy, OnChanges {\r\n\r\n private jsf = inject(JsonSchemaFormService);\r\n private cdr = inject(ChangeDetectorRef);\r\n\r\n readonly dataIndex = input<number[]>(undefined);\r\n readonly layoutIndex = input<number[]>(undefined);\r\n readonly layout = input<any[]>(undefined);\r\n readonly isOrderable = input<boolean>(undefined);\r\n readonly isFlexItem = input(false);\r\n readonly memoizationEnabled = input<boolean>(true);\r\n\r\n dataChangesSubs: Subscription;\r\n ngOnInit() {\r\n if (this.memoizationEnabled) {\r\n this.dataChangesSubs = this.jsf.dataChanges.subscribe((val) => {\r\n //this.selectframeworkInputCache?.clear();\r\n this._showWidgetMemoized.cache.clear();\r\n //TODO review-causing ngOnChanges to run where ever layoutnode is used as an input\r\n //commented out for now\r\n //this._getSelectFrameworkInputsMemoized.cache.clear();\r\n this.cdr.markForCheck();\r\n })\r\n }\r\n\r\n }\r\n removeItem(item) {\r\n this.jsf.removeItem(item);\r\n }\r\n\r\n drop(event: CdkDragDrop<string[]>) {\r\n // most likely why this event is used is to get the dragging element's current index\r\n let srcInd = event.previousIndex;\r\n let trgInd = event.currentIndex;\r\n let layoutItem = this.layout()[trgInd];\r\n let dataInd = layoutItem?.arrayItem ? (this.dataIndex() || []).concat(trgInd) : (this.dataIndex() || []);\r\n let layoutInd = (this.layoutIndex() || []).concat(trgInd)\r\n let itemCtx: any = {\r\n dataIndex: () => { return dataInd },\r\n layoutIndex: () => { return layoutInd },\r\n layoutNode: () => { return layoutItem },\r\n }\r\n this.jsf.moveArrayItem(itemCtx, srcInd, trgInd, true);\r\n }\r\n\r\n isDraggable(node: any): boolean {\r\n let result = node.arrayItem && node.type !== '$ref' &&\r\n node.arrayItemType === 'list' && this.isOrderable() !== false\r\n && node.type !== 'submit'\r\n return result;\r\n }\r\n\r\n\r\n /**\r\n * Predicate function that disallows '$ref' item sorts\r\n * NB declared as a var instead of a function \r\n * like sortPredicate(index: number, item: CdkDrag<number>){..}\r\n * since 'this' is bound to the draglist and doesn't reference the\r\n * FlexLayoutRootComponent instance\r\n */\r\n //TODO also need to think of other types such as button which can be\r\n //created by an arbitrary layout\r\n sortPredicate = (index: number, item: CdkDrag<number>) => {\r\n let layoutItem = this.layout()[index];\r\n let result = this.isDraggable(layoutItem);\r\n //layoutItem.type != '$ref';\r\n return result;\r\n }\r\n\r\n // Set attributes for flexbox child\r\n // (container attributes are set in flex-layout-section.component)\r\n getFlexAttribute(node: any, attribute: string) {\r\n const index = ['flex-grow', 'flex-shrink', 'flex-basis'].indexOf(attribute);\r\n return ((node.options || {}).flex || '').split(/\\s+/)[index] ||\r\n (node.options || {})[attribute] || ['1', '1', 'auto'][index];\r\n }\r\n\r\n private _getSelectFrameworkInputsRaw = (layoutItem: any, i: number) => {\r\n const dataIndexValue = this.dataIndex() || [];\r\n const layoutIndexValue = this.layoutIndex() || [];\r\n\r\n return {\r\n layoutNode: layoutItem,\r\n layoutIndex: [...layoutIndexValue, i],\r\n dataIndex: layoutItem?.arrayItem ? [...dataIndexValue, i] : dataIndexValue,\r\n };\r\n };\r\n\r\n // Define a separate function to hold the memoized version\r\n private _getSelectFrameworkInputsMemoized = memoize(\r\n this._getSelectFrameworkInputsRaw,\r\n (layoutItem: any, i: number) => {\r\n const layoutItemKey = layoutItem?.id ?? JSON.stringify(layoutItem);\r\n return `${layoutItemKey}-${i}`;\r\n }\r\n );\r\n\r\n // This is the public function that the template calls\r\n getSelectFrameworkInputs(layoutItem: any, i: number) {\r\n if (this.memoizationEnabled) {\r\n return this._getSelectFrameworkInputsMemoized(layoutItem, i);\r\n } else {\r\n return this._getSelectFrameworkInputsRaw(layoutItem, i);\r\n }\r\n }\r\n //TODO investigate-causing layout issue with layout,for now\r\n //removed from template\r\n trackByFn(index: number, item: any): any {\r\n return item._id ?? index;\r\n }\r\n // Public function used in the template\r\n showWidget(layoutNode: any): boolean {\r\n if (this.memoizationEnabled) {\r\n return this._showWidgetMemoized(layoutNode);\r\n } else {\r\n return this._showWidgetRaw(layoutNode);\r\n }\r\n }\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (changes['layout'] || changes['dataIndex'] || changes['layoutIndex']) {\r\n // Clear the entire cache of the memoized function\r\n this._showWidgetMemoized.cache.clear(); // Clear cache for showWidget\r\n this._getSelectFrameworkInputsMemoized.cache.clear();\r\n this.cdr.markForCheck();\r\n }\r\n }\r\n // Memoize the showWidget to avoid unnecessary recalculations\r\n private _showWidgetRaw = (layoutNode: any): boolean => {\r\n return this.jsf.evaluateCondition(layoutNode, this.dataIndex());\r\n };\r\n\r\n private _showWidgetMemoized = memoize(\r\n this._showWidgetRaw,\r\n (layoutNode: any) => {\r\n // Memoize based on the layoutNode and dataIndex\r\n return JSON.stringify(layoutNode) + '-' + (this.dataIndex() || []).join('-');\r\n }\r\n );\r\n ngOnDestroy(): void {\r\n //this.selectframeworkInputCache?.clear()\r\n //this.selectframeworkInputCache=null;\r\n this._getSelectFrameworkInputsMemoized.cache.clear();\r\n this.dataChangesSubs?.unsubscribe();\r\n }\r\n}\r\n","import { Component, OnChanges, OnDestroy, OnInit, SimpleChanges, inject, input } from '@angular/core';\r\nimport { AbstractControl } from '@angular/forms';\r\nimport { JsonSchemaFormService } from '@ng-formworks/core';\r\nimport { Subscription } from 'rxjs';\r\n\r\n@Component({\r\n // tslint:disable-next-line:component-selector\r\n selector: 'flex-layout-section-widget',\r\n template: `\r\n\r\n@if (containerType === 'div') {\r\n <div\r\n [class]=\"options?.htmlClass || ''\"\r\n [class.expandable]=\"options?.expandable && !expanded\"\r\n [class.expanded]=\"options?.expandable && expanded\">\r\n @if (!options.notitle) {\r\n <label\r\n [class]=\"'legend ' + (options?.labelHtmlClass || '')\"\r\n [innerHTML]=\"options.title|textTemplate:titleContext\"\r\n (click)=\"toggleExpanded()\"></label>\r\n }\r\n <flex-layout-root-widget\r\n [layout]=\"layoutNode().items\"\r\n [dataIndex]=\"dataIndex()\"\r\n [layoutIndex]=\"layoutIndex()\"\r\n [isFlexItem]=\"getFlexAttribute('is-flex')\"\r\n [class.form-flex-column]=\"getFlexAttribute('flex-direction') === 'column'\"\r\n [class.form-flex-row]=\"getFlexAttribute('flex-direction') === 'row'\"\r\n [style.display]=\"!expanded?'none':getFlexAttribute('display')\"\r\n [style.flex-direction]=\"getFlexAttribute('flex-direction')\"\r\n [style.flex-wrap]=\"getFlexAttribute('flex-wrap')\"\r\n [style.justify-content]=\"getFlexAttribute('justify-content')\"\r\n [style.align-items]=\"getFlexAttribute('align-items')\"\r\n [style.align-content]=\"getFlexAttribute('align-content')\"\r\n [attr.fxLayout]=\"getFlexAttribute('layout')\"\r\n [attr.fxLayoutGap]=\"options?.fxLayoutGap\"\r\n [attr.fxLayoutAlign]=\"options?.fxLayoutAlign\"\r\n [attr.fxFlexFill]=\"options?.fxLayoutAlign\"></flex-layout-root-widget>\r\n @if (options?.showErrors && options?.errorMessage) {\r\n <mat-error\r\n [innerHTML]=\"options?.errorMessage\"></mat-error>\r\n }\r\n </div>\r\n}\r\n\r\n@if (containerType === 'fieldset') {\r\n <fieldset\r\n [class]=\"options?.htmlClass || ''\"\r\n [class.expandable]=\"options?.expandable && !expanded\"\r\n [class.expanded]=\"options?.expandable && expanded\"\r\n [disabled]=\"options?.readonly\">\r\n @if (!options.notitle) {\r\n <legend\r\n [class]=\"'legend ' + (options?.labelHtmlClass || '')\"\r\n [innerHTML]=\"options.title|textTemplate:titleContext\"\r\n (click)=\"toggleExpanded()\"></legend>\r\n }\r\n <flex-layout-root-widget\r\n [layout]=\"layoutNode().items\"\r\n [dataIndex]=\"dataIndex()\"\r\n [layoutIndex]=\"layoutIndex()\"\r\n [isFlexItem]=\"getFlexAttribute('is-flex')\"\r\n [class.form-flex-column]=\"getFlexAttribute('flex-direction') === 'column'\"\r\n [class.form-flex-row]=\"getFlexAttribute('flex-direction') === 'row'\"\r\n [style.display]=\"!expanded?'none':getFlexAttribute('display')\"\r\n [style.flex-direction]=\"getFlexAttribute('flex-direction')\"\r\n [style.flex-wrap]=\"getFlexAttribute('flex-wrap')\"\r\n [style.justify-content]=\"getFlexAttribute('justify-content')\"\r\n [style.align-items]=\"getFlexAttribute('align-items')\"\r\n [style.align-content]=\"getFlexAttribute('align-content')\"\r\n [attr.fxLayout]=\"getFlexAttribute('layout')\"\r\n [attr.fxLayoutGap]=\"options?.fxLayoutGap\"\r\n [attr.fxLayoutAlign]=\"options?.fxLayoutAlign\"\r\n [attr.attr.fxFlexFill]=\"options?.fxLayoutAlign\"></flex-layout-root-widget>\r\n @if (options?.showErrors && options?.errorMessage) {\r\n <mat-error\r\n [innerHTML]=\"options?.errorMessage\"></mat-error>\r\n }\r\n </fieldset>\r\n}\r\n\r\n@if (containerType === 'card') {\r\n <mat-card appearance=\"outlined\"\r\n [ngClass]=\"options?.htmlClass || ''\"\r\n [class.expandable]=\"options?.expandable && !expanded\"\r\n [class.expanded]=\"options?.expandable && expanded\">\r\n @if (!options.notitle) {\r\n <mat-card-header>\r\n <legend\r\n [class]=\"'legend ' + (options?.labelHtmlClass || '')\"\r\n [innerHTML]=\"options.title|textTemplate:titleContext\"\r\n (click)=\"toggleExpanded()\"></legend>\r\n </mat-card-header>\r\n }\r\n <mat-card-content >\r\n <fieldset [disabled]=\"options?.readonly\">\r\n <flex-layout-root-widget\r\n [layout]=\"layoutNode().items\"\r\n [dataIndex]=\"dataIndex()\"\r\n [layoutIndex]=\"layoutIndex()\"\r\n [isFlexItem]=\"getFlexAttribute('is-flex')\"\r\n [class.form-flex-column]=\"getFlexAttribute('flex-direction') === 'column'\"\r\n [class.form-flex-row]=\"getFlexAttribute('flex-direction') === 'row'\"\r\n [style.display]=\"!expanded?'none':getFlexAttribute('display')\"\r\n [style.flex-direction]=\"getFlexAttribute('flex-direction')\"\r\n [style.flex-wrap]=\"getFlexAttribute('flex-wrap')\"\r\n [style.justify-content]=\"getFlexAttribute('justify-content')\"\r\n [style.align-items]=\"getFlexAttribute('align-items')\"\r\n [style.align-content]=\"getFlexAttribute('align-content')\"\r\n [attr.fxLayout]=\"getFlexAttribute('layout')\"\r\n [attr.fxLayoutGap]=\"options?.fxLayoutGap\"\r\n [attr.fxLayoutAlign]=\"options?.fxLayoutAlign\"\r\n [attr.fxFlexFill]=\"options?.fxLayoutAlign\"></flex-layout-root-widget>\r\n </fieldset>\r\n </mat-card-content>\r\n <mat-card-footer>\r\n @if (options?.showErrors && options?.errorMessage) {\r\n <mat-error\r\n [innerHTML]=\"options?.errorMessage\"></mat-error>\r\n }\r\n </mat-card-footer>\r\n </mat-card>\r\n}\r\n\r\n@if (containerType === 'expansion-panel') {\r\n <mat-expansion-panel\r\n [expanded]=\"expanded\"\r\n [hideToggle]=\"!options?.expandable\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>\r\n @if (!options.notitle) {\r\n <legend\r\n [class]=\"options?.labelHtmlClass\"\r\n [innerHTML]=\"options.title|textTemplate:titleContext\"\r\n (click)=\"toggleExpanded()\"></legend>\r\n }\r\n </mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <fieldset [disabled]=\"options?.readonly\">\r\n <flex-layout-root-widget\r\n [layout]=\"layoutNode().items\"\r\n [dataIndex]=\"dataIndex()\"\r\n [layoutIndex]=\"layoutIndex()\"\r\n [isFlexItem]=\"getFlexAttribute('is-flex')\"\r\n [class.form-flex-column]=\"getFlexAttribute('flex-direction') === 'column'\"\r\n [class.form-flex-row]=\"getFlexAttribute('flex-direction') === 'row'\"\r\n [style.display]=\"!expanded?'none':getFlexAttribute('display')\"\r\n [style.flex-direction]=\"getFlexAttribute('flex-direction')\"\r\n [style.flex-wrap]=\"getFlexAttribute('flex-wrap')\"\r\n [style.justify-content]=\"getFlexAttribute('justify-content')\"\r\n [style.align-items]=\"getFlexAttribute('align-items')\"\r\n [style.align-content]=\"getFlexAttribute('align-content')\"\r\n [attr.fxLayout]=\"getFlexAttribute('layout')\"\r\n [attr.fxLayoutGap]=\"options?.fxLayoutGap\"\r\n [attr.fxLayoutAlign]=\"options?.fxLayoutAlign\"\r\n [attr.fxFlexFill]=\"options?.fxLayoutAlign\"></flex-layout-root-widget>\r\n </fieldset>\r\n @if (options?.showErrors && options?.errorMessage) {\r\n <mat-error\r\n [innerHTML]=\"options?.errorMessage\"></mat-error>\r\n }\r\n </mat-expansion-panel>\r\n}`,\r\n styles: [`\r\n fieldset { border: 0; margin: 0; padding: 0; }\r\n .legend { font-weight: bold; }\r\n .expandable > .legend:before { content: '▶'; padding-right: .3em; font-family:auto }\r\n .expanded > .legend:before { content: '▼'; padding-right: .2em; }\r\n `],\r\n standalone: false\r\n})\r\nexport class FlexLayoutSectionComponent implements OnInit, OnDestroy, OnChanges\r\n {\r\n private jsf = inject(JsonSchemaFormService);\r\n\r\n formControl: AbstractControl;\r\n controlName: string;\r\n controlValue: any;\r\n controlDisabled = false;\r\n boundControl = false;\r\n options: any;\r\n expanded = true;\r\n containerType = 'div';\r\n readonly layoutNode = input<any>(undefined);\r\n readonly layoutIndex = input<number[]>(undefined);\r\n readonly dataIndex = input<number[]>(undefined);\r\n\r\n dataChangesSubs: Subscription;\r\n titleContext: any = {\r\n value: {},\r\n values: {},\r\n key: null\r\n }\r\n\r\n get sectionTitle() {\r\n return this.options.notitle ? null : this.jsf.setItemTitle(this);\r\n }\r\n\r\n ngOnInit() {\r\n this.jsf.initializeControl(this);\r\n this.options = this.layoutNode().options || {};\r\n this.expanded = typeof this.options.expanded === 'boolean' ?\r\n this.options.expanded : !this.options.expandable;\r\n switch (this.layoutNode().type) {\r\n case 'section': case 'array': case 'fieldset': case 'advancedfieldset':\r\n case 'authfieldset': case 'optionfieldset': case 'selectfieldset':\r\n this.containerType = 'fieldset';\r\n break;\r\n case 'card':\r\n this.containerType = 'card';\r\n break;\r\n case 'expansion-panel':\r\n this.containerType = 'expansion-panel';\r\n break;\r\n default: // 'div', 'flex', 'tab', 'conditional', 'actions'\r\n this.containerType = 'div';\r\n }\r\n this.updateTitleContext();\r\n this.dataChangesSubs = this.jsf.dataChanges.subscribe((val) => {\r\n this.updateTitleContext();\r\n // this.cdr.markForCheck();\r\n })\r\n }\r\n\r\n toggleExpanded() {\r\n if (this.options.expandable) { this.expanded = !this.expanded; }\r\n }\r\n\r\n // Set attributes for flexbox container\r\n // (child attributes are set in flex-layout-root.component)\r\n getFlexAttribute(attribute: string) {\r\n const flexActive: boolean =\r\n this.layoutNode().type === 'flex' ||\r\n !!this.options.displayFlex ||\r\n this.options.display === 'flex';\r\n // if (attribute !== 'flex' && !flexActive) { return null; }\r\n switch (attribute) {\r\n case 'is-flex':\r\n return flexActive;\r\n case 'display':\r\n return flexActive ? 'flex' : 'initial';\r\n case 'flex-direction': case 'flex-wrap':\r\n const index = ['flex-direction', 'flex-wrap'].indexOf(attribute);\r\n return (this.options['flex-flow'] || '').split(/\\s+/)[index] ||\r\n this.options[attribute] || ['column', 'nowrap'][index];\r\n case 'justify-content': case 'align-items': case 'align-content':\r\n return this.options[attribute];\r\n case 'layout':\r\n return (this.options.fxLayout || 'row') +\r\n this.options.fxLayoutWrap ? ' ' + this.options.fxLayoutWrap : '';\r\n\r\n }\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n\r\n }\r\n\r\n updateTitleContext() {\r\n this.titleContext = this.jsf.getItemTitleContext(this);\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.dataChangesSubs?.unsubscribe();\r\n }\r\n}\r\n","import { ChangeDetectionStrategy, Component, OnInit, inject, input } from '@angular/core';\r\nimport { JsonSchemaFormService } from '@ng-formworks/core';\r\n\r\n\r\n@Component({\r\n // tslint:disable-next-line:component-selector\r\n selector: 'material-add-reference-widget',\r\n template: `\n <section [class]=\"options?.htmlClass || ''\" align=\"end\">\n @if (showAddButton) {\n <button mat-raised-button\n [color]=\"options?.color || 'accent'\"\n [disabled]=\"options?.readonly\"\n (click)=\"addItem($event)\"\n [appStopPropagation]=\"['mousedown', 'touchstart']\">\n @if (options?.icon) {\n <span [class]=\"options?.icon\"></span>\n }\n @if (options?.title) {\n <span [innerHTML]=\"buttonText\"></span>\n }\n </button>\n }\n </section>`,\r\n changeDetection: ChangeDetectionStrategy.Default,\r\n standalone: false\r\n})\r\nexport class MaterialAddReferenceComponent implements OnInit {\r\n private jsf = inject(JsonSchemaFormService);\r\n\r\n options: any;\r\n itemCount: number;\r\n previousLayoutIndex: number[];\r\n previousDataIndex: number[];\r\n readonly layoutNode = input<any>(undefined);\r\n readonly layoutIndex = input<number[]>(undefined);\r\n readonly dataIndex = input<number[]>(undefined);\r\n\r\n ngOnInit() {\r\n this.options = this.layoutNode().options || {};\r\n }\r\n\r\n get showAddButton(): boolean {\r\n return !this.layoutNode().arrayItem ||\r\n this.layoutIndex()[this.layoutIndex().length - 1] < this.options.maxItems;\r\n }\r\n\r\n addItem(event) {\r\n event.preventDefault();\r\n this.jsf.addItem(this);\r\n }\r\n\r\n get buttonText(): string {\r\n const parent: any = {\r\n dataIndex: this.dataIndex().slice(0, -1),\r\n layoutIndex: this.layoutIndex().slice(0, -1),\r\n layoutNode: this.jsf.getParentNode(this),\r\n };\r\n return parent.layoutNode && (parent.layoutNode.add ||\r\n this.jsf.setArrayItemTitle(parent, this.layoutNode(), this.itemCount));\r\n }\r\n}\r\n","import { Component, OnDestroy, OnInit, inject, input } from '@angular/core';\r\nimport { AbstractControl } from '@angular/forms';\r\nimport { JsonSchemaFormService, hasOwn } from '@ng-formworks/core';\r\nimport { Subscription } from 'rxjs';\r\n\r\n@Component({\r\n // tslint:disable-next-line:component-selector\r\n selector: 'material-button-widget',\r\n template: `\n <div class=\"button-row\" [class]=\"options?.htmlClass || ''\">\n <button mat-raised-button\n [attr.readonly]=\"options?.readonly ? 'readonly' : null\"\n [attr.aria-describedby]=\"'control' + layoutNode()?._id + 'Status'\"\n [color]=\"options?.color || 'primary'\"\n [disabled]=\"controlDisabled || options?.readonly\"\n [id]=\"'control' + layoutNode()?._id\"\n [name]=\"controlName\"\n [type]=\"layoutNode()?.type\"\n [value]=\"controlValue\"\n (click)=\"updateValue($event)\"\n [appStopPropagation]=\"['mousedown', 'touchstart']\"\n >\n @if (options?.icon) {\n <mat-icon class=\"mat-24\">{{options?.icon}}</mat-icon>\n }\n @if (options?.title) {\n <span [innerHTML]=\"layoutNode().options?.title\"></span>\n }\n </button>\n </div>`,\r\n styles: [` button { margin-top: 10px; } `],\r\n standalone: false\r\n})\r\nexport class MaterialButtonComponent implements OnInit,OnDestroy {\r\n private jsf = inject(JsonSchemaFormService);\r\n\r\n formControl: AbstractControl;\r\n controlName: string;\r\n controlValue: any;\r\n controlDisabled = false;\r\n boundControl = false;\r\n options: any;\r\n readonly layoutNode = input<any>(undefined);\r\n readonly layoutIndex = input<number[]>(undefined);\r\n readonly dataIndex = input<number[]>(undefined);\r\n\r\n isValidChangesSubs:Subscription;\r\n\r\n ngOnDestroy(): void {\r\n this.isValidChangesSubs?.unsubscribe();\r\n this.isValidChangesSubs=null;\r\n this.updateValue({target:{value:null}});\r\n }\r\n\r\n ngOnInit() {\r\n this.options = this.layoutNode().options || {};\r\n this.jsf.initializeControl(this);\r\n if (hasOwn(this.options, 'disabled')) {\r\n this.controlDisabled = this.options.disabled;\r\n } else if (this.jsf.formOptions.disableInvalidSubmit) {\r\n this.controlDisabled = !this.jsf.isValid;\r\n this.jsf.isValidChanges.subscribe(isValid => this.controlDisabled = !isValid);\r\n }\r\n }\r\n\r\n updateValue(event) {\r\n if (typeof this.options.onClick === 'function') {\r\n this.options.onClick(event);\r\n } else {\r\n this.jsf.updateValue(this, event.target.value);\r\n }\r\n }\r\n\r\n \r\n}\r\n","import { Component, OnDestroy, OnInit, inject, input } from '@angular/core';\r\nimport { AbstractControl } from '@angular/forms';\r\nimport { JsonSchemaFormService, buildTitleMap } from '@ng-formworks/core';\r\n\r\n\r\n@Component({\r\n // tslint:disable-next-line:component-selector\r\n selector: 'material-button-group-widget',\r\n template: `\n <div>\n @if (options?.title) {\n <div>\n <label\n [attr.for]=\"'control' + layoutNode()?._id\"\n [class]=\"options?.labelHtmlClass || ''\"\n [style.display]=\"options?.notitle ? 'none' : ''\"\n [innerHTML]=\"layoutNode().options?.title\"></label>\n </div>\n }\n <mat-button-toggle-group\n [attr.aria-describedby]=\"'control' + layoutNode()?._id + 'Status'\"\n [attr.readonly]=\"options?.readonly ? 'readonly' : null\"\n [attr.required]=\"options?.required\"\n [disabled]=\"controlDisabled || options?.readonly\"\n [name]=\"controlName\"\n [value]=\"controlValue\"\n [vertical]=\"!!options.vertical\">\n @for (radioItem of radiosList; track radioItem) {\n <mat-button-toggle\n [id]=\"'control' + layoutNode()?._id + '/' + radioItem?.name\"\n [value]=\"radioItem?.value\"\n (click)=\"updateValue(radioItem?.value)\">\n <span [innerHTML]=\"radioItem?.name\"></span>\n </mat-button-toggle>\n }\n </mat-button-toggle-group>\n @if (options?.showErrors && options?.errorMessage) {\n <mat-error\n [innerHTML]=\"options?.errorMessage\"></mat-error>\n }\n </div>`,\r\n styles: [` mat-error { font-size: 75%; } `],\r\n standalone: false\r\n})\r\nexport class MaterialButtonGroupComponent implements OnInit,OnDestroy {\r\n private jsf = inject(JsonSchemaFormService);\r\n\r\n formControl: AbstractControl;\r\n controlName: string;\r\n controlValue: any;\r\n controlDisabled = false;\r\n boundControl = false;\r\n options: any;\r\n radiosList: any[] = [];\r\n vertical = false;\r\n readonly layoutNode = input<any>(undefined);\r\n readonly layoutIndex = input<number[]>(undefined);\r\n readonly dataIndex = input<number[]>(undefined);\r\n\r\n ngOnInit() {\r\n this.options = this.layoutNode().options || {};\r\n this.radiosList = buildTitleMap(\r\n this.options.titleMap || this.options.enumNames,\r\n this.options.enum, true\r\n );\r\n this.jsf.initializeControl(this);\r\n }\r\n\r\n updateValue(value) {\r\n this.options.showErrors = true;\r\n this.jsf.updateValue(this, value);\r\n }\r\n ngOnDestroy () {\r\n this.jsf.updateValue(this, null);\r\n }\r\n}\r\n","import { Component, inject, input, OnDestroy, OnInit } from '@angular/core';\r\nimport { AbstractControl } from '@angular/forms';\r\nimport { JsonSchemaFormService } from '@ng-formworks/core';\r\n\r\n@Component({\r\n // tslint:disable-next-line:component-selector\r\n selector: 'material-checkbox-widget',\r\n template: `\n @if (boundControl && !showSlideToggle) {\n <mat-checkbox\n [formControl]=\"formControl\"\n align=\"left\"\n [color]=\"options?.color || 'primary'\"\n [id]=\"'control' + layoutNode()?._id\"\n labelPosition=\"after\"\n [name]=\"controlName\"\n (blur)=\"options.showErrors = true\">\n @if (options?.title) {\n <span\n class=\"checkbox-name\"\n [style.display]=\"options?.notitle ? 'none' : ''\"\n [innerHTML]=\"layoutNode().options?.title\"></span>\n }\n </mat-checkbox>\n }\n @if (!boundControl && !showSlideToggle) {\n <mat-checkbox\n align=\"left\"\n [color]=\"options?.color || 'primary'\"\n [disabled]=\"controlDisabled || options?.readonly\"\n [id]=\"'control' + layoutNode()?._id\"\n labelPosition=\"after\"\n [name]=\"controlName\"\n [checked]=\"isChecked\"\n (blur)=\"options.showErrors = true\"\n (change)=\"updateValue($event)\">\n @if (options?.title) {\n <span\n class=\"checkbox-name\"\n [style.display]=\"options?.notitle ? 'none' : ''\"\n [innerHTML]=\"layoutNode().options?.title\"></span>\n }\n </mat-checkbox>\n }\n @if (boundControl && showSlideToggle) {\n <mat-slide-toggle\n [formControl]=\"formControl\"\n align=\"left\"\n [color]=\"options?.color || 'primary'\"\n [id]=\"'control' + layoutNode()?._id\"\n labelPosition=\"after\"\n [name]=\"controlName\"\n (blur)=\"options.showErrors = true\">\n @if (options?.title) {\n <span\n class=\"checkbox-name\"\n [style.display]=\"options?.notitle ? 'none' : ''\"\n [innerHTML]=\"layoutNode().options?.title\"></span>\n }\n </mat-slide-toggle>\n }\n @if (!boundControl && showSlideToggle) {\n <mat-slide-toggle\n align=\"left\"\n [color]=\"options?.color || 'primary'\"\n [disabled]=\"controlDisabled || options?.readonly\"\n [id]=\"'control' + layoutNode()?._id\"\n labelPosition=\"after\"\n [name]=\"controlName\"\n [checked]=\"isChecked\"\n (blur)=\"options.showErrors = true\"\n (change)=\"updateValue($event)\">\n @if (options?.title) {\n <span\n class=\"checkbox-name\"\n [style.display]=\"options?.notitle ? 'none' : ''\"\n [innerHTML]=\"layoutNode().options?.title\"></span>\n }\n </mat-slide-toggle>\n }\n @if (options?.showErrors && options?.errorMessage) {\n <mat-error\n [innerHTML]=\"options?.errorMessage\"></mat-error>\n }`,\r\n styles: [`\r\n .checkbox-name { white-space: nowrap; }\r\n mat-error { font-size: 75%; }\r\n `],\r\n standalone: false\r\n})\r\nexport class MaterialCheckboxComponent implements OnInit,OnDestroy {\r\n private jsf = inject(JsonSchemaFormService);\r\n\r\n formControl: AbstractControl;\r\n controlName: string;\r\n controlValue: any;\r\n controlDisabled = false;\r\n boundControl = false;\r\n options: any;\r\n trueValue: any = true;\r\n falseValue: any = false;\r\n showSlideToggle = false;\r\n readonly layoutNode = input<any>(undefined);\r\n readonly layoutIndex = input<number[]>(undefined);\r\n readonly dataIndex = input<number[]>(undefined);\r\n\r\n ngOnInit() {\r\n this.options = this.layoutNode().options || {};\r\n this.jsf.initializeControl(this, !this.options.readonly);\r\n if (this.controlValue === null || this.controlValue === undefined) {\r\n this.controlValue = false;\r\n this.jsf.updateValue(this, this.falseValue);\r\n }\r\n const layoutNode = this.layoutNode();\r\n if (layoutNode.type === 'slide-toggle' ||\r\n layoutNode.format === 'slide-toggle'\r\n ) {\r\n this.showSlideToggle = true;\r\n }\r\n }\r\n\r\n updateValue(event) {\r\n this.options.showErrors = true;\r\n this.jsf.updateValue(this, event.checked ? this.trueValue : this.falseValue);\r\n }\r\n\r\n get isChecked() {\r\n return this.jsf.getFormControlValue(this) === this.trueValue;\r\n }\r\n\r\n ngOnDestroy () {\r\n this.jsf.updateValue(this, null);\r\n }\r\n}\r\n","import { Component, OnDestroy, OnInit, inject, input } from '@angular/core';\r\nimport { AbstractControl } from '@angular/forms';\r\nimport { JsonSchemaFormService, TitleMapItem, buildTitleMap } from '@ng-formworks/core';\r\n\r\n// TODO: Change this to use a Selection List instead?\r\n// https://material.angular.io/components/list/overview\r\n\r\n@Component({\r\n // tslint:disable-next-line:component-selector\r\n selector: 'material-checkboxes-widget',\r\n template: `\n <div>\n <mat-checkbox type=\"checkbox\"\n [checked]=\"allChecked\"\n [color]=\"options?.color || 'primary'\"\n [disabled]=\"controlDisabled || options?.readonly\"\n [indeterminate]=\"someChecked\"\n [name]=\"options?.name\"\n (blur)=\"options.showErrors = true\"\n (change)=\"updateAllValues($event)\">\n <span class=\"checkbox-name\" [innerHTML]=\"options?.name\"></span>\n </mat-checkbox>\n @if (options?.title) {\n <label\n class=\"title\"\n [class]=\"options?.labelHtmlClass || ''\"\n [style.display]=\"options?.notitle ? 'none' : ''\"\n [innerHTML]=\"layoutNode().options?.title\"></label>\n }\n <ul class=\"checkbox-list\" [class.horizontal-list]=\"horizontalList\">\n @for (checkboxItem of checkboxList; track checkboxItem) {\n <li\n [class]=\"options?.htmlClass || ''\">\n <mat-checkbox type=\"checkbox\"\n [(ngModel)]=\"checkboxItem.checked\"\n [color]=\"options?.color || 'primary'\"\n [disabled]=\"controlDisabled || options?.readonly\"\n [name]=\"checkboxItem?.name\"\n (blur)=\"options.showErrors = true\"\n (change)=\"updateValue()\">\n <span class=\"checkbox-name\" [innerHTML]=\"checkboxItem?.name\"></span>\n </mat-checkbox>\n </li>\n }\n </ul>\n @if (options?.showErrors && options?.errorMessage) {\n <mat-error\n [innerHTML]=\"options?.errorMessage\"></mat-error>\n }\n </div>`,\r\n styles: [`\r\n .title { font-weight: bold; }\r\n .checkbox-list { list-style-type: none; }\r\n .horizontal-list > li { display: inline-block; margin-right: 10px; zoom: 1; }\r\n .checkbox-name { white-space: nowrap; }\r\n mat-error { font-size: 75%; }\r\n `],\r\n standalone: false\r\n})\r\nexport class MaterialCheckboxesComponent implements OnInit,OnDestroy {\r\n private jsf = inject(JsonSchemaFormService);\r\n\r\n formControl: AbstractControl;\r\n controlName: string;\r\n controlValue: any;\r\n controlDisabled = false;\r\n boundControl = false;\r\n options: any;\r\n horizontalList = false;\r\n formArray: AbstractControl;\r\n checkboxList: TitleMapItem[] = [];\r\n readonly layoutNode = input<any>(undefined);\r\n readonly layoutIndex = input<number[]>(undefined);\r\n readonly dataIndex = input<number[]>(undefined);\r\n\r\n ngOnInit() {\r\n this.options = this.layoutNode().options || {};\r\n const layoutNode = this.layoutNode();\r\n this.horizontalList = layoutNode.type === 'checkboxes-inline' ||\r\n layoutNode.type === 'checkboxbuttons';\r\n this.jsf.initializeControl(this);\r\n this.checkboxList = buildTitleMap(\r\n this.options.titleMap || this.options.enumNames, this.options.enum, true\r\n );\r\n if (this.boundControl) {\r\n const formArray = this.jsf.getFormControl(this);\r\n for (const checkboxItem of this.checkboxList) {\r\n checkboxItem.checked = formArray.value.includes(checkboxItem.value);\r\n }\r\n }\r\n }\r\n\r\n get allChecked(): boolean {\r\n return this.checkboxList.filter(t => t.checked).length === this.checkboxList.length;\r\n }\r\n\r\n get someChecked(): boolean {\r\n const checkedItems = this.checkboxList.filter(t => t.checked).length;\r\n return checkedItems > 0 && checkedItems < this.checkboxList.length;\r\n }\r\n\r\n updateValue() {\r\n this.options.showErrors = true;\r\n if (this.boundControl) {\r\n this.jsf.updateArrayCheckboxList(this, this.checkboxList);\r\n }\r\n }\r\n\r\n updateAllValues(event: any) {\r\n this.options.showErrors = true;\r\n this.checkboxList.forEach(t => t.checked = event.checked);\r\n this.updateValue();\r\n }\r\n \r\n //TODO review this\r\n ngOnDestroy () {\r\n //this.jsf.updateValue(this, null);\r\n let nullVal=[];\r\n this.formControl.reset(nullVal)\r\n this.controlValue=null;\r\n }\r\n}\r\n","import { Component, inject, input, OnDestroy, OnInit } from '@angular/core';\r\nimport { AbstractControl } from '@angular/forms';\r\nimport { JsonSchemaFormService } from '@ng-formworks/core';\r\n\r\n// TODO: Add this control\r\n\r\n@Component({\r\n // tslint:disable-next-line:component-selector\r\n selector: 'material-chip-list-widget',\r\n template: ``,\r\n standalone: false\r\n})\r\nexport class MaterialChipListComponent implements OnInit,OnDestroy {\r\n private jsf = inject(JsonSchemaFormService);\r\n\r\n formControl: AbstractControl;\r\n controlName: string;\r\n controlValue: any;\r\n controlDisabled = false;\r\n boundControl = false;\r\n options: any;\r\n readonly layoutNode = input<any>(undefined);\r\n readonly layoutIndex = input<number[]>(undefined);\r\n readonly dataIndex = input<number[]>(undefined);\r\n\r\n ngOnInit() {\r\n this.options = this.layoutNode().options || {};\r\n this.jsf.initializeControl(this);\r\n }\r\n\r\n updateValue(event) {\r\n this.jsf.updateValue(this, event.target.value);\r\n }\r\n\r\n ngOnDestroy () {\r\n this.jsf.updateValue(this, null);\r\n }\r\n\r\n}\r\n","import { Component, inject, input, OnDestroy, OnInit } from '@angular/core';\r\nimport { AbstractControl } from '@angular/forms';\r\nimport { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';\r\nimport { JsonSchemaFormService } from '@ng-formworks/core';\r\n\r\n@Component({\r\n