我是ajax编程的初学者,所以请多多包涵。
我想要做的是允许用户在单击按钮时添加一个表单字段,如下所示:
对于主窗体,我有以下代码。
class EnrollForm(FlaskForm):
known_for = StringField('Known for',
validators=[
Length(max=LONG_STRING)
]
)
soc_med_info = FieldList(FormField(SocialMediaForm), min_entries=1)
这是它的子表单/表单域
class SocialMediaForm(Form):
social_media = SelectField('Where can we find you?', coerce=str)
other = StringField(validators=[
Length(max=MEDIUM_STRING)
])
handle = StringField('Handle',
validators=[
Length(max=SHORT_STRING)
]
)
followers = StringField('Followers',
validators=[
Length(max=SHORT_STRING),
Regexp('^\d*[kmKM]$', message='Input number of followers')
]
)
html (enroll.html)
<div class="row">
<div class="col-lg-12">
<form method="POST"
action="{{url_for('user.enroll')}}"
id="enroll-form">
{{ form.hidden_tag() }}
<fieldset class="form-group">
<legend>
Be one of us
</legend>
<div class="form-group">
{{ form.known_for.label(class="form-control-label") }}
{% if form.known_for.errors %}
{{ form.known_for(class="form-control form-control-sm is-invalid")}}
<div class="invalid-feedback">
{% for error in form.known_for.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.known_for(class="form-control form-control-sm")}}
{%endif%}
</div>
<fieldset>
<legend>
Social Media Information
</legend>
<span id="platforms">
{% include 'pages/user/platforms.html' %}
</span>
</fieldset>
</fieldset>
</form>
</div>
</div>
注意包含的 html 文件(“platforms.html”)——这是我呈现子表单字段行的地方
{% for soc_med in form.soc_med_info %}
<div class="row">
<div class="col-md-4">
<div class="form-group">
{{ soc_med.social_media.label(class="form-control-label") }}
{% if soc_med.social_media.errors %}
{{ soc_med.social_media(class="form-control form-control-sm is-invalid")}}
<div class="invalid-feedback">
{% for error in form.social_media.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ soc_med.social_media(class="form-control form-control-sm")}}
{%endif%}
</div>
</div>
<div class="col-md-4">
<div class="form-group">
{{ soc_med.handle.label(class="form-control-label") }}
{% if soc_med.handle.errors %}
{{ soc_med.handle(class="form-control form-control-sm is-invalid")}}
<div class="invalid-feedback">
{% for error in form.handle.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ soc_med.handle(class="form-control form-control-sm")}}
{%endif%}
</div>
</div>
<div class="col-md-2">
<div class="form-group">
{{ soc_med.followers.label(class="form-control-label") }}
{% if soc_med.followers.errors %}
{{ soc_med.followers(class="form-control form-control-sm is-invalid")}}
<div class="invalid-feedback">
{% for error in form.followers.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ soc_med.followers(class="form-control form-control-sm")}}
{%endif%}
</div>
</div>
<div class="col-md-2">
<div class="form-group">
{% if loop.index == 1 %}
<button type="button"
id="add-soc-med-btn">
Add Item
</button>
{% else %}
<button type="button">
X
</button>
{% endif %}
</div>
</div>
</div>
{% endfor %}
AJAX 脚本:
<script type="text/javascript">
$("#add-soc-med-btn").on("click", function(evt){
evt.preventDefault();
$.ajax({
url: "{{url_for('user.add_soc_med')}}",
type: "POST",
data: $("#enroll-form").serialize(),
success: function(data) {
console.log(data)
$('#platforms').html(data)
},
error: function(xhr, resp, text){
console.log(xhr, resp, text)
}
});
});
</script>
“观点”:
@user.route('/enroll', methods=['GET', 'POST'])
@login_required
def enroll():
form = EnrollForm()
# Initialize form
for soc_form in form.soc_med_info:
soc_form.social_media.choices = soc_med_platforms
if form.validate_on_submit():
return doEnroll(request, form)
return render_template('pages/user/enroll.html', form=form)
def doEnroll(request, form):
pass
@user.route('/enroll/add/social_media', methods=['POST'])
@login_required
def add_soc_med():
form = EnrollForm(request.form)
form.soc_med_info.append_entry()
for soc_form in form.soc_med_info:
soc_form.social_media.choices = soc_med_platforms
return render_template('pages/user/platforms.html', form=form)
“删除行”功能尚未实现。 预期的结果是连续添加字段行,但是重复点击按钮也只添加了一个字段行
我假设这是因为在视图代码中,“add_soc_med()”;我正在重新初始化 EnrollForm。我想要做的是保留“enroll()”函数中的表单并访问 soc_med_info 字段列表并附加一个条目。
我只是不知道该怎么做。
我在此线程上使用 Jelle van der Zwaag 的回答: 使用 AJAX 使用 Flask-WTForms 将条目附加到 FieldList
你是正确的,在 add_soc_med 视图函数中重新初始化 EnrollForm 是导致问题的原因。表单的状态不会在请求之间保留,因此您需要一种不同的方法。一种解决方案是使用 JavaScript 克隆现有的表单字段并将其附加到表单而不向服务器发出请求。
这是您的 JavaScript 代码的更新版本:
$("#add-soc-med-btn").on("click", function (evt) {
evt.preventDefault();
// Clone the last row in the form
let newRow = $("#platforms .row").last().clone();
// Increment the indices in the field names and ids to ensure unique names
newRow.find(":input").each(function () {
let nameAttr = $(this).attr("name");
let idAttr = $(this).attr("id");
let indexPattern = /\d+/;
let index = parseInt(nameAttr.match(indexPattern)[0]);
let newIndex = index + 1;
let newNameAttr = nameAttr.replace(indexPattern, newIndex);
let newIdAttr = idAttr.replace(indexPattern, newIndex);
$(this).attr("name", newNameAttr);
$(this).attr("id", newIdAttr);
});
// Clear the input values of the new row
newRow.find(":input").val('');
// Update the button in the new row to the "X" button
newRow.find(".col-md-2 button").first().text('X');
// Append the new row to the form
$("#platforms").append(newRow);
});
现在,使用这段 JavaScript 代码,表单将在重复单击按钮时不断添加新行,而无需向服务器发出请求。这也有助于减少服务器负载,因为表单操作完全在客户端完成。然后您可以删除 add_soc_med 视图函数,因为它不再需要了。
请记住,此解决方案采用特定的表单结构,并且字段名称和 ID 遵循示例中使用的模式。如果您的表单结构发生变化,请务必调整代码。
基本上你的方法有效。
但是,单击该按钮后,您将替换整个表单,包括用于添加子表单的按钮。这也意味着不再分配点击事件的监听器。要添加更多条目,需要在填充模板后再次注册监听器。
一个可能的解决方案如下。
function handleClick(evt) {
evt.preventDefault();
$.ajax({
url: "{{url_for('user.add_soc_med')}}",
type: "POST",
data: $("#enroll-form").serialize(),
success: function(data) {
$("#add-soc-med-btn", $('#platforms').html(data))
.on("click", handleClick);
},
error: function(xhr, resp, text){
console.log(xhr, resp, text)
}
});
}
$("#add-soc-med-btn").on("click", handleClick);