I have an upload field in a table. Is there a way to require that all filenames be unique?
Thanks in advance!
I have an upload field in a table. Is there a way to require that all filenames be unique?
Thanks in advance!
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);
Why do you want them to be unique in Forms?
Thanks for your response!
There should be exactly one receipt per transaction number and this would validate that.
Can't you change the setting on the upload field to only allow 1 file? I feel like I'm missing something.
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!
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.
I'll give it a try. I'm new to javascript in the new designer, but can probably figure it out. Thanks!
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
Thanks Zachary. I appreciate the info and the great suggestion.
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.
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);
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
Zachary,
This is working well.
Thank you!
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!