我需要使用以下逻辑创建表单元素:
以下是表示此逻辑的HTML标记:
Choose your budget:
<div id="briefing_budget" class="budget clearfix">
<label>
<input type="radio" id="briefing_budget_0" name="briefing[budget][selected]" required="required" value="9999"> 9 999 rubles
</label>
<label>
<input type="radio" name="briefing[budget][selected]" value="other"> other <input type="text" name="briefing[budget][number]">
</label>
</div>
为了完成这项工作,我使用自定义Twig块创建了自定义字段类型。 Finnaly,我有一些我不喜欢的东西......
以下是自定义类型的代码:
<?php
namespace Company\Optimal\PromoAction\FreeCampaignFor10k;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Exception\LogicException;
use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToBooleanArrayTransformer;
use Symfony\Component\Form\Extension\Core\EventListener\FixRadioInputListener;
use Symfony\Component\Form\Extension\Core\View\ChoiceView;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* choices : [{"<value>": "<label>"}]
*/
class NumberRadioType extends AbstractType
{
/**
* Caches created choice lists.
* @var array
*/
private $choiceListCache = array();
public function buildForm(FormBuilderInterface $builder, array $options)
{
if (!$options['choice_list'] && !is_array($options['choices']) && !$options['choices'] instanceof \Traversable) {
throw new LogicException('Either the option "choices" or "choice_list" must be set.');
}
$preferredViews = $options['choice_list']->getPreferredViews();
$remainingViews = $options['choice_list']->getRemainingViews();
if (null !== $options['empty_value'] && 0 === count($options['choice_list']->getChoicesForValues(array('')))) {
$placeholderView = new ChoiceView(null, '', $options['empty_value']);
$this->addSubForms($builder, array('placeholder' => $placeholderView), $options);
}
$this->addSubForms($builder, $preferredViews, $options);
$this->addSubForms($builder, $remainingViews, $options);
$builder->addViewTransformer(new ChoiceToBooleanArrayTransformer($options['choice_list'], $builder->has('placeholder')));
$builder->addEventSubscriber(new FixRadioInputListener($options['choice_list'], $builder->has('placeholder')), 10);
$name = $builder->getName();
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($name) {
$data = $event->getData();
$data = $data['selected'] == 'other' ? $data['number'] : $data['selected'];
$event->setData($data);
});
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars = array_replace($view->vars, array(
'preferred_choices' => $options['choice_list']->getPreferredViews(),
'choices' => $options['choice_list']->getRemainingViews(),
'separator' => '-------------------',
'empty_value' => null,
));
$view->vars['is_selected'] = function ($choice, $value) {
return $choice === $value;
};
$view->vars['empty_value_in_choices'] = 0 !== count($options['choice_list']->getChoicesForValues(array('')));
if (null !== $options['empty_value'] && !$view->vars['empty_value_in_choices']) {
$view->vars['empty_value'] = $options['empty_value'];
}
}
public function finishView(FormView $view, FormInterface $form, array $options)
{
foreach ($view as $childView) {
$childView->vars['full_name'] = $view->vars['full_name'] . '[selected]';
}
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$choiceListCache =& $this->choiceListCache;
$choiceList = function (Options $options) use (&$choiceListCache) {
$choices = null !== $options['choices'] ? $options['choices'] : array();
// Reuse existing choice lists in order to increase performance
$hash = hash('sha256', json_encode(array($choices, $options['preferred_choices'])));
if (!isset($choiceListCache[$hash])) {
$choiceListCache[$hash] = new SimpleChoiceList($choices, $options['preferred_choices']);
}
return $choiceListCache[$hash];
};
$emptyData = array();
$emptyValue = function (Options $options) {
return $options['required'] ? null : '';
};
$emptyValueNormalizer = function (Options $options, $emptyValue) {
if (false === $emptyValue) {
return;
} elseif ('' === $emptyValue) {
return 'None';
}
return $emptyValue;
};
$resolver->setDefaults(array(
'choice_list' => $choiceList,
'choices' => array(),
'preferred_choices' => array(),
'empty_data' => $emptyData,
'empty_value' => $emptyValue,
'error_bubbling' => false,
'compound' => true,
'data_class' => null,
));
$resolver->setNormalizers(array(
'empty_value' => $emptyValueNormalizer,
));
$resolver->setAllowedTypes(array(
'choice_list' => array('null', 'Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface'),
));
}
/**
* Returns the name of this type.
*
* @return string The name of this type
*/
public function getName()
{
return 'number_radio';
}
/**
* Adds the sub fields for an expanded choice field.
*
* @param FormBuilderInterface $builder The form builder.
* @param array $choiceViews The choice view objects.
* @param array $options The build options.
*/
private function addSubForms(FormBuilderInterface $builder, array $choiceViews, array $options)
{
foreach ($choiceViews as $i => $choiceView) {
if (is_array($choiceView)) {
// Flatten groups
$this->addSubForms($builder, $choiceView, $options);
} else {
$choiceOpts = array(
'value' => $choiceView->value,
'label' => $choiceView->label,
'translation_domain' => $options['translation_domain'],
);
$choiceType = 'radio';
$builder->add($i, $choiceType, $choiceOpts);
}
}
}
}
模板:
{% block number_radio_widget %}
{% spaceless %}
<div {{ block('widget_container_attributes') }}>
{% for child in form %}
<label>{{ form_widget(child) }}{{ child.vars.label }}</label>
{% endfor %}
<label><input type="radio" name="{{ form.vars.full_name }}[selected]" value="other"/>
other <input type="text" name="{{ form.vars.full_name }}[number]"/>
</label>
</div>
{% endspaceless %}
{% endblock %}
我是Symfony的新手,所以我从Symfony的班级ChoiceType
复制了很多,并且实际上并不知道那里发生的一半事情的目的。 :)
Finnaly,问题是:使用Symfony 2表单组件实现目标的最佳(或至少更好)方法是什么?
答案 0 :(得分:1)
如果您从&#34; text&#34;中抄写FormType,那么在树枝中添加一些javascript会很简单
在表单类型中设置所需的最小值:
class NumberRadioType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->setAttribute('configs', $options['configs']);
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['configs'] = $form->getConfig()->getAttribute('configs');
}
/**
* {@inheritdoc}
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'configs' => array()
));
$resolver->setNormalizers(array(
'configs' => function (Options $options, $value) {
return true;
}
));
}
/**
* {@inheritdoc}
*/
public function getParent()
{
return 'text';
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'NumberRadio';
}
你在html twig模板中的:
{% block number_radio_widget %}
{% spaceless %}
<div {{ block('widget_container_attributes') }}>
{% for child in form %}
<label>{{ form_widget(child) }}{{ child.vars.label }}</label>
{% endfor %}
<label><input type="radio" {{id}}/>
other <input type="text" name="{{ form.vars.full_name }}[number]" value="{{value}}"/>
</label>
</div>
{% endspaceless %}
{% endblock %}
您可以使用 {{id}} 来获取输入的参数,例如名称,ID和值
您可以使用 {{value}} 来获取输入值
在javascript twig模板中,您可以自定义组件
{% block number_radio_javascript %}
<script type="text/javascript">
var selectedInput = $('input[name=briefing[budget][selected]]:checked', '#myForm').val()
if(selectedInput ==1){
//do something
}else{
//do something else
}
</script>
{% endblock %}
您需要添加一些代码才能包含javascript部分。看看&#34; genemu form&#34;学习怎么做,但基本上: 你需要创建一个枝条扩展
https://github.com/genemu/GenemuFormBundle/blob/master/Twig/Extension/FormExtension.php
然后每次使用扩展名来使用你的formType
{% extends '::base.html.twig' %}
{% block jsscript %}
{{ vendor_type_javascript(form) }}
{% endblock %}
{% block content %}
{{ form_widget(edit_form) }}
{{ form_errors(edit_form) }}
{{ form_rest(edit_form) }}
{% endblock %}