我正在尝试在 Symfony 中构建一个基于 Web 组件的自定义表单类型。为了简单起见,我构建了一个自定义输入组件。
当我在 HTML 表单中使用该组件时,该组件似乎可以工作 - demo。然而,当在 Symfony 中使用时,该值不会出现在 POST 请求中
export class CustomInput extends HTMLElement {
static formAssociated = true;
static get observedAttributes() {
return ['value', 'name'];
}
constructor() {
super();
this.attachShadow({mode: 'open'});
this.internals = this.attachInternals();
this.render();
}
get inputElement() {
return this.shadowRoot.querySelector('input');
}
connectedCallback() {
this.inputElement.addEventListener('input', (event) => {
this.value = event.target.value;
});
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'value' && oldValue !== newValue) {
this.value = newValue || '';
}
}
get value() {
return this.inputElement.value;
}
set value(newValue) {
this.inputElement.value = newValue;
this.internals.setFormValue(newValue);
}
render() {
this.shadowRoot.innerHTML = `
<input type="text" />
`;
}
}
customElements.define('p-input', CustomInput);
在 Symfony 上下文中我还添加了自定义表单类型:
final class CustomInputType extends AbstractType
{
public function getParent(): string
{
return TextType::class;
}
}
表单类型对应的Twig:
{%- block custom_input_widget -%}
<p-input type="text" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}></p-input>
{%- endblock custom_input_widget -%}
表单本身正在使用新的表单类型:
final class TestForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('title', CustomInputType::class, [
'label' => 'test.title',
]);
// other fields
}
}
最后是渲染表单的树枝:
<div class="form">
{{ form_start(form, {'attr': {'id':'test_edit_form' }}) }}
{{ form_errors(form) }}
<div class="element">
<div class="label">{{ form_label(form.title) }}</div>
<div class="input">{{ form_widget(form.title) }}</div>
</div>
{# more form elements #}
<button type="submit">Submit</button>
{{ form_rest(form) }}
{{ form_end(form) }}
</div>
twig 文件注册在 form_themes 下的 twig.yaml 中。
使用我的新自定义表单类型时会呈现该组件,并且如果预填充基础数据对象,它还会正确设置值。与所有其他表单元素一样,自定义元素也有一个名称属性。
<form name="test_form" method="post" action="/test/edit" id="test_edit_form">
<div class="element">
<div class="label"><label for="test_form_title" class="required">Title</label></div>
<div class="input"><p-input id="test_form_title" name="test_form[title]" required="required" value="Test"></p-input></div>
</div>
<div class="element">
<div class="label"><label for="test_form_number" class="required">Number</label></div>
<div class="input">
<select id="test_form_number" name="test_form[number]" required="required">
<option disabled="disabled" value="">Select...</option>
<option value="1" selected="selected">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
</div>
</div>
<!-- ... -->
</form>
但是当我提交表单时,POST-Request 中的值完全丢失。我可以看到本机输入元素的所有其他提交值,但缺少我的自定义元素。
有人可以帮我弄清楚我错过了什么吗?
您遇到的自定义输入组件未在 POST 请求中发送其值的问题可能源于设置值的方式以及表单数据的序列化方式。在您的 CustomInput 类中,您正确地使用 setFormValue 方法将值与表单关联起来,但似乎在表单提交之前该值可能无法正确更新。
为了确保正确捕获值,您可以为输入元素上的更改事件添加事件监听器。这将确保当输入失去焦点或更改时,值会在表单内部更新。以下是修改connectedCallback方法的方法:
connectedCallback() {this.inputElement.addEventListener('input', (event) =>{this.value=event.target.value;});
this.inputElement.addEventListener('change', (event) => {this.internals.setFormValue(this.value);}); }
此外,请确保在自定义输入元素上正确设置 name 属性,因为这对于正确序列化表单数据至关重要。
通过实施这些更改,提交表单时,自定义输入的值应包含在 POST 请求中。如果问题仍然存在,请考虑检查浏览器的开发人员工具以检查正在发送的表单数据。