Skip to content

Value Format Conversion

Bind custom converters to form components to handle special data formats or conversion logic. Converters enable bidirectional data conversion: converting backend data to form display format (forward), and converting form data to backend required format (reverse).

Converter Overview

Converters provide two conversion methods:

  • toFormValue: Forward conversion, converts backend data to values displayed by form components
  • toValue: Reverse conversion, converts form component values to data format submitted to backend

Usage Scenarios

Converters are suitable for the following scenarios:

  • Data format conversion (e.g., string and array interconversion)
  • Data cleaning (e.g., removing spaces, formatting)
  • Data type conversion (e.g., string and number interconversion)
  • Complex data structure processing

Quick Start

1. Mount Converter

Globally mount the converter in main.js

ts
import {formCreate} from '/path/to/fcDesignerPro/dist/index.es.js'

formCreate.parser({
    name: 'input',
    merge: true,
    toFormValue(val) {
        return (val || '').trim()
    },
    toValue(val) {
        return (val || '').trim()
    },
})

2. Use Converter

Converters will automatically trigger in the following scenarios:

  • Form echo: Calls toFormValue to convert backend data to form display values
  • Form submission: Calls toValue to convert form values to submission data
vue
<template>
    <form-create v-model="formData" :rule="rule" v-model:api="fApi" @submit="handleSubmit"></form-create>
</template>
<script setup>
import {ref} from 'vue';
import {formCreate} from '/path/to/fcDesignerPro/dist/index.es.js'

const formData = ref({});
const fApi = ref(null);
const rule = ref([
    {
        type: 'input',
        field: 'username',
        title: 'Username',
    }
]);

function handleSubmit(formData) {
    // At this point formData.username has been processed through toValue, removing leading and trailing spaces
    console.log('Submission data:', formData);
}
</script>

Complete Examples

Example 1: Remove Leading and Trailing Spaces from Input

Automatically remove leading and trailing spaces from input component values to ensure clean data.

js
import {formCreate} from '/path/to/fcDesignerPro/dist/index.es.js'

formCreate.parser({
    name: 'input',
    merge: true,
    // Forward conversion: convert from backend data to form display value
    toFormValue(val) {
        // If value is null or undefined, return empty string
        if (val == null) {
            return '';
        }
        // Remove leading and trailing spaces
        return String(val).trim();
    },
    // Reverse conversion: convert from form value to submission data
    toValue(val) {
        // Also remove leading and trailing spaces on submission
        if (val == null) {
            return '';
        }
        return String(val).trim();
    },
});

Usage Scenario:

vue
<template>
    <form-create v-model="formData" :rule="rule" v-model:api="fApi"></form-create>
</template>
<script setup>
import {ref, onMounted} from 'vue';

const formData = ref({});
const fApi = ref(null);
const rule = ref([
    {
        type: 'input',
        field: 'username',
        title: 'Username',
    }
]);

// Simulate loading data from backend (contains leading and trailing spaces)
formData.value = {
    username: '  admin  '  // Contains leading and trailing spaces
};
// When form echoes, toFormValue will automatically remove spaces, displaying as 'admin'

function handleSubmit(data) {
    // User inputs '  test  ', toValue will automatically convert to 'test' on submission
    console.log(data.username); // Output: 'test'
}
</script>

Example 2: Convert Checkbox Values to Comma-Separated String

Convert checkbox component array values to comma-separated strings for easier backend storage and processing:

js
import {formCreate} from '/path/to/fcDesignerPro/dist/index.es.js'

formCreate.parser({
    name: 'checkbox',
    merge: true,
    // Forward conversion: convert from backend string to form array
    toFormValue(val) {
        if (!val) {
            return [];
        }
        // If string, split by comma and convert to array
        if (typeof val === 'string') {
            return val.split(',').map(item => item.trim()).filter(item => item);
        }
        // If already array, return directly
        if (Array.isArray(val)) {
            return val;
        }
        return [];
    },
    // Reverse conversion: convert from form array to submission string
    toValue(val) {
        if (!val || !Array.isArray(val)) {
            return '';
        }
        // Convert array to comma-separated string
        return val.filter(item => item).join(',');
    },
});

Usage Scenario:

vue
<template>
    <form-create v-model="formData" :rule="rule" v-model:api="fApi" @submit="handleSubmit"></form-create>
</template>
<script setup>
import {ref, onMounted} from 'vue';

const formData = ref({});
const fApi = ref(null);
const rule = ref([
    {
        type: 'checkbox',
        field: 'hobbies',
        title: '兴趣爱好',
        options: [
            {label: '阅读', value: 'reading'},
            {label: '运动', value: 'sports'},
            {label: '音乐', value: 'music'},
            {label: '旅行', value: 'travel'},
        ]
    }
]);

// Simulate loading data from backend (string format)
formData.value = {
    hobbies: 'reading,sports,music'  // Backend stores as string
};
// When form echoes, toFormValue automatically converts to array ['reading', 'sports', 'music']

function handleSubmit(data) {
    // User selected ['reading', 'travel'], toValue automatically converts to 'reading,travel' on submission
    console.log(data.hobbies); // Output: 'reading,travel'
    // Can directly submit to backend without additional processing
}
</script>

Example 3: Number Formatting

Convert string numbers to number type, or maintain number format. Suitable for scenarios where input box string values need to be converted to number type for backend submission:

js
import {formCreate} from '/path/to/fcDesignerPro/dist/index.es.js'

formCreate.parser({
    name: 'input',
    merge: true,
    // Forward conversion: ensure display as string (form components require)
    toFormValue(val) {
        if (val == null) {
            return '';
        }
        // If number, convert to string for display
        return String(val);
    },
    // Reverse conversion: convert to number type for submission
    toValue(val) {
        if (val === '' || val == null) {
            return null;
        }
        // Convert to number
        const num = Number(val);
        // If conversion fails, return original value
        return isNaN(num) ? val : num;
    },
});

Usage Scenario:

vue
<template>
    <form-create v-model="formData" :rule="rule" v-model:api="fApi" @submit="handleSubmit"></form-create>
</template>
<script setup>
import {ref} from 'vue';

const formData = ref({});
const fApi = ref(null);
const rule = ref([
    {
        type: 'input',
        field: 'price',
        title: '商品价格',
        props: {
            type: 'number',
            placeholder: '请输入价格'
        }
    },
    {
        type: 'input',
        field: 'quantity',
        title: '库存数量',
        props: {
            type: 'number',
            placeholder: '请输入数量'
        }
    }
]);

// Simulate loading data from backend (number type)
formData.value = {
    price: 99.99,      // Backend returns number type
    quantity: 100      // Backend returns number type
};
// When form echoes, toFormValue automatically converts to strings '99.99' and '100' for display

function handleSubmit(data) {
    // User input '199.50' and '50', toValue automatically converts to number type on submission
    console.log(data.price);      // Output: 199.5 (number type)
    console.log(data.quantity);   // Output: 50 (number type)
    console.log(typeof data.price); // Output: 'number'

    // Can directly perform math operations without manual conversion
    const total = data.price * data.quantity;
    console.log('Total:', total); // Output: 9975
}
</script>

Example 4: Date Formatting

Handle date format conversion, converting timestamps or date strings to a unified display format. Suitable for scenarios where backend stores timestamps but form components require date objects:

js
import {formCreate} from '/path/to/fcDesignerPro/dist/index.es.js'

formCreate.parser({
    name: 'datePicker',
    merge: true,
    // Forward conversion: convert backend date format to component-required format
    toFormValue(val) {
        if (!val) {
            return null;
        }
        // If timestamp, convert to date object
        if (typeof val === 'number') {
            return new Date(val);
        }
        // If string, convert to date object
        if (typeof val === 'string') {
            return new Date(val);
        }
        return val;
    },
    // Reverse conversion: convert date object to timestamp for submission
    toValue(val) {
        if (!val) {
            return null;
        }
        // If date object, convert to timestamp
        if (val instanceof Date) {
            return val.getTime();
        }
        return val;
    },
});

Usage Scenario:

vue
<template>
    <form-create v-model="formData" :rule="rule" v-model:api="fApi" @submit="handleSubmit"></form-create>
</template>
<script setup>
import {ref} from 'vue';

const formData = ref({});
const fApi = ref(null);
const rule = ref([
    {
        type: 'datePicker',
        field: 'birthday',
        title: '出生日期',
        props: {
            type: 'date',
            placeholder: '请选择日期'
        }
    },
    {
        type: 'datePicker',
        field: 'startTime',
        title: '开始时间',
        props: {
            type: 'datetime',
            placeholder: '请选择日期时间'
        }
    }
]);

// Simulate loading data from backend (timestamp format)
formData.value = {
    birthday: 631123200000,  // Backend returns timestamp: 1990-01-01
    startTime: 1609459200000 // Backend returns timestamp: 2021-01-01 00:00:00
};
// When form echoes, toFormValue automatically converts to date objects for display

function handleSubmit(data) {
    // User selected dates, toValue automatically converts to timestamps on submission
    console.log(data.birthday);   // Output: 631123200000 (timestamp)
    console.log(data.startTime);  // Output: 1609459200000 (timestamp)
    console.log(typeof data.birthday); // Output: 'number'

    // Can directly submit to backend without manual conversion
    // Backend APIs typically receive timestamp format for easier storage and calculation
}
</script>

Example 5: Using Context Information

Converter functions can receive context parameters for more complex conversion logic. Suitable for scenarios where conversion method needs to be dynamically determined based on component configuration:

js
import {formCreate} from '/path/to/fcDesignerPro/dist/index.es.js'

formCreate.parser({
    name: 'select',
    merge: true,
    // Forward conversion: use context information
    toFormValue(val, ctx) {
        // ctx contains current rule, form data, etc.
        const {prop} = ctx;

        // Determine conversion method based on rule configuration
        if (prop.props?.multiple) {
            // Multiple selection mode: string to array
            if (typeof val === 'string') {
                return val.split(',').filter(item => item);
            }
            return Array.isArray(val) ? val : [];
        } else {
            // Single selection mode: return directly
            return val || '';
        }
    },
    // Reverse conversion: use context information
    toValue(val, ctx) {
        const {prop} = ctx;

        if (prop.props?.multiple) {
            // Multiple selection mode: array to string
            return Array.isArray(val) ? val.join(',') : '';
        } else {
            // Single selection mode: return directly
            return val || '';
        }
    },
});

Usage Scenario:

vue
<template>
    <form-create v-model="formData" :rule="rule" v-model:api="fApi" @submit="handleSubmit"></form-create>
</template>
<script setup>
import {ref} from 'vue';

const formData = ref({});
const fApi = ref(null);
const rule = ref([
    {
        type: 'select',
        field: 'category',
        title: '商品分类',
        props: {
            multiple: false,  // 单选模式
            placeholder: '请选择分类'
        },
        options: [
            {label: '电子产品', value: 'electronics'},
            {label: '服装', value: 'clothing'},
            {label: '食品', value: 'food'}
        ]
    },
    {
        type: 'select',
        field: 'tags',
        title: '商品标签',
        props: {
            multiple: true,  // 多选模式
            placeholder: '请选择标签'
        },
        options: [
            {label: '热销', value: 'hot'},
            {label: '新品', value: 'new'},
            {label: '推荐', value: 'recommend'}
        ]
    }
]);

// Simulate loading data from backend
formData.value = {
    category: 'electronics',        // Single selection: backend returns string
    tags: 'hot,new,recommend'       // Multiple selection: backend returns comma-separated string
};
// When form echoes:
// - category single selection: directly displays 'electronics'
// - tags multiple selection: toFormValue automatically converts to array ['hot', 'new', 'recommend']

function handleSubmit(data) {
    // After user operations, on submission:
    // - category single selection: directly returns string 'clothing'
    // - tags multiple selection: toValue automatically converts to string 'hot,new'
    console.log(data.category);  // Output: 'clothing' (string)
    console.log(data.tags);       // Output: 'hot,new' (string, multiple selection auto-converted)

    // Same converter automatically adapts different conversion logic based on component configuration
    // No need to register different converters for single and multiple selection
}
</script>

Converter Method Description

toFormValue

Function: Convert backend data to form component display value

Call Timing:

  • When form initializes
  • When calling fApi.reload() method
  • When setting form data

Parameters:

  • value: Backend data value
  • ctx: Context object, containing the following properties:
    • prop: Current component's rule configuration
    • $api: Form API instance

Return Value: Converted form display value

toValue

Function: Convert form component value to data format submitted to backend

Call Timing:

  • When form submits
  • When calling fApi.submit() method
  • When getting form data

Parameters:

  • value: Form component's current value
  • ctx: Context object, containing the following properties:
    • prop: Current component's rule configuration
    • $api: Form API instance

Return Value: Converted submission data

Notes

  1. Converter Scope: Converters are bound by component name (name). Only one converter can be registered per component name; later registrations override earlier ones.

  2. Performance Considerations: Converters are called on every data conversion. Avoid time-consuming operations in converters.

  3. Data Consistency: Ensure toFormValue and toValue are inverse operations, i.e., toValue(toFormValue(val)) should equal the original value (or equivalent value).

  4. Null Value Handling: Properly handle boundary cases like null, undefined, and empty strings in converters.

  5. Type Safety: Pay attention to data type conversions to avoid errors caused by type mismatches.

Data Structure

ts
type Parser = (name: string, parser: ParserConfig) => void;

interface ParserConfig {
    // Whether to merge built-in parsing rules, keep true for built-in components
    merge?: true;
    // Forward conversion: convert backend data to form display value
    toFormValue?: (value: any, ctx: ParserContext) => any;
    // Reverse conversion: convert form value to submission data
    toValue?: (value: any, ctx: ParserContext) => any;
}

interface ParserContext {
    // Current component's rule configuration
    rule: Rule;
    // Form API instance
    $api: Api;
}

merge Parameter Description

  • When adding parsers for built-in components (such as input, select, etc.), configure merge: true to avoid overriding system built-in parsing logic.
  • Custom extended components can omit this parameter if there is no default parsing logic.

By customizing converters, you can flexibly handle various data format conversion requirements, achieving seamless integration between form data and backend data, improving development efficiency and user experience.