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

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

报告相同问题?

悬赏问题

  • ¥50 adb连接不到手机是怎么回事?
  • ¥15 vs2022无法联网
  • ¥15 TCP的客户端和服务器的互联
  • ¥15 VB.NET操作免驱摄像头
  • ¥15 笔记本上移动热点开关状态查询
  • ¥85 类鸟群Boids——仿真鸟群避障的相关问题
  • ¥15 CFEDEM自带算例错误,如何解决?
  • ¥15 有没有会使用flac3d软件的家人
  • ¥20 360摄像头无法解绑使用,请教解绑当前账号绑定问题,
  • ¥15 docker实践项目