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

Question

Question

Easiest Way to Reject a Form While Missing Some Required Fields

asked on August 12, 2025

I'm curious how other users are managing use cases like this.

Owner of the process I'm creating wants an approver to be able to click a "Reject" action button on the form to return it to an earlier stage in the process.  But they want to do it without filling in a dozen required fields on the form (basically make them required when submitting but not when rejecting).

I know I could do this with Field rules and a checkbox/radio button/etc. to make the decision - but they really want it to be with the submission buttons.

I handled this on the Classic Designer by having Javascript remove the required attribute from the fields when the Reject button was clicked, and they are wanting that same functionality in the Layout Designer.

Any suggestions or tricks that people have learned to make this kind of thing work in the Layout Designer?

0 0

Answer

SELECTED ANSWER
replied on March 19 • Show version history

I figured out a way to reject a form in the new designer while bypassing required fields - with code only!

No field rules required so it is super easy to add this to a new form!

/*Bypass required fields on form reject by user.
The reqFields array is declared outside the function so that it carries across multiple submission attempts.
If the Reject button is used, the required validation of the fields is removed, even if the submission fails
for another reason.
However, another submission attempt (non-Reject) will reinstate the required validation of those fields
based on what is carried over in the reqFields array from the prior Reject submission attempt.*/
var reqFields = [];
LFForm.onFormSubmission(async function (event) {
  const userAction = event.data.action.value;
  if (userAction == 'Reject') {
    reqFields = LFForm.findFields(f => f.settings.required); 
    for (const e of reqFields) {
      await LFForm.validateFields(e, {"required": false});
    }
  }
  else {
    for (const e of reqFields) {
      await LFForm.validateFields(e, {"required": true});
    }
  }
});

EDIT: Based on feedback from Zac St. Louis, I removed the await keyword from line 11 because the LFForm.findFields function runs synchronously.

EDIT AGAIN: Modified code with more feedback from Zac St. Louis.  Rather than looping through the array, it verifies the array isn't empty and passes the whole array to the LFForm.validateFields function, so that improves functionality. Also addresses some edge cases around the initial Reject submission failing (for a different reason than required fields) and ensuring the required fields are reapplied before any other submissions.

/*Bypass required fields on form reject by user.
The reqFields array is declared outside the function so that it carries across multiple submission attempts.
If the Reject button is used, the required validation of the fields is removed, even if the submission fails
for another reason.
However, another submission attempt (non-Reject) will reinstate the required validation of those fields
based on what is carried over in the reqFields array from the prior Reject submission attempt.*/
let reqFields = [];
LFForm.onFormSubmission(async function (event) {
  const userAction = event.data.action.value;
  if (userAction == 'Reject') {
    reqFields = LFForm.findFields(f => f.settings.required);
    if (reqFields.length > 0) {
      await LFForm.validateFields(reqFields, { "required": false });
    }
  }
  else {
    const stillReq = LFForm.findFields(f => f.settings.required).filter((f) => reqFields.findIndex(rf => rf.fieldId === f.fieldId) === -1);
    const allReq = reqFields.concat(stillReq);
    if (allReq.length > 0) {
      await LFForm.validateFields(allReq, { "required": true });
    }
  }
});
3 0

Replies

replied on August 21, 2025 • Show version history

I found an option that works (sort of).

I made a hidden field on my form.  I named it "user_submit_action".  Via Field Rules, it is hidden Always, and ignores data when hidden.

Then I have Javascript update the value in the user_submit_action field when the user presses a submission button.

Finally, I have Field Rule(s) that act on every single field that is required.  They set the fields to optional when the user_submit_action = Reject.

The result is the user presses any submission button, the Javascript populates the user_submit_action field with the value for that submission button.  If that value is Reject, the various required fields are changed to optional, and then the submission processes like that.  In my testing on Version 12.0.2503.10378, it worked as expected.

And since the Field rules is set to ignore the value when hidden, it doesn't save upon submission and thus future tasks all start with a clean slate in the user_submit_action field.

Here's the Javascript: 

//Add the submit action to the user_submit_action field on submission.
LFForm.onFormSubmission(async function (event) {
  await LFForm.setFieldValues({variableName: "user_submit_action"}, event.data.action.value);
});

 

6 0
replied on August 21, 2025

Very nice! I've done something like this in the Classic Designer, but I didn't even think to try it in the modern designer.

1 0
SELECTED ANSWER
replied on March 19 • Show version history

I figured out a way to reject a form in the new designer while bypassing required fields - with code only!

No field rules required so it is super easy to add this to a new form!

/*Bypass required fields on form reject by user.
The reqFields array is declared outside the function so that it carries across multiple submission attempts.
If the Reject button is used, the required validation of the fields is removed, even if the submission fails
for another reason.
However, another submission attempt (non-Reject) will reinstate the required validation of those fields
based on what is carried over in the reqFields array from the prior Reject submission attempt.*/
var reqFields = [];
LFForm.onFormSubmission(async function (event) {
  const userAction = event.data.action.value;
  if (userAction == 'Reject') {
    reqFields = LFForm.findFields(f => f.settings.required); 
    for (const e of reqFields) {
      await LFForm.validateFields(e, {"required": false});
    }
  }
  else {
    for (const e of reqFields) {
      await LFForm.validateFields(e, {"required": true});
    }
  }
});

EDIT: Based on feedback from Zac St. Louis, I removed the await keyword from line 11 because the LFForm.findFields function runs synchronously.

EDIT AGAIN: Modified code with more feedback from Zac St. Louis.  Rather than looping through the array, it verifies the array isn't empty and passes the whole array to the LFForm.validateFields function, so that improves functionality. Also addresses some edge cases around the initial Reject submission failing (for a different reason than required fields) and ensuring the required fields are reapplied before any other submissions.

/*Bypass required fields on form reject by user.
The reqFields array is declared outside the function so that it carries across multiple submission attempts.
If the Reject button is used, the required validation of the fields is removed, even if the submission fails
for another reason.
However, another submission attempt (non-Reject) will reinstate the required validation of those fields
based on what is carried over in the reqFields array from the prior Reject submission attempt.*/
let reqFields = [];
LFForm.onFormSubmission(async function (event) {
  const userAction = event.data.action.value;
  if (userAction == 'Reject') {
    reqFields = LFForm.findFields(f => f.settings.required);
    if (reqFields.length > 0) {
      await LFForm.validateFields(reqFields, { "required": false });
    }
  }
  else {
    const stillReq = LFForm.findFields(f => f.settings.required).filter((f) => reqFields.findIndex(rf => rf.fieldId === f.fieldId) === -1);
    const allReq = reqFields.concat(stillReq);
    if (allReq.length > 0) {
      await LFForm.validateFields(allReq, { "required": true });
    }
  }
});
3 0
replied on March 20 • Show version history

Does this still allow for the built-in Task Comment Box field to be set to Required using a Field Rule when populating another field with what Action Button was selected? In our case we would still want the end user to have to enter a comment in the Task Comment box when they select Reject, but make all the other fields not required.

1 0
replied on March 20

I didn't test that.  But if it does remove the requirement on that and it is a problem, you could easily add another LFForm.validateFields line after the one that removes the requirement (line 13 in the edited code).  In the one you add, you can just reapply the requirement for that one specific field.

1 0
replied on March 20

In my initial testing, the Task Comment Box is still required.

1 0
replied on March 20

That makes sense with it being a completely different type of element.

0 0
replied on August 12, 2025

You can use a radio button to select your approve/reject decision instead of using a submit button for it. This way, you can conditionally require fields only when approve is selected.

3 0
replied on August 13, 2025

Yeah, I think that might end up being the way to go.  Thank you.

0 0
replied on August 12, 2025 • Show version history

I usually handle this by creating my own Approve/Reject radio buttons with a single Submit button.

Then, I set field rules based on the radio buttons.

2 0
replied on August 13, 2025

Yeah, I think that might end up being the way to go.  Thank you.

0 0
replied on August 21, 2025

What Jason said is how we handle it as well. I've had discussions with the Forms team about being able to do this when selecting an Action button, as well as making the built in Task Comment box required based on what action button is selected. Hopefully someday.

1 0
replied on August 21, 2025

This is already marked as solved, but I'll just add that I feel this pain.

We also used JS to remove the required attribute in the Classic Designer, and it was a much cleaner solution. I don't love depending on radio buttons to select approve/reject before clicking Submit, and that feels much more like a workaround than a step forward.

Hopefully, the ability to suppress the required attribute on button click is added back in future releases!

2 0
replied on August 12, 2025

Generally what I do in these use cases are to only enable the approve button if all the fields are completed while reject has none such requirements. We then add a note to said fields that must be completed before Approval is allowed. It is not as clean since it is harder to tell required fields, but does fit the use case. 

1 0
replied on August 12, 2025

That might work for some use cases.  Thank you.

0 0
replied on August 12, 2025

Have you taken a look at using Process Stages in your process?  I use them along with field rules to enforce the field being optional for operations in that Process Stage.

 

1 0
replied on August 12, 2025

I've done that in multiple cases - but I don't think it will work here where I have a form that is being considered by a user for approval or rejection (with rejection being to return it to the prior user).  With approval, we need to make sure the user has populated those fields, but with rejection they don't have to.

0 0
replied on March 9

After upgrading to V12, we've used Matthew's solution on a couple of forms as changes have been requested (in v11 we used the radio button/Submit suggestion). However I do think I just found that the button press event doesn't work when adding a custom button via the new canned feature in the task properties window. Can anyone confirm that this is the case?

1 0
replied on March 9

Works for me on Version 12.0.2509.20409

I created a custom button for "Test", and it's value still populates into the field using the Javascript.

0 0
replied on March 9

Thanks for checking! It turns out the system was adding %20 for the spaces in the button label, so it ended up storing "Return%20for%20Correction".

1 0
replied on March 9 • Show version history

Ah, that would sense if you have spaces.

Note that you can have different values and labels so that your label includes spaces but your value does not.

For example, if you set your value as "Return" and the Label as "Return for Correction", then your script would reference them one of these ways:

LFForm.onFormSubmission(async function (event) {
  console.log(event.data.action.value);     //"Return"
  console.log(event.data.action.label);     //"Return for Correction"
});

If you are configuring from the Process Diagram, the value would be set as the "Button CSS Class" and the label would be set as the "Button Label".

If you are configuring via script with the LFForm.changeActionButton function, it would be like this:

LFForm.changeActionButton("Return", {label: "Return for Correction"});
2 0
replied on March 10

Perfect, thank you so much!

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

Sign in to reply to this post.