如何在Yii 2中跨Ajax请求使用ActiveForm实例?

时间:2016-11-11 19:38:35

标签: php jquery ajax yii yii2

例如,我们在示例视图中有这个ActiveForm实现:

<?php $form = ActiveForm::begin(); ?>

    <?=$form->field($model, 'first_name')->textInput(['maxlength' => true]); ?>

    <?=$form->field($model, 'last_name')->textInput(['maxlength' => true]); ?>

    <div id="additional-form-fields"></div>

    <a href="#" id="load-additional-form-fields">
        Load more fields
    </a>

<?php ActiveForm::end(); ?>

现在,我想在此表单中添加更多ActiveField / ActiveForm个字段,并将它们放在带有Ajax的#additional-form-fields元素中,我会做一个简单的jQuery回调:

$('#load-additional-form-fields').click(function() {
    $.get('/site/additional-fields', {}, function(data) {
        $('#additional-form-fields').html( data );
    });
});

additional-fields内的操作SiteController可能是:

public function actionAdditionalFields() {
    $model = new User;

    return $this->renderAjax('additional-fields', [
        'model' => $model,
        // I could pass a 'form' => new ActiveForm, here, but it's a big NO-NO!
    ]);
}

只有当我在此操作视图中不使用任何其他ActiveField字段时,这才能完美运行:

<?=$form->field($model, 'biography')->textInput(['maxlength' => true]); ?>

<?=$form->field($model, 'country')->textInput(['maxlength' => true]); ?>

<?=$form->field($model, 'occupation')->textInput(['maxlength' => true]); ?>

当然,我必须在此视图中以某种方式传递或设置$form,但在此视图中的任何位置都不能使用其他ActiveForm::begin() / ActiveForm::end(),因为它会创建另一个<form>标记,因此当我注入Ajax响应时,我最终会在<form>内找到<form> ...

现在,我的问题如下:由于我想使用ActiveForm,如何通过多个请求共享ActiveForm的实例?

是可行的/可能的,如果是的话,请帮我理解如何?

到目前为止,我已经尝试将$form放入会话中,但这肯定不起作用而不是一个选项。与此不同的是,我在将参数传递给renderAjax时尝试过:

[
    'model' => $model,
    'form' => new ActiveForm,
]

在这种情况下,我得到以下内容:

  1. 使用适当的名称和ID来创建表单字段。
  2. 再次加载jQuery(在响应的底部:<script src="..."> ...你明白了)
  3. 我没有获得生成的JavaScript进行验证。
  4. 是否有共享$form的实例?

1 个答案:

答案 0 :(得分:1)

好的,我已经设法做到这一点,所以我将在这里发布解决方案,我将在Github上打开一个问题 - 在将来的版本中可能会有用。

1。 yii2\widgets\ActiveForm.php

中的更新

我在ActiveForm类中添加了以下属性:

/**
 * @var boolean whether to echo the form tag or not
 */
public $withFormTag = true;

我已将run()方法改为此(检查// <-- added):

public function run()
{
    if (!empty($this->_fields)) {
        throw new InvalidCallException('Each beginField() should have a matching endField() call.');
    }

    $content = ob_get_clean();

    if($this->withFormTag) { // <-- added
        echo Html::beginForm($this->action, $this->method, $this->options);
    } // <-- added

    echo $content;

    if ($this->enableClientScript) {
        $id = $this->options['id'];
        $options = Json::htmlEncode($this->getClientOptions());
        $attributes = Json::htmlEncode($this->attributes);
        $view = $this->getView();
        ActiveFormAsset::register($view);
        $view->registerJs("jQuery('#$id').yiiActiveForm($attributes, $options);");
    }

    if($this->withFormTag) { // <-- added
        echo Html::endForm();
    } // <-- added
}

因此,如果我们实例化一个这样的表格:

$form = ActiveForm::begin([
    'withFormTag' => false,
]);

它不会echo <form>标记,但会呈现所有ActiveField项目,如果$this->enableClientScript = true;,它将创建各自的JavaScript / jQuery验证程序。

2。我本地视图/文件中的更新

在基类中应用上一个修复后,我需要在我的视图中执行以下操作:

<?php $form = ActiveForm::begin([
    'withFormTag' => false,
    'id' => 'w0',
]); ?>

我必须传递id参数,因为ActiveForm类的每个下一个实例都会增加1,我希望我的JavaScript / jQuery验证器应用于父表单,默认情况下从0开始 - &gt; w0

这就是诀窍!

以下是Github问题:https://github.com/yiisoft/yii2/issues/12973