16
16
*/
17
17
import { Location } from '@angular/common' ;
18
18
import { Component , EventEmitter , Input , OnChanges , OnDestroy , OnInit , Output , SimpleChanges , ViewEncapsulation } from '@angular/core' ;
19
- import { UntypedFormControl , UntypedFormGroup } from '@angular/forms' ;
19
+ import { Form , UntypedFormGroup } from '@angular/forms' ;
20
20
import { ActivatedRoute } from '@angular/router' ;
21
21
import { FormlyFieldConfig , FormlyFormOptions } from '@ngx-formly/core' ;
22
22
import { FormlyJsonschema } from '@ngx-formly/core/json-schema' ;
@@ -32,9 +32,9 @@ import { AbstractCanDeactivateComponent } from '../../component/abstract-can-dea
32
32
import { Error } from '../../error/error' ;
33
33
import { RouteCollectionService } from '../../route/route-collection.service' ;
34
34
import { LoggerService } from '../../service/logger.service' ;
35
- import { Record } from '../record' ;
36
35
import { RecordUiService } from '../record-ui.service' ;
37
36
import { RecordService } from '../record.service' ;
37
+ import { JSONSchemaService } from './services/jsonschema.service' ;
38
38
import { processJsonSchema , removeEmptyValues , resolve$ref } from './utils' ;
39
39
import { LoadTemplateFormComponent } from './widgets/load-template-form/load-template-form.component' ;
40
40
import { SaveTemplateFormComponent } from './widgets/save-template-form/save-template-form.component' ;
@@ -83,7 +83,7 @@ export class EditorComponent extends AbstractCanDeactivateComponent implements O
83
83
fields : FormlyFieldConfig [ ] ;
84
84
85
85
// root element of the editor
86
- rootFormlyConfig : FormlyFieldConfig ;
86
+ rootField : FormlyFieldConfig ;
87
87
88
88
// list of fields to display in the TOC
89
89
tocFields$ : Observable < any > ;
@@ -123,15 +123,6 @@ export class EditorComponent extends AbstractCanDeactivateComponent implements O
123
123
// Config for resource
124
124
private _resourceConfig : any ;
125
125
126
- // list of custom validators
127
- private _customValidators = [
128
- 'valueAlreadyExists' ,
129
- 'uniqueValueKeysInObject' ,
130
- 'numberOfSpecificValuesInObject' ,
131
- 'dateMustBeGreaterThan' ,
132
- 'dateMustBeLessThan'
133
- ] ;
134
-
135
126
// list of fields to be hidden
136
127
private _hiddenFields : FormlyFieldConfig [ ] = [ ] ;
137
128
@@ -148,16 +139,6 @@ export class EditorComponent extends AbstractCanDeactivateComponent implements O
148
139
return this . editorSettings . longMode ;
149
140
}
150
141
151
- // Editor edit mode
152
- public get editMode ( ) : boolean {
153
- return this . pid ? true : false ;
154
- }
155
-
156
- // Editor root field
157
- public get rootField ( ) : FormlyFieldConfig {
158
- return this . rootFormlyConfig ;
159
- }
160
-
161
142
// Editor function
162
143
public get editorComponent ( ) : ( ) => EditorComponent {
163
144
return ( ) => this ;
@@ -188,7 +169,8 @@ export class EditorComponent extends AbstractCanDeactivateComponent implements O
188
169
protected location : Location ,
189
170
protected modalService : BsModalService ,
190
171
protected routeCollectionService : RouteCollectionService ,
191
- protected loggerService : LoggerService
172
+ protected loggerService : LoggerService ,
173
+ protected jsonschemaService : JSONSchemaService
192
174
) {
193
175
super ( ) ;
194
176
this . form = new UntypedFormGroup ( { } ) ;
@@ -458,39 +440,23 @@ export class EditorComponent extends AbstractCanDeactivateComponent implements O
458
440
this . clearHiddenFields ( ) ;
459
441
460
442
// form configuration
443
+ const editorConfig = {
444
+ pid : this . pid ,
445
+ longMode : this . longMode ,
446
+ recordType : this . recordType
447
+ }
461
448
const fields = [
462
449
this . formlyJsonschema . toFieldConfig ( this . schema , {
463
450
// post process JSONSChema7 to FormlyFieldConfig conversion
464
451
map : ( field : FormlyFieldConfig , jsonSchema : JSONSchema7 ) => {
465
452
/**** additional JSONSchema configurations *******/
466
-
467
- // initial population of arrays with a minItems constraints
468
- if ( jsonSchema . minItems && ! jsonSchema . hasOwnProperty ( 'default' ) ) {
469
- field . defaultValue = new Array ( jsonSchema . minItems ) ;
470
- }
471
- // If 'format' is defined into the jsonSchema, use it as props to try a validation on this field.
472
- // See: `email.validator.ts` file
473
- if ( jsonSchema . format ) {
474
- field . props . type = jsonSchema . format ;
475
- }
476
-
477
- if ( jsonSchema ?. widget ?. formlyConfig ) {
478
- const { props } = jsonSchema . widget . formlyConfig ;
479
-
480
- if ( props ) {
481
- this . _setSimpleOptions ( field , props ) ;
482
- this . _setValidation ( field , props ) ;
483
- this . _setRemoteSelectOptions ( field , props ) ;
484
- this . _setRemoteTypeahead ( field , props ) ;
485
- }
486
- }
487
- // Add editor component function on the field
488
- field . props . editorComponent = this . editorComponent ;
489
-
453
+ field = this . jsonschemaService . processField ( field , jsonSchema ) ;
454
+ field . props . editorConfig = editorConfig ;
455
+ field . props . getRoot = ( ( ) => this . rootField ) ;
456
+ field . props . setHide = ( ( field : FormlyFieldConfig , value : boolean ) => this . setHide ( field , value ) ) ;
490
457
if ( this . _resourceConfig != null && this . _resourceConfig . formFieldMap ) {
491
458
return this . _resourceConfig . formFieldMap ( field , jsonSchema ) ;
492
459
}
493
-
494
460
return field ;
495
461
}
496
462
} )
@@ -504,7 +470,7 @@ export class EditorComponent extends AbstractCanDeactivateComponent implements O
504
470
if ( this . fields ) {
505
471
this . title = this . fields [ 0 ] . props ?. label ;
506
472
this . description = this . fields [ 0 ] . props ?. description ;
507
- this . rootFormlyConfig = this . fields [ 0 ] ;
473
+ this . rootField = this . fields [ 0 ] ;
508
474
}
509
475
}
510
476
@@ -775,147 +741,25 @@ export class EditorComponent extends AbstractCanDeactivateComponent implements O
775
741
* Hide the given formly field.
776
742
* @param field - FormlyFieldConfig, the field to hide
777
743
*/
778
- hide ( field : FormlyFieldConfig ) : void {
779
- field . hide = true ;
780
- if ( this . isRoot ( field . parent ) ) {
781
- this . addHiddenField ( field ) ;
744
+ setHide ( field : FormlyFieldConfig , value : boolean ) : void {
745
+ if ( value ) {
746
+ if ( field . parent . props . isRoot ) {
747
+ this . addHiddenField ( field ) ;
748
+ }
749
+ } else {
750
+ this . removeHiddenField ( field ) ;
751
+ // scroll at the right position
752
+ // to avoid: Expression has changed after it was checked
753
+ // See: https://blog.angular-university.io/angular-debugging/
754
+ // wait that the component is present in the DOM
755
+ setTimeout ( ( ) => this . setFieldFocus ( field , true ) ) ;
782
756
}
757
+ field . hide = value ;
783
758
}
784
759
785
760
/********************* Private ***************************************/
786
761
787
- /**
788
- * Populate a select options with a remote API call.
789
- * @param field formly field config
790
- * @param formOptions JSONSchema object
791
- */
792
- private _setRemoteSelectOptions (
793
- field : FormlyFieldConfig ,
794
- formOptions : any
795
- ) : void {
796
- if ( formOptions . remoteOptions && formOptions . remoteOptions . type ) {
797
- field . type = 'select' ;
798
- field . hooks = {
799
- ...field . hooks ,
800
- afterContentInit : ( f : FormlyFieldConfig ) => {
801
- const recordType = formOptions . remoteOptions . type ;
802
- const query = formOptions . remoteOptions . query || '' ;
803
- f . props . options = this . recordService
804
- . getRecords ( recordType , query , 1 , RecordService . MAX_REST_RESULTS_SIZE )
805
- . pipe (
806
- map ( ( data : Record ) =>
807
- data . hits . hits . map ( ( record : any ) => {
808
- return {
809
- label : formOptions . remoteOptions . labelField && formOptions . remoteOptions . labelField in record . metadata
810
- ? record . metadata [ formOptions . remoteOptions . labelField ]
811
- : record . metadata . name ,
812
- value : this . apiService . getRefEndpoint (
813
- recordType ,
814
- record . id
815
- )
816
- } ;
817
- } )
818
- )
819
- ) ;
820
- }
821
- } ;
822
- }
823
- }
824
762
825
- /**
826
- * Store the remote typeahead options.
827
- * @param field formly field config
828
- * @param formOptions JSONSchema object
829
- */
830
- private _setRemoteTypeahead (
831
- field : FormlyFieldConfig ,
832
- formOptions : any
833
- ) : void {
834
- if ( formOptions . remoteTypeahead && formOptions . remoteTypeahead . type ) {
835
- field . type = 'remoteTypeahead' ;
836
- field . props = {
837
- ...field . props ,
838
- ...{ remoteTypeahead : formOptions . remoteTypeahead }
839
- } ;
840
- }
841
- }
842
-
843
- /**
844
- *
845
- * @param field formly field config
846
- * @param formOptions JSONSchema object
847
- */
848
- private _setValidation ( field : FormlyFieldConfig , formOptions : any ) : void {
849
- if ( formOptions . validation ) {
850
- // custom validation messages
851
- // TODO: use widget instead
852
- const { messages } = formOptions . validation ;
853
- if ( messages ) {
854
- if ( ! field . validation ) {
855
- field . validation = { } ;
856
- }
857
- if ( ! field . validation . messages ) {
858
- field . validation . messages = { } ;
859
- }
860
- for ( const key of Object . keys ( messages ) ) {
861
- const msg = messages [ key ] ;
862
- // add support of key with or without Message suffix (required == requiredMessage),
863
- // this is useful for backend translation extraction
864
- field . validation . messages [ key . replace ( / M e s s a g e $ / , '' ) ] = ( error , f : FormlyFieldConfig ) =>
865
- // translate the validation messages coming from the JSONSchema
866
- // TODO: need to remove `as any` once it is fixed in ngx-formly v.5.7.2
867
- this . translateService . stream ( msg ) as any ;
868
- }
869
- }
870
-
871
- // store the custom validators config
872
- field . props . customValidators = { } ;
873
- if ( formOptions . validation && formOptions . validation . validators ) {
874
- for ( const customValidator of this . _customValidators ) {
875
- const validatorConfig = formOptions . validation . validators [ customValidator ] ;
876
- if ( validatorConfig != null ) {
877
- field . props . customValidators [ customValidator ] = validatorConfig ;
878
- }
879
- }
880
- }
881
-
882
- if ( formOptions . validation . validators ) {
883
- // validators: add validator with expressions
884
- // TODO: use widget
885
- const validatorsKey = Object . keys ( formOptions . validation . validators ) ;
886
- validatorsKey . map ( validatorKey => {
887
- const validator = formOptions . validation . validators [ validatorKey ] ;
888
- if ( 'expression' in validator && 'message' in validator ) {
889
- const { expression } = validator ;
890
- const expressionFn = Function ( 'formControl' , `return ${ expression } ;` ) ;
891
- const validatorExpression = {
892
- expression : ( fc : UntypedFormControl ) => expressionFn ( fc ) ,
893
- // translate the validation message coming form the JSONSchema
894
- message : this . translateService . stream ( validator . message )
895
- } ;
896
- field . validators = field . validators !== undefined ? field . validators : { } ;
897
- field . validators [ validatorKey ] = validatorExpression ;
898
- }
899
- } ) ;
900
- }
901
- }
902
- }
903
-
904
- /**
905
- * Convert JSONSchema form options to formly field options.
906
- * @param field formly field config
907
- * @param formOptions JSONSchema object
908
- */
909
- private _setSimpleOptions ( field : FormlyFieldConfig , formOptions : any ) : void {
910
- // some fields should not submit the form when enter key is pressed
911
- if ( field . props . doNotSubmitOnEnter != null ) {
912
- field . props . keydown = ( f : FormlyFieldConfig , event ?: any ) => {
913
- if ( event . key === 'Enter' ) {
914
- event . preventDefault ( ) ;
915
- }
916
- } ;
917
- }
918
- }
919
763
920
764
/**
921
765
* Handle form error
0 commit comments