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

Question

Question

I have an upload field in a table. Is there a way to require that all filenames be unique?

asked on October 14

I have an upload field in a table. Is there a way to require that all filenames be unique?

Thanks in advance!

0 0

Answer

APPROVED ANSWER SELECTED ANSWER
replied on October 15

The file upload field returns an object from getFieldValues. The object contains a list of all of the files that were uploaded or an empty array if a file was removed from the field.

 

I threw together a quick example of how this would work for both having a duplicate check within each row of the table and a multiline field outside of the table. I commented all of the lines of code so you know what is going on. NOTE: this code does not handle a user removing a row from the table, but it does handle a user removing a file from the upload field.

I encourage you to review the code and make sure you understand what it is doing before implementing it in any production code, but I am happy to explain anything you need!

 

const formFields = {
  multiline: { fieldId: 70 },
  uploadColumn: { fieldId: 69 },
  isDuplicateColumn: { fieldId: 46 },
}

LFForm.onFieldChange(async (ev) => {
  // get fieldId and row number from the event that fired
  const { fieldId, index } = ev.options[0];
  if (fieldId === undefined) return;
  // create a formFieldId object to get the value of the field
  const formFieldId = { fieldId };
  // When field is in a table/collection index = row number, so lets only focus on that row
  if (index !== undefined && index !== -1) formFieldId.index = index;
  // get the value of the field that changed
  /**
   * @type {Array<{ name: string, size: string }>}
   */
  const changedValue = LFForm.getFieldValues(formFieldId);
  console.log('Field changed:', formFieldId, changedValue);

  /**
   * @type {{ name: string, size: string }[][]}
   */
  const allUploadFieldValues = LFForm.getFieldValues(formFields.uploadColumn);

  // reset current field duplicate status
  await LFForm.setFieldValues(formFields.isDuplicateColumn, '', { index });
  const allFileNames = new Set();
  const dupes = new Set();
  for (let i = 0; i < allUploadFieldValues.length; i++) {
    const fieldValue = allUploadFieldValues[i];
    if (index !== undefined && index !== -1 && i === index) continue; // skip current row
    // Only one file allowed per upload field so grab first from the array
    const file = fieldValue[0];
    if (!file) continue; // skip empty rows
    // create a unique key for each file based on name and size
    const fileKey = `${file.name}-${file.size}`;
    // check if the file key already exists in the set
    if (allFileNames.has(fileKey)) {
      dupes.add(file.name);
    } else {
      allFileNames.add(fileKey);
    }

    const isDuplicate = changedValue[0] && file.name === changedValue[0].name && file.size === changedValue[0].size;
    if (isDuplicate) {
      dupes.add(file.name);
      const isDuplicateColumnFieldId = formFields.isDuplicateColumn.fieldId;
      try {

        // set the duplicate status for the current row
        await LFForm.setFieldValues(formFields.isDuplicateColumn, 'duplicate', { fieldId: isDuplicateColumnFieldId, index: i });
        // if the current row is a duplicate, set the duplicate status for the other rows that have the same file
        await LFForm.setFieldValues(formFields.isDuplicateColumn, 'duplicate', { fieldId: isDuplicateColumnFieldId, index });
      } catch (error) {
        // Remove this code if you don't have per row checking
      }
    }
  }
  const finalDupes = Array.from(dupes);
  console.log('mf dupes', finalDupes);
  await LFForm.setFieldValues(formFields.multiline, finalDupes.join(', '));

  // get list
}, formFields.uploadColumn);

 

1 0

Replies

replied on October 14

Why do you want them to be unique in Forms?

0 0
replied on October 14

Thanks for your response!

There should be exactly one receipt per transaction number and this would validate that.

 

0 0
replied on October 14

Can't you change the setting on the upload field to only allow 1 file? I feel like I'm missing something.

0 0
replied on October 14

Each upload field allows only one file. However, there are multiple rows in the table and I want to ensure that the end users don't drag the same file into more than one row.

It also causes problems with the workflow that processes the stored files. If the filename changes when stored (ex. adding  "(2)"), the custom query against Forms can't find the associated row data for indexing.

Thanks!

0 0
replied on October 14

Ah, so you want the receipt to be unique when compared to the other upload receipts. I have not tested this, but using JavaScript in the Modern Designer, there is getFieldValues. I would be curious to see what it returns for an upload field when a file is uploaded.

1 0
replied on October 14

I'll give it a try. I'm new to javascript in the new designer, but can probably figure it out. Thanks!

 

0 0
replied on October 15

getFieldValues will return an array of fields with an array of file upload names and sizes in your case since it is in a table. You can definitely determine if you have duplicates that way. I would also recommend using a column within the table to denote which row(s) are duplicates since you won't be able to validate the actual file upload field

2 0
replied on October 15

Thanks Zachary. I appreciate the info and the great suggestion.

0 0
replied on October 15

These are my preliminary results.

Using this script:

LFForm.onFieldChange(function(){ 
  LFForm.setFieldValues({fieldId: 38}, 
  LFForm.getFieldValues({fieldId: 4})) }, {fieldId: 4});

 

{fieldId: 38} is a multiline field

{fieldId: 4} is the upload field on the table with 10 lines

 

I am getting this result: 

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

 

I've tried a number of things but have only gotten this far, an array of objects. I don't see anything in the available instructions that shows how to dig into the objects. Hoping there is more to this scripting than shows in the instructions.

0 0
APPROVED ANSWER SELECTED ANSWER
replied on October 15

The file upload field returns an object from getFieldValues. The object contains a list of all of the files that were uploaded or an empty array if a file was removed from the field.

 

I threw together a quick example of how this would work for both having a duplicate check within each row of the table and a multiline field outside of the table. I commented all of the lines of code so you know what is going on. NOTE: this code does not handle a user removing a row from the table, but it does handle a user removing a file from the upload field.

I encourage you to review the code and make sure you understand what it is doing before implementing it in any production code, but I am happy to explain anything you need!

 

const formFields = {
  multiline: { fieldId: 70 },
  uploadColumn: { fieldId: 69 },
  isDuplicateColumn: { fieldId: 46 },
}

LFForm.onFieldChange(async (ev) => {
  // get fieldId and row number from the event that fired
  const { fieldId, index } = ev.options[0];
  if (fieldId === undefined) return;
  // create a formFieldId object to get the value of the field
  const formFieldId = { fieldId };
  // When field is in a table/collection index = row number, so lets only focus on that row
  if (index !== undefined && index !== -1) formFieldId.index = index;
  // get the value of the field that changed
  /**
   * @type {Array<{ name: string, size: string }>}
   */
  const changedValue = LFForm.getFieldValues(formFieldId);
  console.log('Field changed:', formFieldId, changedValue);

  /**
   * @type {{ name: string, size: string }[][]}
   */
  const allUploadFieldValues = LFForm.getFieldValues(formFields.uploadColumn);

  // reset current field duplicate status
  await LFForm.setFieldValues(formFields.isDuplicateColumn, '', { index });
  const allFileNames = new Set();
  const dupes = new Set();
  for (let i = 0; i < allUploadFieldValues.length; i++) {
    const fieldValue = allUploadFieldValues[i];
    if (index !== undefined && index !== -1 && i === index) continue; // skip current row
    // Only one file allowed per upload field so grab first from the array
    const file = fieldValue[0];
    if (!file) continue; // skip empty rows
    // create a unique key for each file based on name and size
    const fileKey = `${file.name}-${file.size}`;
    // check if the file key already exists in the set
    if (allFileNames.has(fileKey)) {
      dupes.add(file.name);
    } else {
      allFileNames.add(fileKey);
    }

    const isDuplicate = changedValue[0] && file.name === changedValue[0].name && file.size === changedValue[0].size;
    if (isDuplicate) {
      dupes.add(file.name);
      const isDuplicateColumnFieldId = formFields.isDuplicateColumn.fieldId;
      try {

        // set the duplicate status for the current row
        await LFForm.setFieldValues(formFields.isDuplicateColumn, 'duplicate', { fieldId: isDuplicateColumnFieldId, index: i });
        // if the current row is a duplicate, set the duplicate status for the other rows that have the same file
        await LFForm.setFieldValues(formFields.isDuplicateColumn, 'duplicate', { fieldId: isDuplicateColumnFieldId, index });
      } catch (error) {
        // Remove this code if you don't have per row checking
      }
    }
  }
  const finalDupes = Array.from(dupes);
  console.log('mf dupes', finalDupes);
  await LFForm.setFieldValues(formFields.multiline, finalDupes.join(', '));

  // get list
}, formFields.uploadColumn);

 

1 0
replied on October 15

Wow, thanks! I will give this a try and add a note about how it goes. I'm mostly appreciative to see some real code! Thanks again

0 0
replied on October 15

Zachary,

This is working well.

Thank you!

0 0
replied on October 15

I think I'm going to redo my form using the Classic Form Designer. The scripting for the Modern Form designer isn't robust enough. Thanks for the responses!

0 0
replied on October 15

Any code you need for this will be just as complicated in classic as it is in the modern designer. Take a look at my previous reply for a working example.

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

Sign in to reply to this post.