Form Assembly Custom Success Message

Recently I was asked to write some simple JavaScript for a FormAssembly form. At Virtual we use FormAssembly to create custom forms to connect to Salesforce. One our use cases is to create a custom voting mechanism for organizations. The idea being that we send out “ballots” which are basically just FormAssembly forms. They are connected to our Salesforce instance and some custom objects that we have. We wanted a simple way to disable the form after it has been submitted so that a given user cannot vote more than once.

Our form basically has two states. Each member of the organization receives a their own unique link to the form which is how we keep track of which users have voted and what their vote was. This also allows us to track the status of the vote. When they first receive the link their vote status is pending. Once the vote has been cast the status changes to Cast. Here is a very simple example of what this looks like in production.

As you can see, nothing fancy, however we wanted to add some logic to it so that if the ballot has already been cast, the form would be hidden and a custom message shown to the user. In writing the simple code for this project I made a few decisions.

  1. Code should be written in ‘Vanilla’ JavaScript for maximum portability/compatibility.
  2. Code should be modular enough to be used in many future forms with very minor changes.
  3. The success message should be customizable in FormAssembly. Meaning, no one should have to touch the code to change the message.

Taking these constraints into consideration, here is the code I came up with.

    window.addEventListener('load', function () {
var ballotStatus = document.querySelector("input[title='Ballot Status']");
if (ballotStatus.value.toLowerCase() === 'cast') {
document.querySelector('form').style.display = 'none';
document.querySelector('form').parentNode.innerHTML += '<h2>'+document.querySelector("input[title='Ballot Cast Message']").value+'</h2>';
} else {
document.querySelector("input[title='Ballot Cast Message']").parentNode.parentElement.style.display = 'none'
}
})

That’s it. Short and simple. Now I will walk you through the code and how it functions. First notice that I am wrapping all of the functionality in an Event Listener. The reason for this is that it appears that when you add custom code to the Properties section of a FormAssembly form, it executes the code before the form has actually loaded. Because of this, the ballot status is not actually ready when the script runs.

Next you can see that this script assumes that you have a Text Input in the form with the name of Ballot Status. This is the input that will hold the status. In our case either “Pending” or “Cast”. I am simply checking to see if the ballot status is equal to cast. Then I hide the form and prepend the message above the hidden form container. As you can see I am using the value of a Text Input titled Ballot Cast Message. I am also hiding that input when the page loads. This allows me to easily change the message from within FormAssembly without messing with the code.

Overall this works pretty good but as I was typing this up, I realized a pretty big bug. The way that I am targeting the form is very problematic.

        document.querySelector('form').style.display = 'none';

I realized I am making a blanket statement here as this may not be the only form on the page. If I were using jQuery I could do something like this

$("input[title='Ballot Status']").closest('form').hide().parent().prepend('<h2>Hello World</h2>')

That would hide my form and add Hello World in the space where the form previously existed. All in one line. However let’s stick with our plain JavaScript approach. As always, there are a couple ways to do this. You could write a function that traverses up the DOM until it hits the parent container. I explored that approach but for the purpose of simplicity I just decided to target the form’s container class. It appears that every FormAssembly form that gets embedded in a page has this parent container with the class of wFormContainer so I can simply refactor my code below to target this container instead of the generic form selector.

    var ballotStatus = document.getElementsByClassName("wFormContainer")[0];

Here is the updated code.

  window.addEventListener('load', function () {
var ballotStatus = document.querySelector("input[title='Ballot Status']");
if (ballotStatus.value.toLowerCase() === 'cast') {
var form = document.getElementsByClassName("wFormContainer")[0];
form.style.display = 'none';
form.parentNode.innerHTML += '<h2>'+document.querySelector("input[title='Ballot Cast Message']").value+'</h2>';
} else {
document.querySelector("input[title='Ballot Cast Message']").parentNode.parentElement.style.display = 'none'
}
})

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top