Populate Field Options at Template Level
Sometimes you may need to populate field options such as Dropdown, Checkboxes or Radios dynamically at the template level. Perhaps you're populating the options from a Craft Entry or some other Twig template code in your template. Freeform specifically wasn't designed to handle this, but you can work around it with this guide.
While Freeform does allow for populating field options with predefined data in the control panel, this isn't always enough for every use case. Further to this, Freeform explicitly requires that all options exist for the field in the form builder work with field types like Dropdown, Checkboxes, etc. To work around this, you can create the field as a regular Text field instead, and then modify the formatting template to account for it and include your own Twig code to pull in dynamic options. It isn't a perfect solution, but the closest you can get.
Instructions
Here's how to make those changes on your site:
Create a new form or edit an existing form as usual. Add a new Text field and let's call it Services with a handle of services
, and place it somewhere into your form layout.
Update your formatting template code...
-
Let's assume you're using something that resembles the Solspace sample Flexbox formatting template:
{{ form.renderTag }}
{% for row in rows %}
{% set width = (12 / (row|length)) %}
<div{{ form.attributes.row|raw }}>
{% for field in row %}
{{ field.render() }}
{% endfor %}
</div>
{% endfor %}
{{ form.renderClosingTag }} -
Update it to include a conditional that checks on your new Services field:
{{ form.renderTag }}
{% for row in rows %}
{% set width = (12 / (row|length)) %}
<div{{ form.attributes.row|raw }}>
{% for field in row %}
{% if field.handle == "services" %}
// YOUR CUSTOM CODE HERE
{% else %}
{{ field.render() }}
{% endif %}
{% endfor %}
</div>
{% endfor %}
{{ form.renderClosingTag }} -
Let's say you wanted to populate the Services field with options from a Craft Entry that is already loaded into the page, and you want to grab the options of that field (e.g.
companyServices
). The final code might look something like this:{{ form.renderTag }}
{% for row in rows %}
{% set width = (12 / (row|length)) %}
<div{{ form.attributes.row|raw }}>
{% for field in row %}
{% if field.handle == "services" %}
{{ field.renderLabel() }}
{{ field.renderInstructions() }}
<select name="{{ field.handle }}" id="{{ field.idAttribute }}">
<option>Please select...</option>
{% for option in entry.companyServices %}
<option value="{{ option.value }}">{{ option.label }}</option>
{% endfor %}
</select>
{{ field.renderErrors() }}
{% else %}
{{ field.render() }}
{% endif %}
{% endfor %}
</div>
{% endfor %}
{{ form.renderClosingTag }}
Your form will now display options populated by the outside Craft Entry source, and allow you users to submit the form choosing one of those options. The data will then be stored in the Services text field as a simple string of text.