如何在Ajax请求中使用ActiveForm实例



例如,我们在示例视图中有这个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 );
    });
});

SiteController中的动作additional-fields应该是:

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验证

是否有办法共享$form的实例?

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

1。yii2widgetsActiveForm.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项目,它将创建各自的JavaScript/jQuery验证器,如果$this->enableClientScript = true;

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

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

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

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

这就是成功的秘诀!

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

最新更新