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

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

报告相同问题?

悬赏问题

  • ¥15 Multisim仿真设计地铁到站提醒电路
  • ¥15 怎么用一个500W电源给5台60W的电脑供电
  • ¥15 请推荐一个轻量级规则引擎,配合流程引擎使用,规则引擎负责判断出符合规则的流程引擎模板id
  • ¥15 Excel表只有年月怎么计算年龄
  • ¥50 资源管理器无法使用且一直崩溃重启
  • ¥15 用sql语句完成下列问题
  • ¥50 yalmip+Gurobi 求解线性规划
  • ¥15 微信开发者工具/云函数/数据库
  • ¥15 Torch not compiled with CUDA enabled
  • ¥15 三种节点编号优化算法比较