You are viewing limited content. For full access, please sign in.

Question

Question

LFForm Object setFieldValue support for collections and tables.

asked on June 13 Show version history

Currently the setFieldValue function in the LFForm object does not support collections and/or tables - is there currently a workaround for this?

1 0

Answer

SELECTED ANSWER
replied on June 13 Show version history

Actually, why not both. The following code supports setting field values with both options test it out and let me know how it goes. It also assumes you are using well formed values and does not attempt to convert values for checkboxes/dates/etc.

The options object parameter of setTableFieldValues takes two parameters:

  • replaceMode - either "replace" the entire table or "append" to existing values
  • valueOrder - either an array of 'row' array values, or an array of 'column' array values

the default is { replaceMode: 'replace', valueOrder: 'row' }

 

const findField = (field) => {
  if (field.fieldId) {
    return LFForm.findFieldsByFieldId(field.fieldId);
  }
  if (field.variableId) {
    return LFForm.findFieldsByVariableId(field.variableId);
  }
  if (field.variableName) {
    return LFForm.findFieldsByVariableName(field.variableName);
  }
  throw new Error('Field must have a fieldId, variableId, or variableName');
};
const findFieldByIdParam = (fieldId) => {
  if (fieldId === undefined || fieldId === null) {
    return [];
  }
  if (Array.isArray(fieldId)) {
    return fieldId.flatMap(findField);
  }
  return findField(fieldId);
};

/**
 * @param tableFieldId table field to set values on
 * @param values values to set on the table, order of values dictated by options.valueOrder
 * @param {{ replaceMode: 'replace' | 'append', valueOrder: 'row' | 'column'}} options replaceMode to `replace` or `append` values, valueOrder to set values by `row` or `column`
 * @returns a promise showing the result of the setFieldValues operation
 * @example
 * 
 * ```javascript
 * // replaceMode: 'replace', valueOrder: 'row'
 * await setFieldValues(
 *  { fieldId: 6 },
 *  [
 *     [row1Column1Value, row1column2Value]
 *     [row2Column1Value, row2column2value]
 *  ],
 *  { replaceMode: 'replace', valueOrder: 'row' });
 * 
 * // replaceMode: 'replace', valueOrder: 'column'
 * await setFieldValues(
 *  { fieldId: 6 },
 *  [
 *    [row1column1Value, row2column1Value]
 *    [row1column2Value, row2column2Value]
 *  ],
 *  { replaceMode: 'replace', valueOrder: 'column' });
 * ```
 */
const setFieldValues = async (tableFieldId, values, options) => {
  const { replaceMode = 'replace', valueOrder = 'row' } = options;
  const tableField = findFieldByIdParam(tableFieldId)[0];
  const currentTableFieldValues = LFForm.getFieldValues(tableField);
  const curRowCount = currentTableFieldValues.length;
  // handle row counts for the table
  if (replaceMode === 'replace') {
    if (curRowCount < values.length) {
      await LFForm.addRow(tableFieldId, values.length - curRowCount);
    } else if (curRowCount > values.length) {
      await LFForm.deleteRow(
        tableFieldId,
        ...Array.from(Array(curRowCount - values.length)).map(
          (_, i) => curRowCount - i - 1
        )
      );
    }
  } else if (replaceMode === 'append') {
    await LFForm.addRow(tableFieldId, values.length);
  }
  // setup the values for the table
  const colNumberToFieldId = {};
  const tableTemplate = Object.values(tableField.repeatableTemplate).reduce(
    (acc, field, i) => {
      colNumberToFieldId[i] = field.fieldId;
      acc[field.fieldId] = [];
      return acc;
    },
    {}
  );
  if (replaceMode === 'append') {
    for (const fieldId of Object.keys(tableTemplate)) {
      tableTemplate[fieldId].push(
        ...LFForm.getFieldValues({ fieldId: Number(fieldId) })
      );
    }
  }
  if (valueOrder === 'row') {
    for (const row of values) {
      for (let col = 0; col < row.length; col++) {
        tableTemplate[colNumberToFieldId[col]].push(row[col]);
      }
    }
  } else if (valueOrder === 'column') {
    for (let col = 0; col < values.length; col++) {
      for (const row of values[col]) {
        tableTemplate[colNumberToFieldId[col]].push(row);
      }
    }
  }
  return Promise.allSettled(
    Object.entries(tableTemplate).map(([fieldId, values]) => {
      return LFForm.setFieldValues({ fieldId: Number(fieldId) }, values);
    })
  );
};

 

0 0

Replies

replied on June 13 Show version history

What is the expected input for the new values? For example doing getFieldValues on the table returns an array of objects where each object is the columns of that particular row.
Would something like this work?

[
  [row1Column1Value, row1column2Value]
  [row2Column1Value, row2column2value]
] 

Or would it be preferred to use:
 

[
  [row1column1Value, row2column1Value]
  [row1column2Value, row2column2Value]
]

 

 

0 0
replied on June 14

Personally I prefer the first option over the second; if I'm looking at it, it visually makes more sense. But that's just me.

0 0
replied on June 14

I think the first option makes sense when you are getting your data externally, the second option makes more sense if you are copying data from an existing form table since you retrieve by column. Either way, wrote it to support both

1 0
You are not allowed to follow up in this post.

Sign in to reply to this post.