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

Question

Question

Is it possible to store table cells in variables in the modern form designer JavaScript?

asked on May 5 Show version history

The following code works, but I'm trying to figure out how to store the table cells in variables. So, if the fieldID for the table column changes, I would just have to change the fieldId on one line of code.

Code that works without error:

const formFields = {
  vacColFieldId: { fieldId: 102 },
  vacAccum: {fieldId: 102, index: 0},
  vacEarned: {fieldId: 102, index: 1},
  vacTaken: {fieldId: 102, index: 2},
  vacBalance: {fieldId: 102, index: 3}
};

const updateBalance = async (formFields) => {
  
  let VacationAccumulated = LFForm.getFieldValues({fieldId: 102, index: 0});
  let VacationEarned = LFForm.getFieldValues({fieldId: 102, index: 1});
  let VacationTaken = LFForm.getFieldValues({fieldId: 102, index: 2});
  let VacationBalance = LFForm.getFieldValues({fieldId: 102, index: 3});

  let result = (VacationAccumulated + VacationEarned) - VacationTaken;
 
  if (VacationBalance !== result) {
      await LFForm.setFieldValues({fieldId: 102, index: 3}, result);
  }
}

LFForm.onFieldBlur(function() {updateBalance();}, formFields.vacColFieldId);

Code that doesn't work:

I've tried to change the "if (VacationBalance !== result)" section to the following, but it breaks the functionality:

if (VacationBalance !== result) {
        await LFForm.setFieldValues(VacationBalance, result);
}

The error message in the console reads as follows:

Uncaught (in promise) Error: Unable to find field. Please check your ID.

When I try to print the VacationBalance variable to the console, it doesn't return anything:

console.log("VacationBalance = ", VacationBalance);

Result shown in the console --> VacationBalance =

Also, I need to do the same calculation in the 2 columns adjacent (fieldIds 103 and 104) to the Vacation column (fieldId 102). So, it would be nice to pass in the fieldId to the updateBalance() function.

Any suggestions for improvements in this code are much appreciated!

0 0

Answers

APPROVED ANSWER
replied two days ago Show version history

Take formFields out of your async function arguments; that is creating a new formFields argument for the function, which supersedes the variable you defined at the root level.

This code works for me (with different variable ids for my test form)

const formFields = {
  vacBalance: { fieldId: 22, index: 0 }
};

const updateBalance = async () => {
  let v = LFForm.getFieldValues(formFields.vacBalance);
  console.log(v);
};

When you put formFields in the async as an argument, that is not passing the existing variable, it is a separate reference in the scope of the function.

// this causes an error because formFields is a new argument here
const updateBalance = async (formFields) => {
  let v = LFForm.getFieldValues(formFields.vacBalance);
  console.log(v);
};

If you still want a parameter for your updateBalance method, you can name it where you had formFields before, just use a different name so they don't conflict with one another.

For example,

const updateBalance = async (fieldId) => {
  let v = LFForm.getFieldValues(formFields.vacBalance);
  // do something with fieldId
};

LFForm.onFieldBlur(function() {
  // this is where you set the input parameters
  updateBalance(100);
}, formFields.vacColFieldId);

 

3 0
SELECTED ANSWER
replied two days ago

Hi Mandi, can you try this?

const formFields = (fieldId) => ({
  vacAccum: { fieldId, index: 0 },
  vacEarned: { fieldId, index: 1 },
  vacTaken: { fieldId, index: 2 },
  vacBalance: { fieldId, index: 3 }
});

const updateBalance = async (fieldId) => {
  const fields = formFields(fieldId);

  const accumulated = parseFloat(LFForm.getFieldValues(fields.vacAccum)) || 0;
  const earned     = parseFloat(LFForm.getFieldValues(fields.vacEarned)) || 0;
  const taken      = parseFloat(LFForm.getFieldValues(fields.vacTaken)) || 0;
  const balance    = parseFloat(LFForm.getFieldValues(fields.vacBalance)) || 0;

  const result = (accumulated + earned) - taken;

  if (balance !== result) {
    await LFForm.setFieldValues(fields.vacBalance, result);
  }
};

// Attach to blur for one table column (e.g., fieldId: 102)
LFForm.onFieldBlur(() => updateBalance(102), { fieldId: 102 });

// If you want to do the same for others, repeat:
LFForm.onFieldBlur(() => updateBalance(103), { fieldId: 103 });
LFForm.onFieldBlur(() => updateBalance(104), { fieldId: 104 });

 

0 0
replied one day ago

Luis, this works perfectly! Thank you so much! I wish I could mark all of these as answers.

1 0
replied one day ago

Hi, @████████I am pleased to know that I could be useful and have been able to help. Thank you. 

0 0

Replies

replied on May 5

Based on the object storing the id/index objects, shouldn't the code be the following?

(i.e., formFields.vacBalance instead of VacationBalance)

if (VacationBalance !== result) {
        await LFForm.setFieldValues(formFields.vacBalance, result);
}

If I'm understanding correctly, the code that failed would put the value from the vacation balance field in where the id/index parameters are meant to go.

0 0
replied on May 5 Show version history

Yes, that's my intention. smiley

I tried that (using formFields.vacBalance), but got the following error:
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'vacBalance')

To give you an idea of what is expected in the UI, see the "Vacation" column below:

0 0
APPROVED ANSWER
replied two days ago Show version history

Take formFields out of your async function arguments; that is creating a new formFields argument for the function, which supersedes the variable you defined at the root level.

This code works for me (with different variable ids for my test form)

const formFields = {
  vacBalance: { fieldId: 22, index: 0 }
};

const updateBalance = async () => {
  let v = LFForm.getFieldValues(formFields.vacBalance);
  console.log(v);
};

When you put formFields in the async as an argument, that is not passing the existing variable, it is a separate reference in the scope of the function.

// this causes an error because formFields is a new argument here
const updateBalance = async (formFields) => {
  let v = LFForm.getFieldValues(formFields.vacBalance);
  console.log(v);
};

If you still want a parameter for your updateBalance method, you can name it where you had formFields before, just use a different name so they don't conflict with one another.

For example,

const updateBalance = async (fieldId) => {
  let v = LFForm.getFieldValues(formFields.vacBalance);
  // do something with fieldId
};

LFForm.onFieldBlur(function() {
  // this is where you set the input parameters
  updateBalance(100);
}, formFields.vacColFieldId);

 

3 0
replied two days ago

I appreciate the use of the formFields object to consolidate your fields! The typical way you would summate fields in a table is per row where the following code snippet outlines how you would pass the changed field to the helper function so you can take into account the row index within the calculation function

const formFields = {
   amount: { fieldId: 1 },
   quantity: { fieldId: 2 },
};

const calculateIt = (fieldBlurred) => {
  const amount = LFForm.getFieldValues({ 
    fieldId: formFields.amount.fieldId, 
    // notice the use of the passed field index here to control the row being calculated
    index: fieldBlurred.index,
  });
  // Do stuff with amount
};

LFForm.onFieldBlur((field) => calculateIt(field), formFields.quantity);

whereas for your use case you're summing columns so the index is only relevant for the specific fields all together. Because you have static rows and calculate across all rows every time there is a change you don't need to pass the field into your helper function

2 0
replied two days ago

I wish I could mark multiple responses as the answer. These are both great suggestions! Jason's comments totally make sense and it fixes my error. I'm going to try to implement your solution, as it reduces the lines of code. 

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

Sign in to reply to this post.