MartMakkie
MartMakkie

Reputation: 13

Flask-WTF: How to define custom variables in Flask FormField

I am trying to setup a dynamic form in Flask where the form has a dynamically populated FieldList of FormFields. While most of it works, I keep running into issues with the variables of each FormField. I need each FormField to have a label which is the name of the FormField (and is rendered on page) and a custom ID which is used in a show/hide script which uses a dynamically filled SelectField to select a sub-form to show and hide. However, I cannot get the variables to retain their state after the form is submitted, which also prevents me from correctly processing the returned data.

These are my form classes:

class ColumnForm(Form):
    text = Label('', '')
    condition = SelectField('Condition', choices=[('eq', 'Equal to'), ('contains', 'Contains')], validators=[Optional()])
    value = StringField(validators=[Optional()])

class CategoryForm(Form):
    catName = ''
    Columns = FieldList(FormField(ColumnForm))
    def add_field(self, name):
        # I have tried several ways of adding the formFields to the FieldList, this is the only way I get the variables to be renamed, but I do not have a way to get the submitted data back
        if not self.checkIfformInFieldList(name):
            self.Columns.append_entry()#{'text' : name})
            self.Columns[-1].form.text = Label(len(self.Columns)-1, name)
            self.Columns[-1].name = name
            self.Columns[-1].id = name
            self.Columns[-1].form.condition.id = f'{name}-condition'
            self.Columns[-1].form.condition.name = f'{name}-condition'
            self.Columns[-1].form.value.name = name+'-value'
            self.Columns[-1].form.value.id = name+'-value'
            self.Columns[-1].form.value.validators = [Optional()] 
    def checkIfformInFieldList(self, name)->bool:
        for column in self.Columns:
            if column.name == name:
                return True
        return False

class baseForm(FlaskForm):
    table_select = SelectField('Select Table', choices=['Select Table'],validators=[Optional()])
    submit = SubmitField('Filter')
    tables = FieldList(FormField(CategoryForm))
    def add_category(self, catName:str, columnNames:list):
        self.tables.append_entry()
        self.tables[-1].name = catName
        self.tables[-1].id = catName
        for columnName in columnNames:
            self.tables[-1].add_field(columnName)

Here is (a simplified version of) my form initialization:

@app.route('/', methods=['GET', 'POST']))
def index():
    form = baseForm(request.form)
    databaseStructure = get_database_structure(db_dict)
    for table in databaseStructure:
        form.table_select.choices.append(table)
    if not form.tables.entries:
        for table, columns in databaseStructure.items():
            form.add_category(table, columns)
    if request.method == 'POST' and form.validate():
        print(form.data)
    return render_template('index.html', form = form)

Here is (a simplified version) of my html template:


<form method="post">
    {{ form.hidden_tag() }}
    <p>
        {{ form.table_select.label }}<br>
        {{ form.table_select }}
    </p>
    {% for category in form.tables %}
    <div id = "{{ category.name }}">
        {% for column in category.Columns %}
        <p>
            {{ column.form.text }}
            {{ column.form.condition }}
            {{ column.form.value }}
        </p>{% endfor %}
</div>
{% endfor %}
    <p>{{ form.submit() }}</p>
</form>
<script>
    document.addEventListener('DOMContentLoaded', function () {
        const tableSelect = document.querySelector('#table_select');
        const columnSelect = document.querySelector('#column_select');
        tableSelect.addEventListener('change', function () {
            localStorage.setItem('selectedTable', tableSelect.value)
        });
    });
    window.onload = showFormFunction()
    document.getElementById("table_select").onchange = function() {showFormFunction()};
    function showFormFunction() {
        let table_select_value = document.getElementById("table_select").value;
        {% for tableName in form.tables %}{% if loop.index0 == 0 %}
        if (table_select_value == "{{ tableName.id }}"){ {% else %} else if (table_select_value == "{{ tableName.id }}"){ {% endif %}
            document.getElementById("{{ tableName.id }}").style.display = "inline"; {% for tableNamex in form.tables %} {% if tableName.id != tableNamex.id %}
            document.getElementById("{{ tableNamex.id }}").style.display = "none"; {% endif %} {% endfor %}
        }{% endfor %} else { {% for tableName in form.tables %}
            document.getElementById("{{ tableName.id }}").style.display = "none";{% endfor %}
        }
        
    };
</script>

Upvotes: 1

Views: 23

Answers (0)

Related Questions