[英]Populating entity field type in dynamic form Symfony2
我有一个实体Lexeme,其中包含语言和音素实体。
在我的表单类型中,我希望根据为Lexeme选择的语言实体而对音素的选择有所不同。
问题是当我动态更新表单时,会显示正确的音素,但不会从数据库中填充这些音素:即,那些属于数据库中Lexeme的音素不会在动态加载的表单中显示为选中状态。
Lexeme控制器:
public function editAction(Request $request, $id)
{
$lexeme = $this->getDoctrine()
->getRepository('Aleph2OmegaTranscriptionBundle:Lexeme')
->find($id);
$query = $this->getDoctrine()
->getRepository('Aleph2OmegaTranscriptionBundle:Lexeme')
->createQueryBuilder('l')
->where('l.id > :thisId')
->setParameter('thisId', $id)
->setMaxResults(1)
->getQuery();
$nextLexeme = $query->getResult();
$query = $this->getDoctrine()
->getRepository('Aleph2OmegaTranscriptionBundle:Lexeme')
->createQueryBuilder('l')
->where('l.id < :thisId')
->setParameter('thisId', $id)
->setMaxResults(1)
->getQuery();
$previousLexeme = $query->getResult();
if ( count($nextLexeme) < 1 ) {
$query = $this->getDoctrine()
->getRepository('Aleph2OmegaTranscriptionBundle:Lexeme')
->createQueryBuilder('l')
->orderBy('l.id', 'asc')
->setMaxResults(1)
->getQuery();
$nextLexeme = $query->getResult();
}
if ( count($previousLexeme) < 1 ) {
$query = $this->getDoctrine()
->getRepository('Aleph2OmegaTranscriptionBundle:Lexeme')
->createQueryBuilder('l')
->orderBy('l.id', 'desc')
->setMaxResults(1)
->getQuery();
$previousLexeme = $query->getResult();
}
if (!$lexeme) {
$lexeme = new Lexeme();
}
$form = $this->createForm(new EditLexemeType(), $lexeme);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($lexeme);
$em->flush();
return $this->redirect($this->generateUrl('aleph2_omega_transcription_lexemes_edit', array ('id'=>$lexeme->getId())));
}
return $this->render('Aleph2OmegaTranscriptionBundle:Lexeme:edit.html.twig', array(
'form' => $form->createView(),
'previousId' => $previousLexeme[0]->getId(),
'nextId' => $nextLexeme[0]->getId()
));
}
Lexeme表单类型:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$formModifier = function (FormInterface $form, $language) {
$form
->remove('phonemes')
->add('phonemes', 'entity', array(
'class' => 'Aleph2OmegaTranscriptionBundle:Phoneme',
'property' => 'latin',
'expanded' => true,
'multiple' => true,
'by_reference' => false,
'query_builder' => function(EntityRepository $er) use ($language) {
return $er->createQueryBuilder('u')
->select('p')
->from('Aleph2OmegaTranscriptionBundle:Phoneme', 'p')
->where('p.language = :language')
->setParameter('language', $language);
},
));
};
$builder
->add('language', 'entity', array(
'class' => 'Aleph2OmegaTranscriptionBundle:Language',
'property' => 'name',
'expanded' => false,
'multiple' => false,
))
->add('defaultGreek')
->add('defaultHebrew')
->add('save', 'submit')
//->add('id', 'hidden')
->add('words', 'collection', array(
'type' => new WordLimitedProtoType(),
'allow_add' => true,
'allow_delete' => true,
'options' => array('data_class' => 'Aleph2Omega\TranscriptionBundle\Entity\Word'),
'prototype' => true,
'by_reference' => false,
))
->add('phonemes', 'entity', array(
'class' => 'Aleph2OmegaTranscriptionBundle:Phoneme',
'property' => 'latin',
'expanded' => true,
'multiple' => true,
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('u')
->select('p')
->from('Aleph2OmegaTranscriptionBundle:Phoneme', 'p')
->where('p.language = :language')
->setParameter('language', '1');
},
))
->add('save', 'submit')
->setMethod('POST')
->addEventListener(
FormEvents::POST_SUBMIT,
function ($event) {
$event->stopPropagation();
},
900)
->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
$data = $event->getData();
if ($data instanceof Word) {
$formModifier($event->getForm(), $data->getLanguage());
}
}
)
->get('language')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
$language = $event->getForm()->getData();
$formModifier($event->getForm()->getParent(), $language);
});
}
Lexeme Twig模板:
{{ include('Aleph2OmegaTranscriptionBundle::menu.html.twig') }}
{{ form_start(form) }}
{{ form_row(form._token) }}
<h1><a href="{{ path('aleph2_omega_transcription_lexemes_edit', {'id': previousId}) }}"><</a> Edit Lexeme <a href="{{ path('aleph2_omega_transcription_lexemes_edit', {'id': nextId}) }}">></a></h1>
{{ form_errors(form) }}
<table>
<tr><th>Language</th><td>{{ form_widget(form.language) }}</td></tr>
<tr><th>Default Greek</th><td>{{ form_widget(form.defaultGreek) }}</td></tr>
<tr><th>Default Hebrew</th><td>{{ form_widget(form.defaultHebrew) }}</td></tr>
</table>
<table>
<tr><th>Phonemes</th></tr>
<tr><td>{{ form_widget(form.phonemes) }}</td></tr>
</table>
<h3>{{ form_widget(form.save) }}</h3>
<table class="words" data-prototype="{% filter escape %}{% include 'Aleph2OmegaTranscriptionBundle:Word:limited_prototype.html.twig' with { 'item': form.words.vars.prototype } %}{% endfilter %}">
{# iterate over each existing word and render its fields #}
<tr><th>transcription</th><th>normalised</th><th>Hebrew</th><th>comment</th></tr>
{% for word in form.words %}
<tr>
<td>{{ form_widget(word.transcription) }}</td>
<td>{{ form_widget(word.normalisedTranscription) }}</td>
<td>{{ form_widget(word.hebrewTranscription) }}</td>
<td>{{ form_widget(word.comment) }}</td>
</tr>
{{ form_rest(word) }}
{% endfor %}
</table>
{{ form_rest(form) }}
{{ form_end(form) }}
AJAX的javascript:
jQuery(document).ready(function() {
$("[id$=language]").change(function() {
languageChange();
});
function languageChange() {
var $languages = $("[id$=language]");
$($languages).each(function() {
var $form = $(this).closest('form');
var data = {};
data[$(this).attr('name')] = $(this).val();
$.ajax({
url : $form.attr('action'), //Routing.generate('route_id', /* your params */), //
type: $form.attr('method'),
data: data,
success: function(html) {
$phonemes = $("[id$=phonemes]");
$($phonemes).each(function() {
$(this).replaceWith(
$(html).find('#'+this.id)
);
});
}
});
});
}
languageChange();
});
更新:一些截图
在私人通信中,有些人希望澄清我要寻找的行为。
这是来自其他实体(单词)的页面,该实体未使用AJAX填充音素字段。 这表现出我想要的行为:
通过AJAX更新的Lexeme实体(上面的代码所针对的)正确显示了每种语言的正确音素,只是没有检查数据库中记录为“已连接”到Lexeme的音素。
例如,当选择“希伯来语”时,以下是正确显示的音素:
以下是选择“希腊语”时正确显示的音素:
最后,就调试而言,我已经扎根使用Chrome控制台和网络显示,这表明问题可能是由于CSRF和AJAX引起的。 但是,我不明白的是-如果CSRF确实是问题所在,为什么从服务器返回页面呢?
更新2:部分解决方法
好的,因此至少可以正确显示初始页面加载的部分解决方法是避免AJAX调用。 这不能解决确保AJAX更新正确显示所有内容的问题,但至少可以改善功能(并且,我认为,与使用AJAX相比,预填充表单是一种更好的做法)。
在buildForm函数中,可以使用以下方法获取填充表单的数据:
$lexemeEntity = $builder->getData();
然后可以将其输入填充音素实体类型的初始查询中(请注意,不要忘记在定义的函数的声明中“使用”此字形):
'query_builder' => function(EntityRepository $er) use ($lexemeEntity) {
return $er->createQueryBuilder('u')
->select('p')
->from('Aleph2OmegaTranscriptionBundle:Phoneme', 'p')
->where('p.language = :language')
->setParameter('language', $lexemeEntity->getLanguage());
},
最后,需要在javascript中关闭对每个页面的初始加载的默认AJAX调用。 我通过评论来做到这一点:
//languageChange();
现在,初始页面加载都正确地填充了,但是使用AJAX对表单进行的进一步更新仍未加载所有数据,对此仍然有任何帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.