使用ajax在yii2中向表单添加更多字段

Kul*_*ngi 13 php ajax yii2

我有一个Yii2 form:

<?php $form = ActiveForm::begin(['id' => 'que']); ?>
    <?php echo $form->field($model, 'type')
            ->dropDownList($questionTypes, [
                'class' => 'form-control ng-pristine ng-valid ng-touched',
                'prompt' => 'Select question type',
                'ng-model' => 'que.type',
                'ng-change' => 'addAnswerOptions(que);',
        ]);
    ?>
<?php ActiveForm::end(); ?>
Run Code Online (Sandbox Code Playgroud)

根据选定的下拉值,我必须在同一模型的相同形式中添加更多字段.将添加哪些字段完全取决于下拉值.

我怎样才能做到这一点?

D.M*_*ill 5

根据您提供的信息,我建议您这样做.

1)动态 - 没有AJAX

使用您需要的所有字段构建表单,只需按照以下单独包含每个"方案" div:

<?php $form = ActiveForm::begin(['id' => 'que']); ?>
    <?php echo $form->field($model, 'type')
            ->dropDownList($questionTypes, [
                'class' => 'form-control ng-pristine ng-valid ng-touched',
                'prompt' => 'Select question type',
                'ng-model' => 'que.type',
                'ng-change' => 'addAnswerOptions(que);',
        ]);
    ?>
    <div class="form-option" data-type="class" style="display:none;">
        <?php
            // ... fields here for case type == class
        ?>
    </div>
    <div class="form-option" data-type="prompt" style="display:none;">
        <?php
            // ... fields here for case type == prompt
        ?>
    </div>
    <div class="form-option" data-type="ng-model" style="display:none;">
        <?php
            // ... fields here for case type == ng-model
        ?>
    </div>
    <div class="form-option" data-type="ng-change" style="display:none;">
        <?php
            // ... fields here for case type == ng-change
        ?>
    </div>
<?php ActiveForm::end(); ?>
Run Code Online (Sandbox Code Playgroud)

然后,您将需要注册Javascript代码以显示正确的块,具体取决于所选的下拉选项.Bellow是使用JQuery的一个例子:

$(document).ready(function(){
    $('select.form-control').change(function(){
        $('.form-option').hide(); // hide all options if an option is showing
        var index = $('select.form-control').index();
        $('div[data-type="'+index+'"]').show(); //show the correct fields
    });
});
Run Code Online (Sandbox Code Playgroud)

如果您打算这样做,我建议您对表单使用AJAX验证.它将避免您在页面重新加载时遇到麻烦.

提交表单后,您必须处理控制器中的每个案例.您可以使用一组简单的if()语句来检查下拉值.或者,您可以根据下拉值设置模型验证方案.

这样做的好处是它会更快,你将能够利用ActiveForm.缺点是您需要知道要为每个选项显示哪些字段,并且n当您不知道多少字段时,它不允许累积字段数n.

2)使用Ajax

如果您想使用ajax调用来加载额外的表单字段,您将必须controller/action组合将返回字段,具体取决于您在GET

此操作将生成要显示的字段的html.这是一个例子:

public function actionAjaxFields($type)
{
    $html = '';
    if($type == "class")
    {
        $html .= Html::textInput('Field1');
    }
    elseif($type == "prompt")
    {
        $html .= Html::textInput('Field2');
    }
    else
    {
        // etc...
    }
    return $html;
}
Run Code Online (Sandbox Code Playgroud)

请注意,您还可以将用户ID传递给此方法,这样您就可以生成模型并使用Html::activeTextInput(),但是您将无法利用这些ActiveForm功能.

完成此操作后,您应该将函数绑定到下拉列表的更改事件,并使用以下内容:

var responsePromise = $http.get("controller/ajax-fields", {params: {type: <type-from-dropdown>}});
Run Code Online (Sandbox Code Playgroud)

不幸的是我对angularjs知之甚少,所以这是我可以在javascript方面提供帮助的程度.我确信google/stackoverflow上有关于绑定事件和将数据附加到angularjs中的DOM的信息足以让你运行.

如果我能在Yii2方面获得任何额外帮助,请告诉我.