🌈 Rule component example

☀️ Why do you need a rule component

The underlying JSON parser of the data visualization platform provides support for template strings, such as:

'#{data.count > 10 ? "red" : "yellow"}'
Copy the code

Template strings are not friendly to use in visual scaffolding:

  1. The user needs to learn template string syntax, and it is not convenient to write template strings in the editor
  2. Variable names need to be written manually and are prone to error

🌧 Design Requirements

Rule components should be fully implemented as long as template strings can be implemented.

  1. A single variable result, e.g#{data.count}
  2. A conditional judgment, as'#{data.count > 10 ? "red" : "yellow"}'
  3. Multi-conditional judgments such as#{data.count > 10? "red" : data.price > 100 ? "yellow" : "blue"}
  4. Satisfy multiple conditions at the same time, such as#{data.count > 10 && data.price > 100 ? "red" : "yellow"}

🌟 Design Idea

The overall train of thought

The result obtained by the template string is unique, that is, if the current condition is satisfied, the result will be used. If the condition is not satisfied, the judgment will continue.

Can be designed as an array format:

[{conditions: conditions1, result: 'result1' },
  { conditions: conditions2, result: 'result2' },
  { result: 'result3'}]Copy the code

Each group of elements in the array is an or relationship. After the current condition is met, the group result is used without backward judgment.

If conditions are met by default, no conditions need to be set for some groups.

Thus meet the design requirements 1,2,3.

The conditions thought

To facilitate the construction of data.count > 10, conditions consists of three fields: variable, operator and value.

conditions: { variable: 'data.count'.operator: '= = ='.value: 10 },
Copy the code

In order to meet multiple conditions (design Requirement 4), conditions are also designed as an array format. Each group of elements is and relation, which should be met at the same time.

conditions: [
 { variable: 'data.count'.operator: '= = ='.value: 10 },
  { variable: 'data.price'.operator: '>'.value: 100}].Copy the code

☃️ format parsing

Once the COMPONENT’s Json format is set, it’s time to think about format conversion.

Obtain the result of condition execution with the built-in template string parsing function template:

function transformValue(value) {
  if (typeof value === 'string') {
    return ` '${value}'`;
  }

  return value;
}

function parseCondition(condition, data) {
  const { variable, operator, value } = condition;
  const conditionStr = operator
    ? ` # {${variable} ${operator} ${transformValue(value)}} `
    : ` # {${variable}} `;

  let result;
  try {
    // Pass data to the template string and return the template string execution result
    result = template(conditionStr, data);
  } catch (e) {}

  return result;
}
Copy the code

For the rest, just code as you were designed

 function transform(config, data) {
  let finalResult;
  for (let i = 0; i < config.length; i += 1) {
    const { conditions = [], result } = config[i];
    if(! conditions.length) { finalResult = result;break;
    }
    if (conditions.every((condition) = > parseCondition(condition, data))) {
      finalResult = result;
      break; }}return finalResult;
}
Copy the code

🌈 code implementation ideas

Array configuration capability

The List component is implemented based on rC-field-form, and the left line is added to beautify the style.

cable

Principle: Each group of elements draws two upward and downward lines based on the center, and hides the upward line of the first element and the downward line of the last element.

Code implementation: Github

Result Indicates the result item configuration

In order to facilitate management and code writing, the overall use of JSON configuration. The code in the example uses the following structure:

resultFields: [
  {
    name: 'children'.label: 'text'.wrapperCol: 24.labelCol: 2.field: {
      type: 'autocomplete'.props: {
       allowClear: true,}}}, {name: 'type'.label: 'type'.field: {
      type: 'autocomplete'.props: {
        source: [{text: 'success'.value: 'success' },
          { text: 'danger'.value: 'danger'},].resultType: 'textType',},},}, {name: 'style'.label: 'the style'.field: 'editor',}]Copy the code

The implementation principle can be found in this article: Sula – Plug-in implementation

// The core code is as follows
import { FunctionComponent, ComponentClass } from 'react';

class PluginStore {
  plugins = {};

  registerField = (key, field) = > {
    if (this.plugins[key]) return;
    this.plugins[key] = field;
  };

  getPlugins = () = > {
    return this.plugins;
  };
}

const pluginStore = new PluginStore();

export default pluginStore;
Copy the code

👀 end

Insert an AD:

Front-end configuration framework – Sula