doushishi6513 2016-11-11 19:38
浏览 40
已采纳

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

For example we have this ActiveForm implementation in a sample view:

<?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(); ?>

Now, I want to add more ActiveField / ActiveForm fields inside this form and place them in the #additional-form-fields element with Ajax, I'd do a simple jQuery callback:

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

And the action additional-fields inside SiteController would be something as:

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!
    ]);
}

And this works perfectly, only if I don't use any other ActiveField fields inside this action's view:

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

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

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

Of course, I have to pass or instatiate $form somehow in this view, but it's NOT an option to use another ActiveForm::begin() / ActiveForm::end() anywhere inside this view since it will create another <form> tag and thus when I inject the Ajax response, I'll end up with with a <form> inside a <form> ...

Now, my question is as follows: Since I want to use ActiveForm, how can I share an instance of the ActiveForm through out multiple requests?

Is it doable / possible, if so, please help me realize how?

So far I have tried to put $form inside a session, but that's definitelly not working and not an option. Different than that, I've tried when passing parameters to renderAjax:

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

In this case I get the following:

  1. Form fields are created as they should with appopriate names and id's.
  2. jQuery is loaded again (at the bottom of the response: <script src="..."> ... you get the idea)
  3. I don't get the generated JavaScript for validation.

Is there anyway to share an instance of $form?

  • 写回答

1条回答 默认 最新

  • dongxiong5546 2016-11-11 20:05
    关注

    Okay, I have manage to do this, so I'll post the solution here and I'll open an issue on Github - might be useful in future versions.

    1. Updates in yii2\widgets\ActiveForm.php

    I've added a following property to the ActiveForm class:

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

    And I've changed run() method into this (check for // <-- 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
    }
    

    Thus if we instantiate a form like this:

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

    It will not echo a <form> tag, but will render all ActiveField items and it will create their respective JavaScript/jQuery validators if $this->enableClientScript = true;.

    2. Updates in my local view/file

    After applying the previous fix in the base class, I needed to do the following in my view:

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

    I had to pass the id parameter since every next instance of the ActiveForm class is incremented by 1, and I want my JavaScript/jQuery validators to be applied to the parent form, which by default starts from 0 -> w0.

    And this is what did the trick!

    Here's the Github issue as well: https://github.com/yiisoft/yii2/issues/12973

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝
  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号
  • ¥50 安装pyaudiokits失败
  • ¥15 计组这些题应该咋做呀
  • ¥60 更换迈创SOL6M4AE卡的时候,驱动要重新装才能使用,怎么解决?
  • ¥15 让node服务器有自动加载文件的功能
  • ¥15 jmeter脚本回放有的是对的有的是错的
  • ¥15 r语言蛋白组学相关问题