How do I implement a "strong" type system for different types of inputs for a form in Angular?

Discussão em 'Angular' iniciado por felixhir, Outubro 29, 2024.

  1. felixhir

    felixhir Guest


    This question is not about getting it to run, it's about how to solve this problem in a "clean" (readable, maintainable) way.
    ​
    Context


    I'm currently working on a drag-and-drop based editor with which one can create a form in Angular 18. The form is supposed to support different input elements (e.g. common things like <input> or <select> but also advanced types like ngx-datatable).

    Behind the scenes the editor will generate a JSON-file that contains the configuration of the form, so all input elements will have a JSON-representation. This configuration is partially the same for all elements (e.g. label or required as well as type) but some also have type specifics to them (e.g. a select requires some options to be passed along). All the different options should be configurable in the editor.

    I want some sort of component or container that renders the configuration options of a specific form field that is selected elsewhere. The selection will be available in a signal, no problems there. The problem arises when trying to display the configuration interface depending on the type of the form field.

    Approach


    The specific configuration of any element depends on its type, a property in the JSON of type string. In my code this property is a union type of all the different inputs I want to support (think 'input' | 'textarea' | 'checkbox' | 'select', ...). Now in order to show some specific options I have a component called form-field-details that looks something like this:

    @switch (formField.type) {
    @case ('input') {
    <ng-container *ngTemplateOutlet="text" />
    }
    @case ('textarea') {
    <ng-container *ngTemplateOutlet="text" />
    }
    @case ('checkbox') {
    <ng-container *ngTemplateOutlet="checkbox" />
    }
    @case ('select') {
    <ng-container *ngTemplateOutlet="select" />
    }
    }

    <!-- Some templates with inputs and two-way-bindings to parts of the formField -->

    Problem


    While this works, I feel like it is the wrong approach. I am now stuck with a component that has to know about all the different types of inputs and how it should bind their data. It seems like a violation of the information expert principle. Additionally this component is getting larger and more complex every time I add a new type of input.

    Another issue arises when I want to include sub-sets of types (e.g. some fields to input data, some to display data). Now I always have to check if the type of a form-field is included in some form of string array, making my problems worse.

    I would assume that another solution would be to create a component for each form-field that is then slotted by the form-field-details component. However, this would still require a container with some sort of switch and a type containing all possible fields. Is there a way to have some classes / components that can be used interchangably that define the way they are rendered by themselves?

    Continue reading...

Compartilhe esta Página