I have this onChange method with its related function calls below for React-Jsonschema-Form. The problem I am facing is, newFormData when get passed to computeValueByFormula does not pass the async value.
onChange = ({ schema, formData }) => {
const { properties } = schema
this.updateTotalCell(properties)
lookUpValue(properties, formData).then(newFormData => {
const newFormData2 = computeValueByFormula(properties, newFormData)
this.setState({ formData: newFormData2 })
})
}
// recursive function to do math calculation on string formula input
// use case: mathCalculation("1 * 2 + 4 / 2 - 6")
export function mathCalculation (formula) {
const plusOperator = '+'
const minusOperator = '-'
const multiplyOperator = '*'
const divideOperator = '/'
if (formula.indexOf(plusOperator) > 0) {
const operands = formula.split(plusOperator)
let total = 0
operands.forEach(operand => {
total = total + mathCalculation(operand)
})
return total
}
else if (formula.indexOf(minusOperator) > 0) {
const operands = formula.split(minusOperator)
let total = 0
operands.forEach((operand, index) => {
if (index === 0) {
total = mathCalculation(operand)
}
else {
total = total - mathCalculation(operand)
}
})
return total
}
else if (formula.indexOf(multiplyOperator) > 0) {
const operands = formula.split(multiplyOperator)
let total = 1
operands.forEach(operand => {
total = total * mathCalculation(operand)
})
return total
}
else if (formula.indexOf(divideOperator) > 0) {
const operands = formula.split(divideOperator)
let total = 1
operands.forEach((operand, index) => {
if (index === 0) {
total = mathCalculation(operand)
}
else {
total = total / mathCalculation(operand)
}
})
return total
}
return Number(formula)
}
// compute field value based on value of other fields
export function computeValueByFormula (properties, formData) {
let newFormData = {...formData}
Object.keys(properties).forEach(key => {
if (properties[key].formula) {
const formula = properties[key].formula
let operands = formula.replace(/\+|-|\*|\//g, ' ').split(' ')
operands = operands.map(operand => formData[operand])
if (properties[key].type === 'number') {
const operators = formula.replace(/\w/g, '').split('')
const updatedFormula = operands.map(operand => operators.length > 0 ? operand + operators.shift() : operand).join('')
newFormData[key] = mathCalculation(updatedFormula)
}
else if (properties[key].type === 'string'){
newFormData[key] = operands.join(' ')
}
}
else if (properties[key].type === 'array') {
if (formData[key] !== undefined) {
newFormData[key].forEach((item, childKey) => {
newFormData[key][childKey] = computeValueByFormula(properties[key].items.properties, formData[key][childKey])
})
}
}
})
return newFormData
}
// lookup value based on value of other field
export function lookUpValue (properties, formData, parentFieldName, parentFormData) {
let newFormData = {...formData}
Object.keys(properties).forEach(async (key) => {
if (properties[key].lookup) {
const { collection, field, parameterField } = properties[key].lookup
if (parentFormData !== undefined) { // pattern is in array field item
if (parameterField.indexOf(':') > 0) { // parsing array field item
const arrayRef = parameterField.split(':')
const arrayField = arrayRef[0]
const itemField = arrayRef[1]
if (arrayField === parentFieldName) {
const lookupValue = formData[itemField]
newFormData[key] = await axios.get(`${API_URL}/record-lookup?collection_id=${collection}&lookup_field=${itemField}&lookup_value=${lookupValue}&lookup_target_field=${field}`)
.then(res => res.data.data)
}
} else {
const lookupValue = parentFormData[parameterField]
newFormData[key] = await axios.get(`${API_URL}/record-lookup?collection_id=${collection}&lookup_field=${parameterField}&lookup_value=${lookupValue}&lookup_target_field=${field}`)
.then(res => res.data.data)
}
} else {
const lookupValue = formData[parameterField]
newFormData[key] = await axios.get(`${API_URL}/record-lookup?collection_id=${collection}&lookup_field=${parameterField}&lookup_value=${lookupValue}&lookup_target_field=${field}`)
.then(res => res.data.data)
}
}
else if (properties[key].type === 'array') {
if (formData[key] !== undefined) {
newFormData[key].forEach(async (item, childKey) => {
newFormData[key][childKey] = await lookUpValue(properties[key].items.properties, formData[key][childKey], key, formData).then(data => data)
})
}
}
})
return Promise.resolve(newFormData)
}
What I want to accomplish is to look up a value based on user's input on the form. Let's say I have currency table on the database, whenever a user change a dropdown select of currency name, another field which supposed to hold the currency rate will do server call to fetch related currency data from database.
This field will have a lookup field on the schema. The same as field which has math calculation on it, will have formula field on the schema.
Somehow after the server call, it will update the formData on the other places, but formData that's passed to computeValueByFormula is not updated. Even if I pass it directly without the spread operator.
This give me a blank field on the form while on the formData I have the value.
Note: The recursive form of the functions needed to evaluate the array field items.
lookUpValueis not declared as anasyncfunction. Notry..catchblocks or error handlers within.catch()appear at the code at the question.