Я пытаюсь достичь следующего одновременно в Flask:
- Возможность динамически добавлять и удалять строки (в данном случае просто StringField) в таблице wtform
- Возможность автозаполнения в этом StringField
Я реализовал следующие сценарии на основе поиска, который я сделал в Интернете. По сути, я собрал два javascripts, найденных из двух разных онлайн-источников.
Проблема, с которой я столкнулся, заключается в том, что кажется, что функция «Добавить / удалить строку» работает хорошо, а автозаполнение работает хорошо для предварительно заполненных строк (то есть строк, созданных из Flask перед рендерингом страницы). Однако автозаполнение не выполняется для строк, созданных кнопкой «Добавить».
Чтобы показать эффект, первый пи c ниже показывает автозаполнение для предварительно заполненного поля и работает нормально. 
Второй пи c ниже показывает проблему с автозаполнением в поле, созданном кнопкой '+ Добавить фрукты':
Я набрал буквы «Или», и появляется раскрывающееся меню, но после выбора (щелчка) «Оранжевый» в раскрывающемся списке поле не заполняется (поэтому в текстовом поле остается «Или»), а затем курсор переходит на строку выше . Желаемым поведением должно быть поле, заполненное «Orange» после нажатия, а курсор остается в текущей строке.
Я потратил на это часы и не мог понять, что не так с моим кодом. Я действительно ценю, если кто-то может помочь в этом. Ниже приведены два сценария для репликации проблемы:
Python код:
from flask import Flask, render_template, jsonify
from flask_wtf import FlaskForm
from wtforms import StringField, FieldList, FormField, SubmitField
from wtforms.validators import DataRequired
app = Flask(__name__)
class FruitForm(FlaskForm):
name = StringField('Fruit', validators=[DataRequired('Name')])
class BasketForm(FlaskForm):
fruits = FieldList(FormField(FruitForm))
submit = SubmitField('Submit')
@app.route('/autocomplete')
def autocomplete():
choices = ['Apple', 'Orange', 'Banana']
return jsonify(choices)
@app.route('/', methods=['GET', 'POST'])
def home():
form = BasketForm()
form.fruits = [
FruitForm(name="Apple")
]
if form.validate_on_submit():
pass
return render_template('home.html', form=form)
if __name__ == '__main__':
import os
app.config['SECRET_KEY'] = os.urandom(32)
app.run(debug=True, port=5002)
html / javascript код
<!DOCTYPE html>
<html lang="en">
<head>
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js" integrity="sha256-eGE6blurk5sHj+rmkfsGYeKyZx3M4bG+ZlFyA7Kns7E=" crossorigin="anonymous"></script>
<!-- Bootstrap CSS -->
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
</head>
<body>
<main role="main" class="container">
<form method="POST" class="form-group">
{{ form.hidden_tag() }}
<div data-toggle="fieldset" id="basket-fieldset">
<!-- Add Button -->
<div class="row">
<div class="col">
<button class="btn btn-info" type="button" data-toggle="fieldset-add-row" data-target="#basket-fieldset">+ Add Fruit</button>
</div>
</div>
<!-- Fruit List -->
{% for fruit in form.fruits %}
<div class="row" data-toggle="fieldset-entry">
<div class="col">{{ fruit.name(class="form-control autocomplete") }}</div>
<div class="col"><button class="btn btn-danger" type="button" data-toggle="fieldset-remove-row" id="port-fruit-{{loop.index0}}-remove">-</button></div>
</div>
{% endfor %}
</div>
</form>
<script>
$(function() {
/////////////////////////////////////////////////////////////////////////////////////
// Dynamically Add / Remove a row
$("div[data-toggle=fieldset]").each(function() {
var $this = $(this);
//Add new entry
$this.find("button[data-toggle=fieldset-add-row]").click(function() {
var target = $($(this).data("target"))
console.log(target);
var oldrow = target.find("[data-toggle=fieldset-entry]:last");
var row = oldrow.clone(true, true);
console.log(row.find(":input")[0]);
var elem_id = row.find(":input")[0].id;
var elem_num = parseInt(elem_id.replace(/.*-(\d{1,4})-.*/m, '$1')) + 1;
row.find(":input").each(function() {
console.log(this);
var id = $(this).attr('id').replace('-' + (elem_num - 1) + '-', '-' + (elem_num) + '-');
$(this).attr('name', id).attr('id', id).val('');
});
oldrow.after(row);
}); //End add new entry
//Remove row
$this.find("button[data-toggle=fieldset-remove-row]").click(function() {
if($this.find("[data-toggle=fieldset-entry]").length > 1) {
var thisRow = $(this).closest("[data-toggle=fieldset-entry]");
thisRow.remove();
}
}); //End remove row
});
/////////////////////////////////////////////////////////////////////////////////////
// Autocomplete Fruit name
$(".autocomplete").autocomplete({
source:function(request, response) {
$.getJSON("{{url_for('autocomplete')}}",{
q: request.term, // in flask, "q" will be the argument to look for using request.args
}, function(data) {
response(data); // matching_results from jsonify
});
},
minLength: 2,
select: function(event, ui) {
console.log(ui.item.value);
}
});
});
</script>
</main>
</body>
</html>
вы можете запустить приложение, просто поместив два скрипта в одну папку, а затем выполните python3 app.py, чтобы поиграть с приложением. Спасибо