Hello! I have a use case that I’m wondering how to implement, and if I’d be able to see it in action in the editor or only on a live deployed site (I’m currently still building and haven’t upgraded to deploy yet).
In the application I’m building we would like our users to set up form templates and set one of their templates to ‘active’. In Supabase I have a table for Forms tied to a user and then a table for Form_Fields that are tied to a form. I am pulling this data correctly and can see it when I fetch from Supabase.
Now, I would like to dynamically create the form based on the form fields tied to the form that is currently active. Natively, it doesn’t appear to allow for binding a form element to data to dynamically generate this. I could create segmented sections for inputs, select boxes, other types of form fields and bind each of those sections to data and filter based on the field_type, but it won’t necessarily be in the order set in the database because I’ll have to group field_types together. I’ve worked up a Javascript function with the help of ChatGPT (which I’ve added in the code block) that will take the data and dynamically create the html elements. But here is where I’m having a hard time adding the function/binding it to data and figuring out how to see it in action, but then would it even be able to create those elements in the editor?
Any help here would be very welcome! Thanks!
// The createForm function
function createForm(containerId, formFields) {
const container = document.getElementById(containerId);
const form = document.createElement('form');
form.setAttribute('id', 'dynamic-form');
formFields
.sort((a, b) => a.field_order - b.field_order)
.forEach(field => {
const fieldWrapper = document.createElement('div');
fieldWrapper.classList.add('form-field-wrapper');
const label = document.createElement('label');
label.setAttribute('for', field.field_name.toLowerCase());
label.textContent = field.field_name;
let inputElement;
if (field.field_type === 'text' || field.field_type === 'email' || field.field_type === 'password') {
inputElement = document.createElement('input');
inputElement.setAttribute('type', field.field_type);
inputElement.setAttribute('id', field.field_name.toLowerCase());
inputElement.setAttribute('name', field.field_name.toLowerCase());
} else if (field.field_type === 'checkbox') {
inputElement = document.createElement('input');
inputElement.setAttribute('type', 'checkbox');
inputElement.setAttribute('id', field.field_name.toLowerCase());
inputElement.setAttribute('name', field.field_name.toLowerCase());
} else if (field.field_type === 'radio') {
inputElement = document.createElement('div');
inputElement.setAttribute('id', field.field_name.toLowerCase());
inputElement.setAttribute('name', field.field_name.toLowerCase());
field.options.forEach(option => {
const radioWrapper = document.createElement('div');
const radioInput = document.createElement('input');
const radioLabel = document.createElement('label');
radioInput.setAttribute('type', 'radio');
radioInput.setAttribute('name', field.field_name.toLowerCase());
radioInput.setAttribute('value', option.label.toLowerCase());
radioLabel.textContent = option.label;
radioWrapper.appendChild(radioInput);
radioWrapper.appendChild(radioLabel);
inputElement.appendChild(radioWrapper);
});
} else if (field.field_type === 'select') {
inputElement = document.createElement('select');
inputElement.setAttribute('id', field.field_name.toLowerCase());
inputElement.setAttribute('name', field.field_name.toLowerCase());
field.options.forEach(option => {
const optionElement = document.createElement('option');
optionElement.setAttribute('value', option.label.toLowerCase());
optionElement.textContent = option.label;
inputElement.appendChild(optionElement);
});
}
if (field.is_required) {
inputElement.setAttribute('required', 'required');
}
fieldWrapper.appendChild(label);
if (inputElement) {
fieldWrapper.appendChild(inputElement);
}
form.appendChild(fieldWrapper);
});
const submitButton = document.createElement('button');
submitButton.setAttribute('type', 'submit');
submitButton.textContent = 'Submit';
form.appendChild(submitButton);
container.innerHTML = '';
container.appendChild(form);
}
// Example form fields data (THIS WILL BE DATA FROM SUPABASE)
const formFields = [
{ id: 1, field_name: 'First Name', field_type: 'text', is_required: true, field_order: 1 },
{ id: 2, field_name: 'Gender', field_type: 'radio', is_required: true, field_order: 2, options: [{ label: 'Male' }, { label: 'Female' }] },
{ id: 3, field_name: 'Country', field_type: 'select', is_required: false, field_order: 3, options: [{ label: 'USA' }, { label: 'Canada' }] },
{ id: 4, field_name: 'Subscribe', field_type: 'checkbox', is_required: false, field_order: 4 }
];
// Call the function to generate the form
createForm('form-container', formFields);