Dynamically Create/Alter Form Fields from URL Parameters (Not Prepopulate Existing Fields)

587 views Asked by At

In a formstack form, I need to be able to pass a list to the form as a parameter and, from that list, create checkboxes or dropdown menus that the user can select and that are saved in formstack's database and sent to integrations like all other fields. Here's an example of what I'd like to send in:

http://theformurl?list=option1,option2,option3,option4

From this, I'm trying to use code insertion in either (or a mixture of) the head, footer, or a code embed to create a new field on load that looks and acts like all the other fields.

I've been tinkering with Jenna Molby's approach to dynamically modifying html with url parameters found here:

https://jennamolby.com/tutorial-examples/dynamic-content-based-on-a-url-parameter-example/

But no luck so far. At present, I've not succeeded in getting dynamic text to populate in the form, let alone a form field that then talks to formstack's back end.

Is this doable, and if so, can anyone recommend an approach or a thread to pull on to figure it out?

--update

Thanks to Eric's suggestion, I was able to get halfway there. This code in the footer can commandeer a checkbox that you've already inserted in the form by id. It will replace that checkbox with the values you send in the url. But the selections don't get caught by Formstack when you submit.

<script>
document.addEventListener("DOMContentLoaded", function(event) {
  var url = new URL(window.location.href);
  //Put field number in var fieldNumber
  var fieldNumber = "12345678";
  //Put the parameter you're searching for in var param
  var param = "parameter name";
  //if you want a prefix before your values in the checkbox, use prefix
  var prefix = "Prefix ";
  //Put the question you want to ask here.
    var theQuestion = "Which of the values that came through the url will you select?";
  //What should the single checkbox say if no parameters are passed?
  var theDefaultBox = "No variables were contained in the parameter.";
  var theField = "field" + fieldNumber;
  var theFieldID = "fsCell"+fieldNumber;
  var values = url.searchParams.get(param).split(",");
  var theFieldHTMLfront = "";
  if (values) {theFieldHTMLfront = "<fieldset id=\"label"+fieldNumber+"\"><legend class=\"fsLabel fsLabelVertical\"><span>"+theQuestion+"</span></legend><div class=\"fieldset-content\"><label class=\"fsOptionLabel vertical\" for=\""+theField+"_1\"><input type=\"checkbox\" id=\""+theField+"_1\" name=\""+theField+"[]\" value=\""+ prefix + values[0] + "\" class=\"fsField vertical\" />"+ prefix + values[0] + "</label>";} else {theFieldHTMLfront = "<fieldset id=\"label"+fieldNumber+"\"><legend class=\"fsLabel fsLabelVertical\"><span>Which values may have observed or have knowledge about this event?</span></legend><div class=\"fieldset-content\"><label class=\"fsOptionLabel vertical\" for=\""+theField+"_1\"><input type=\"checkbox\" id=\""+theField+"_1\" name=\""+theField+"[]\" value=\""+theDefaultBox+"\" class=\"fsField vertical\" />test</label>";}
  var theFieldHTMLback = "</div></fieldset>";
  for (var i = 1; i < values.length; i++) {
    theFieldHTMLfront += "<label class=\"fsOptionLabel vertical\" for=\""+theField+(i+1)+"\"><input type=\"checkbox\" id=\""+theField+(i+1)+"\" name=\""+theField+"[]\" value=\""+prefix+values[i]+"\" class=\"fsField vertical\" />"+ prefix + values[i] + "</label>"; 
  }
  var theFieldHTML = theFieldHTMLfront + theFieldHTMLback;
  document.getElementById(theFieldID).innerHTML = theFieldHTML;
  });
</script>

Any thoughts on how to get it to talk to Formstack on submit?

2

There are 2 answers

0
Jacob Small On BEST ANSWER

So I've managed to find a solution that works for me. Thanks Eric for getting me started.

It requires adding two fields to the form you want to use this in: (1) a hidden text entry field where the selected values will be written, and (2) a placeholder checkbox field that this code will overwrite. You'll need to grab their id numbers, which I did by opening the live form and viewing source.

<script>
var selectedValues = [];
//This code goes in your Formstack theme footer. In the form that you want to add dynamic checkboxes to, create two fields using the WYSIWYG editor: a checkbox field and a text entry field. Make the text entry field hidden. You will need to know the id number of both the text entry and checkbox fields.

//Put the text entry field number in var textFieldNumber
var textFieldNumber = "field"+"12345678";
var index;
var checkboxFieldNumber = "12345679";
//Put the parameter you're searching for in var param
var param = "param";
//if you want a prefix before your values in the checkbox, use prefix
var prefix = "";
//Put the question you want to ask here.
var theQuestion = "Your question?";
//What should the single checkbox say if no parameters are passed?
var theDefaultBox = "Default message.";
document.addEventListener("DOMContentLoaded", function(event) {
  var url = new URL(window.location.href);
  //Put checkbox field number in var checkboxFieldNumber
  //Build the replacement HTML for the placeholder checkbox field.
  var theField = "field" + checkboxFieldNumber;
  var theFieldID = "fsCell"+checkboxFieldNumber;
  var values = url.searchParams.get(param).split(",") || null;
  var theFieldHTMLfront = "";
  if (values) {theFieldHTMLfront = "<fieldset id=\"label"+checkboxFieldNumber+"\"><legend class=\"fsLabel fsLabelVertical\"><span>"+theQuestion+"</span></legend><div class=\"fieldset-content\"><label class=\"fsOptionLabel vertical\" for=\""+theField+"_1\"><input type=\"checkbox\" id=\""+theField+"_1\" name=\""+theField+"[]\" value=\""+values[0]+"\" onchange=\"checkBoxToggle(this)\" class=\"fsField vertical\" />"+ prefix + values[0] + "</label>";} else {theFieldHTMLfront = "<fieldset id=\"label"+checkboxFieldNumber+"\"><legend class=\"fsLabel fsLabelVertical\"><span>Which values may have observed or have knowledge about this event?</span></legend><div class=\"fieldset-content\"><label class=\"fsOptionLabel vertical\" for=\""+theField+"_1\"><input type=\"checkbox\" id=\""+theField+"_1\" name=\""+theField+"[]\" value=\""+theDefaultBox+"\" onchange=\"checkBoxToggle(this)\" class=\"fsField vertical\" />test</label>";}
  var theFieldHTMLback = "</div></fieldset>";
  //iterate through the array found in the url parameters, adding a new checkbox option for each element in the array.
  if (values) {for (var i = 1; i < values.length; i++) {
    theFieldHTMLfront += "<label class=\"fsOptionLabel vertical\" for=\""+theField+(i+1)+"\"><input type=\"checkbox\" id=\""+theField+"_"+(i+1)+"\" name=\""+theField+"[]\" value=\""+values[i]+"\" onchange=\"checkBoxToggle(this)\" class=\"fsField vertical\" />"+ prefix + values[i] + "</label>";
  };}
  //finalize replacement HTML
  var theFieldHTML = theFieldHTMLfront + theFieldHTMLback;
  //write new HTML to DOM
  document.getElementById(theFieldID).innerHTML = theFieldHTML;
});

function checkBoxToggle(thisBox) {
  if(thisBox.checked) {
    //When a new checkbox is selected, add its value to array selectedValues, sort it, and write it to the text entry field.
    selectedValues.push(thisBox.value);
    selectedValues.sort();
    document.getElementById(textFieldNumber).value = selectedValues;
  } else {
    //When a checkbox is deselected, splice its value out of array selectedValues and write the array to the text entry field's value
    index = selectedValues.indexOf(thisBox.value);
    if (index > -1) {
      selectedValues.splice(index, 1);
      document.getElementById(textFieldNumber).value = selectedValues;
    }
  }
}
</script>
0
Eric Nail On

Not familiar with formstack or what exactly you're getting from the URL and placing into forms or of what type, but I'll take a shot in the dark here.

Perhaps something like this:

var paramsToGet = ['param', 'param', 'param'];

document.addEventListener("DOMContentLoaded", function(event) {
  let url = new URL(window.location.href);
  paramsToGet.forEach((v)=>{
    let thisParam = url.searchParams.get(param);
    newFormElement(thisParam, x, x, "Default Value");
  })
});

var newFormElement = (type, element_id, target_id, default_value) => {
  default_value = default_value || null;
  let el = document.createElement(type);
  el.id = element_id;
  if (default_value) {el.value = default_value;}
  document.getElementById(target_id).appendChild(el);
}