提交表单后,子表单值在接收端显示为 null

Posted

技术标签:

【中文标题】提交表单后,子表单值在接收端显示为 null【英文标题】:Subform values are showing up as null on the receiving end after form submit 【发布时间】:2019-02-11 03:13:21 【问题描述】:

我已经构建了一个可以正常提交的表单,但是当我在控制器中查看子表单值时,它们在接收端都以 null 结束。

这是我的UserProfileType 表单,基于Userclass。具体来说,我们正在查看的子表单是subscriptionTier1subscriptionTier1subscriptionTier1

class UserProfileType extends AbstractType

    public function buildForm(FormBuilderInterface $builder, array $options)
    
        $builder
            ->add('firstName', TextType::class)
            ->add('lastName', TextType::class)
            ->add('email', EmailType::class)

            // etc... I'll keep out the unimportant fields

            // here are the subforms whose values show up as null on the back end
            ->add('subscriptionTier1', UserSubscriptionTierType::class, [
                'required' => false,
                'mapped' => false
                ])
            ->add('subscriptionTier2', UserSubscriptionTierType::class, [
                    'required' => false,
                    'mapped' => false
                ])
            ->add('subscriptionTier3', UserSubscriptionTierType::class, [
                    'required' => false,
                    'mapped' => false
                ])
            ->add('save', SubmitType::class, [
                'attr' => ['class' => 'save'],
            ])
        ;

public function configureOptions(OptionsResolver $resolver)

    $resolver->setDefaults(array(
            'data_class' => User::class,
            'mode' => null
        )
    );

这是我的UserSubscriptionTierType 表单类型类的样子:

class UserSubscriptionTierType extends AbstractType

    public function buildForm(FormBuilderInterface $builder, array $options)
    
        $builder
            ->add('name', TextType::class, [
                'attr' => [
                    'maxlength' => 25
                ]
            ])
            ->add('price', ChoiceType::class, [
                'choices' => [
                    '$10 per month' => 10,
                    '$20 per month' => 20,
                    '$30 per month' => 30
                ]
            ])
            ->add('description', TextareaType::class)
            ->add('messaging', CheckboxType::class, [
                'required' => false
            ])
        ;
    

    public function configureOptions(OptionsResolver $resolver)
    
        $resolver->setDefaults(array(
            'data_class' => UserSubscriptionTier::class,
        ));
    

如下图所示,subform subscriptionTier1的名称、价格、描述值都是在前端设置的:

这是subscriptionTier1 子表单的树枝代码的样子:

    <div class="row justify-content-center w-100 ml-0 mr-0 mt-3 tier tier-1" >
        <div class="col-lg-6 mt-1">
            <div class="form-group form-control-lg w-100">
                <label for="firstname" class="mb-2">Tier 1 Name</label>
                 form_widget(form.subscriptionTier1.name,  'attr': 'class': 'form-control') 
            </div>
        </div>
        <div class="col-lg-6 mt-1">
            <div class="form-group form-control-lg w-100">
                <label for="tier1price" class="mb-2">Tier 1 Price</label>
                 form_widget(form.subscriptionTier1.price,  'attr': 'class': 'form-control') 
            </div>
        </div>
        <div class="col-lg-12 mt-3">
            <div class="form-group form-control-lg w-100">
                <label for="bio" class="mb-2">Tier 1 Description
                    <sup class="text-danger">*</sup>
                </label>
                 form_widget(form.subscriptionTier1.description,  'attr': 'class': 'form-control border-box', 'rows':'8') 
            </div>
        </div>
        <div class="col-lg-12">
            <div class="form-group form-control-lg w-100">
                <div class="form-check">
                    <label class="form-check-label">
                         form_widget(form.subscriptionTier1.messaging,  'attr': 'class': 'form-control form-check-input') 
                        <span class="form-check-sign"></span>
                        Enable Messaging
                    </label>
                </div>
            </div>
        </div>
    </div>

这里是接收端的代码,控制器:

public function saveProfileAction(Request $request)

    $user = $this->getUser();

    $form = $this->createForm(UserProfileType::class, $user);
    $form->handleRequest($request);

dump($form->get('subscriptionTier1')->getData()); 

所以在调试中,如果我只转储第一个表单subscriptionTier1,你可以看到值都是null

ProfileController.php on line 269:
Form #2235 ▼
  -config: FormBuilder #2236 ▶
  -parent: Form #2112 ▶
  -children: OrderedHashMap #2237 ▶
  -errors: []
  -submitted: true
  -clickedButton: null
  -modelData: UserSubscriptionTier #2280 ▼
    -id: null
    -posts: ArrayCollection #2323 ▶
    -subscriptions: null
    -name: null         // Don't understand why this is null 
    -price: null        // Don't understand why this is null 
    -description: null  // Don't understand why this is null 
    -tierNumber: null
    -versionNumber: null
    -messaging: false
    -user: null
    +"subsciptions": ArrayCollection #2089 ▶
  
  -normData: UserSubscriptionTier #2280 ▶
  -viewData: UserSubscriptionTier #2280 ▶
  -extraData: []
  -transformationFailure: null
  -defaultDataSet: true
  -lockSetData: false

有人知道为什么这些值没有传递到后端(或被清空)吗?

【问题讨论】:

如果它不在Request 对象中(您也可以检查原始$_POST 数据确定),那么您应该检查呈现的html。如果数据没有随请求一起提供,那么您在后端就无能为力了。 【参考方案1】:

由于UserProfileType 表单类型的data_class 选项设置为User 类,模型数据将是User 类的实例,并且由于User 类没有像@987654327 这样的字段@ 等,这些不会出现在您的模型数据中。

相反,您可以像这样在控制器中的表单中访问未映射的字段:

$subscriptionTier1 = $form->get('subscriptionTier1')->getData();

文档here

编辑:您只能在处理完表单并且提交表单后才能访问subscriptionTier1等的值,否则将为null:

public function saveProfileAction(Request $request)

    $user = $this->getUser();

    $form = $this->createForm(UserProfileType::class, $user);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) 
        $subscriptionTier1 = $form->get('subscriptionTier1')->getData();
        dump($subscriptionTier1);
    

【讨论】:

嗨 iirxs,谢谢,这是一个很大的帮助。现在表单值全部为空。我将不得不编辑问题。但这仍然是一个很大的帮助。 我已经编辑了我的答案以帮助您更好地理解它【参考方案2】:

我不知道这是否只是一种解决方法,或者这实际上是最佳实践方式,但这是我如何让它工作的:

我有以下子表单标签: form_start(form.subscriptionTier1) etc... form_end(form.subscriptionTier1)

这将嵌套表单标签。显然,您不允许嵌套这样的表单。

因此,为所有 subscriptionTier1subscriptionTier1subscriptionTier1 取出 form_start(form.subscriptionTier1) form_end(form.subscriptionTier1) ,然后检查请求对象中的表单值。

【讨论】:

以上是关于提交表单后,子表单值在接收端显示为 null的主要内容,如果未能解决你的问题,请参考以下文章

关于前端form提交表单,后端springmvc接收的问题

为什么Django引发IntegrityError:列“user_id”中的null值在提交表单时违反了非空约束?

js 提交的表单后如何在本页面接收返回值

在使用openfeign做表单提交时,HttpServletRequest传参后服务端接收不到数据的问题

在使用openfeign做表单提交时,HttpServletRequest传参后服务端接收不到数据的问题

在使用openfeign做表单提交时,HttpServletRequest传参后服务端接收不到数据的问题