Why dynamic forms?

The project requires list fields to be dynamic, creating an indirect requirement for the form to be dynamic. (When a field appears in both the list and the edit form, the list and form should hide the changed fields if the field is configured not to be displayed.)

What are the problems with dynamic forms?

1. The layout is bulky and not flexible enough

How fields are arranged

There are two general scenarios for inter-field layouts

Grid layout

The advantage of a grid layout is that it is flexible, but the disadvantage is that it is difficult to wrap lines. Generally, a grid divides the available space horizontally into 24 equally wide grids when configured as follows:

[{
    span:8
  },{
    span:16
}]
Copy the code

You get the following result:



When the screen shrinks or the browser window shrinks, we expect the following results



Yet the result could be this:



Or this:

If we wanted to insert a pure layout UI element C between them, we would be in trouble:

The width of A,B is reduced to create A new area, as follows:

[{
    span:7
  },{
    span:2
  },{
    span:15
}]
Copy the code



Or do you leave the grid layout unchanged, but instead take A block from A or B and give it to C?

Here is a scenario where an area is cut out of B and given to C:

Analysis of the

The first way

  • Advantages: No component adaptation is required, just change the lower grid layout configuration
  • Disadvantages: Affects the available space of other components

The second way

  • Advantages: does not affect the grid layout configuration, B components can achieve source level, on the C component to fill in the scene to do adaptation, optimization
  • Disadvantages: need to modify the source code of B component, add a space (slot) inside it can fill other components, relatively bulky

These two ways, on the layout, there is no absolute good or bad, according to the scene flexibly choose the best

Fluid layout

Streaming layout, divided into row and column direction streaming layout, the general use of row streaming layout

When the horizontal space is insufficient, the line is wrapped automatically. Figure C falls to the second line because of insufficient space:



A combination of streaming and raster layouts may be the ideal solution

Layout within fields

The layout within a field refers to the layout between the matching Chinese field name of the input item, the possible interpretation of the Chinese field name, the unit, the verification hint and the input item itself, for example:

In general, for the layout of fields, it is common to set the arrangement of Chinese fields and input interaction areas (horizontal and vertical).

However, there are still many scenarios, which need to configure the visibility of Chinese field names, Chinese definitions, units, verification prompts, and display mode of verification results (inline text, toast, dialog, etc., as shown in the figure).

To achieve this, we can add a lot of configuration items, and then a lot of documentation



This is cumbersome, but the most flexible way to support a limited number of scenarios!

But what if we have a lot of special scenarios? Such as:





We’ll have to change the code to add configuration and interface logic, and the form-Item component will get bigger and bigger, more complex, and out of control:



Thinking, if we will make the above layout into a theme, when the time comes, configure a theme, whether it will simplify the tedious configuration items? Here are two different themes:







In this way, a simple configuration of topics can simplify a lot of tedious processes.

But this introduces a new problem:Different topics have different configuration itemsThis leads to more complex visual layout system design

In practice, it is often recommended to use topic + local configuration items to complete the whole solution. This actually changes the single-layer configuration to two-layer configuration, which simplifies the mental burden to some extent and greatly reduces the complexity of components within a single topic

Multiple input result fusion

Field fusion is required when the first and last names are separate inputs, but the result requires only name as a field

How do I insert a non-field interface element?

Outside the form of the interface layout, we can use code to achieve

Sometimes, however, we want to add field independent interface elements such as illustrations, text, lines, and even buttons, maps, and custom components to the form to make it look like a UI design



So, how do we tease out our configuration items to describe a non-field interface element?

Multirecord field

Part of a form, or field, that results in an array, such as:



The field values for the final form submission are:

{... statOrder:[{ drugName:'1', count:3, dose:302 },{ drugName:'2', count:4, dose:50 }] ... }Copy the code

The complexity of this type of field is that we need to consider how to add, delete and change records, and how to flexibly layout

How to implement field validation elegantly

Form linkage

Select field: Select one or more input types from a set of options, such as drop-down boxes, check boxes, checkboxes, etc

  • Select field options for field linkage
    • Availability linkage
    • Visibility linkage
    • Style linkage
  • Linkage of fields with selective field options
    • Availability linkage
    • Visibility linkage
    • Style linkage
  • Linkage of options between selectable fields
    • Availability linkage
    • Visibility linkage
    • Style linkage

Style linkage

slightly

Value linkage

When a variable field value is automatically calculated according to an algorithm based on one or more variable fields, it is called value linkage. In this case, the variable fields are generally unavailable

The following shows a scenario where the length of stay is calculated automatically







How do you implement this feature?

String-based function calls

The basic string-based function calls I know of in the market today are characterized by presetting common formulas and using the eval function to execute built-in functions in a blessing mode:

function MAX(a,b){... } function DayCount(start,end){... }...Copy the code
{
	formula:'MAX(_$field1$_,_$field2$_)'
},
...
{
	formula:'DayCount(_$field1$_-_$field2$_)'
}
Copy the code
//field1, field2... // step 2 get field1, field2 from model (form value) // 2,3... // step-3 replaces the field in options.formula with the corresponding value... // eval(' MAX(2,3) '); // eval(' MAX(2,3) ');Copy the code

The above methods can cover most of the actual scenarios, but they are still not flexible enough. For automatic calculation in special scenarios, it is particularly difficult



The above scenario, using string-based formula calls, is far more complex than writing direct code and is simply impossible to maintain

At this point, you can consider configuring the function directly

Display the function configuration

{formula:function(model){//... return ... }}Copy the code

Isn’t it more intuitive and flexible? Unfortunately, this approach has a fatal drawback: JSON does not support function serialization, which means that saving the configuration to the database and retrieving it will result in the failure of all formulas! Of course, there is a way to do this, which is to string the function

Option = {formula: 'function(model){ return ... } `}Copy the code

then

Eval (' option.formula=${option.formula} ') [field] = options.formula(model) [field] = options.formula(model)Copy the code

In order to have a good experience in the development phase, formula can be configured as a function during the development phase. When uploading the database, a conversion tool is provided to convert the function into a string. The component automatically identifies and converts the string formula into a function formula

// Transform tool method core logic: option.formula = '${option.formula}Copy the code
Formula if(typeof option.formula= == 'string'){eval(' option.formula=${option.formula} ')} option.formula(model) ...Copy the code

Field filtering

When there is linkage between two fields, and the master variable field is only used to control the linkage of the slave variable field, the master variable field should not appear in the submitted data of the form

Form backfill problem

The backfill problem should be considered from two aspects:

  • The form change
  • The filtered field is backfilled

The form change

Because the form is based on configuration items, and the configuration is probably generated by our internal configuration or user customization and stored in the database, it is inevitable that the form will change during the process of iteration and user use. At this point, we should consider the problem of backfilling old data. Here are two ideas:

  • Provide form version mechanism, old data use the corresponding old version of the form
  • If the form expectations are manageable, the new table can be unidirectionally compatible with the old form values

The filtered field is backfilled

As mentioned earlier, some of the main variable fields will have filtered values, and when backfilled, their corresponding values will not be correctly backfilled, which can lead to fatal consequences: some variable fields may not be displayed

Do YOU want to leave the tripartite UI?

, currently on the market basically is in integrating and UI, some powerful open source project, but also for multiple popular UI source adapter, but it will cost a lot of human resources, and, due to the underlying architecture, basic it is difficult to support mobile h5 end for commercial projects, basic it is the use of the three sides of the UI, If the dynamic form does not find a suitable VERSION of the UI, it cannot be used, or a dynamic form-bound UI must be introduced

The remote options

Some of the options for select fields come from the database and you have to think about how do you connect with tokens or cookies more easily

Location: scheme VS rendering kernel

When designing dynamic forms, you need to prioritize whether a dynamic forms solution is out of the box or just a dynamic forms rendering kernel. The difference is,

  • Kernel: only define rules, and render rules, do not do too many built-in components, provide extension API, developers need to configure their own component pool in the project
  • Solution: out of the box, built-in rich components, tools, developers out of the box, convenient, but bloated, not flexible

Appendix: