ng-dynamic-forms icon indicating copy to clipboard operation
ng-dynamic-forms copied to clipboard

Custom Form Models

Open knight-bubble opened this issue 4 years ago • 4 comments

I'm submitting a


[ ] Bug / Regression
[x] Feature Request / Proposal

I'm using


NG Dynamic Forms Version: `13.0.0`

[x] Basic UI
[ ] Bootstrap UI  
[ ] Foundation UI
[ ] Ionic UI
[ ] Kendo UI
[ ] Material  
[ ] NG Bootstrap
[ ] Prime NG

Description

Now you can define custom controls and then use them to replace existing ones. As described here Custom Form Controls However it is still missing a clear description about what exactly it does, and as I understand it doesn't allow to ADD a control, it allows to REPLACE one based on the type defined in the lib.

But what if needs to be added a new model form? What would be the way to do that? I came up with a solution that requires redefining fromJSON method of DynamicFormService, but is it the way, or there is a solution that I am not aware of?

So my proposal/question is:

  1. if there is a good solution to add a new input model w/o injecting a new service, it has to be added to the README file.
  2. If there is no such way, to add one :)

knight-bubble avatar Jun 25 '21 16:06 knight-bubble

@knight-bubble

I admit the docs here are not perfect. In general, you're also free to plug in your own custom model.

However, there's one limitation: at the moment a custom form control model cannot be recreated from JSON.

Thus, when using a custom form control model you need to provide your form model as code rather than JSON.

  1. Create a class that inherits from DynamicFormControlModel.
export const MY_DYNAMIC_FORM_CONTROL_TYPE = "MY_CUSTOM_TYPE";

export class MyDynamicFormControlModel extends DynamicFormControlModel {

  @serializable() readonly type: string = MY_DYNAMIC_FORM_CONTROL_TYPE;
  //...
}
  1. Create a class for the corresponding custom form control according to the docs:
@Component({
    selector: "my-dynamic-custom-form-control",
    templateUrl: "./my-dynamic-custom-form-control.component.html",
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyDynamicCustomFormControlComponent extends DynamicFormControlComponent {
    @Input() group!: FormGroup;
    @Input() layout?: DynamicFormLayout;
    @Input() model!: MyDynamicFormControlModel;

    @Output() blur: EventEmitter<any> = new EventEmitter();
    @Output() change: EventEmitter<any> = new EventEmitter();
    @Output() customEvent: EventEmitter<DynamicFormControlCustomEvent> = new EventEmitter();
    @Output() focus: EventEmitter<any> = new EventEmitter();

    @ViewChild(MyCustomFormControlComponent) myCustomFormControlComponent!: MyCustomFormControlComponent;

    constructor(protected layoutService: DynamicFormLayoutService,
                protected validationService: DynamicFormValidationService) {
        super(layoutService, validationService);
    }
}
  1. Map your custom model class to your custom form control via DYNAMIC_FORM_CONTROL_MAP_FN:
providers: [
  {
    provide: DYNAMIC_FORM_CONTROL_MAP_FN,
    useValue: (model: DynamicFormControlModel): Type<DynamicFormControl> | null  => {
      switch (model.type) {
        case MyDynamicFormControlModel;
          return MyDynamicCustomFormControlComponent;

        }
     }
  }
]

udos86 avatar Jun 26 '21 17:06 udos86

@udos86 should it be case MY_DYNAMIC_FORM_CONTROL_TYPE instead of case MyDynamicFormControlModel? So it would match the patterns used in the lib.

Also what if there will be added something like:

    {
      provide: DYNAMIC_FORM_MODEL_MAP_FN,
      useValue: (type: string, model: any, layout: any): DynamicFormControlModel | null => {
        switch (type) {
          case MY_DYNAMIC_FORM_CONTROL_TYPE:
            return new MyDynamicFormControlModel(model, layout);
        }
      }
    }

And then in the switch of fromJSON:

....
default:
  {
    if (this.DYNAMIC_FORM_MODEL_MAP_FN !== undefined) {
      const model2 = this.DYNAMIC_FORM_MODEL_MAP_FN(model.type, model, layout)
      if (model !== null) {
        formModel.push(model2);
      } else {
        throw new Error(`custom form control model is not resolved by type "${model.type}"`);
      }
    } else {
      throw new Error(`unknown form control model defined on JSON with id "${model.id}"`);
    }
  }
break;

knight-bubble avatar Jun 28 '21 09:06 knight-bubble

@knight-bubble Yes, sorry my bad!

udos86 avatar Jul 01 '21 20:07 udos86

+1, I'm also interested in adding additional form field types, like for example one that allows you to take a picture/video or upload a file or a checkbox group that would work just like the radio group, but most of all I would like to add a form field type for a signature input where it's possible to draw a signature. Is there no example set up or a tutorial article as a reference for how to go about adding completely new models?

FI55 avatar Aug 30 '22 14:08 FI55