Yii2:加载模态表单并通过Ajax提交数据而无需重定向到视图

时间:2017-08-22 11:57:05

标签: ajax yii2 modal-dialog

我的Yii2项目中有两个模型。一个模型:ApartmentBuilding取决于另一个模型:Caretaker通过关系。假设我通过表单创建ApartmentModel,我从动态下拉菜单中选择caretaker。然后我意识到我需要的看护人还没有添加到数据库中,因此,我必须从ApartmentBuilding模型表单中添加看护人的详细信息,然后继续填写ApartmentBulding表单的详细信息。这是我问题的用法。

到目前为止,我已设法通过Caretaker表单中的模式启动ApartmentBulding模型表单。在提交Caretaker模型表单的详细信息后,该网站会重定向到CaretakerController的视图。但是,我需要的是能够使用我刚刚通过模态添加的看护人的新细节来刷新下拉表单,并且能够继续填写表格的其余部分。

任何帮助破解这一点都将受到赞赏。

到目前为止,这是我的代码:

ApartmentBuilding _form.php

<?php

use yii\helpers\Html;
use kartik\widgets\ActiveForm;
use app\models\Landlord;
use app\models\Caretaker;
use yii\helpers\ArrayHelper;
use yii\bootstrap\Button;
use yii\helpers\Url;

/* @var $this yii\web\View */
/* @var $model app\models\ApartmentBuilding */
/* @var $form yii\widgets\ActiveForm */
?>

<div class="apartment-building-form">

    <?php $form = ActiveForm::begin([
        'type' => ActiveForm::TYPE_HORIZONTAL,
        'formConfig' => ['labelSpan' => 3, 'deviceSize' => ActiveForm::SIZE_TINY],
    ]); ?>

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

    <?= $form->field($model, 'landlord_id')->dropDownList(ArrayHelper::map(Landlord::find()->select(['landlord_id', 'first_name', 'last_name'])->all(), 'landlord_id', 'displayName'),['class' => 'form-control inline-block', 'prompt'=>'Select Landlord']) ?>

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

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

    <?= $form->field($model, 'address')->widget(\kalyabin\maplocation\SelectMapLocationWidget::className(), [
        'attributeLatitude' => 'latitude',
        'attributeLongitude' => 'longitude',
        'googleMapApiKey' => 'YOUR_API_KEY_HERE',
    ]) ?>

    <?= $form->field($model, 'number_of_floors')->textInput() ?>

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

    <div class="form-group kv-fieldset-inline">
        <?= Html::activeLabel($model, 'caretaker_id', ['label'=>'Caretaker', 'class'=>'col-sm-3 control-label']) ?>
        <div class="col-sm-8">
            <?= $form->field($model, 'caretaker_id',['showLabels'=>false])->dropDownList(ArrayHelper::map(Caretaker::find()->select(['caretaker_id', 'first_name', 'last_name'])->all(), 'caretaker_id', 'displayName'),['class' => 'form-control inline-block', 'prompt'=>'Select Caretaker']) ?>
        </div>  
        <div class="col-sm-1">
            <?= Html::button('<i class="glyphicon glyphicon-plus"></i>', ['value'=>Url::to(['caretaker/new']), 'title' => 'Create New Caretaker', 'class' => 'btn btn-success showModalButton']) ?>
        </div>
    </div>

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

    <div class="col-sm-offset-3 col-sm-9">
        <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
        <?= Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
    </div>

    <?php ActiveForm::end(); ?>

</div>

看守_form.php

<?php

use yii\helpers\Html;
use kartik\widgets\ActiveForm;
use kartik\widgets\DatePicker;

/* @var $this yii\web\View */
/* @var $model app\models\Caretaker */
/* @var $form yii\widgets\ActiveForm */
?>

<div class="caretaker-form">

    <?php $form = ActiveForm::begin([
        'type' => ActiveForm::TYPE_HORIZONTAL,
        'formConfig' => ['labelSpan' => 3, 'deviceSize' => ActiveForm::SIZE_TINY],
    ]); ?>

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

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

    <?= $form->field($model, 'sex')->dropDownList(['Male' => 'Male', 'Female' => 'Female'],['prompt'=>'Select Sex']) ?> 

    <?= $form->field($model, 'date_of_birth')->widget(DatePicker::classname(), ['options' => ['placeholder' => 'Enter birth date ...'], 'pluginOptions' => ['autoclose'=>true, 'format' => 'yyyy-mm-dd']]) ?>

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

    <?= $form->field($model, 'mobile')->widget(\yii\widgets\MaskedInput::className(), ['mask' => '254999999999',]) ?>

    <div class="col-sm-offset-3 col-sm-9">
        <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
        <?= Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
    </div>

    <?php ActiveForm::end(); ?>

</div>

CaretakerController actionNew()

public function actionNew()
{
    $model = new Caretaker();
    $model->company_id = Yii::$app->user->identity->company_id;

    if ($model->load(Yii::$app->request->post()) && $model->save()) {
        return false;
    } else {
        return $this->renderAjax('create', [
            'model' => $model,
        ]);
    }
}

模态处理程序:

<?php
yii\bootstrap\Modal::begin([
    'headerOptions' => ['id' => 'modalHeader'],
    'id' => 'modal',
    'size' => 'modal-lg',
    //keeps from closing modal with esc key or by clicking out of the modal.
    // user must click cancel or X to close
    'clientOptions' => ['backdrop' => 'static', 'keyboard' => FALSE]
]);
echo '<div id="modalContent"><div style="text-align:center"><?= Html::img("@web/img/loading.gif");?></div></div>';
yii\bootstrap\Modal::end();
?>

模态-popup.js

$(function(){
    //get the click of modal button to create / update item
    //we get the button by class not by ID because you can only have one id on a page and you can
    //have multiple classes therefore you can have multiple open modal buttons on a page all with or without
    //the same link.
//we use on so the dom element can be called again if they are nested, otherwise when we load the content once it kills the dom element and wont let you load another modal on click without a page refresh
      $(document).on('click', '.showModalButton', function(){
         //check if the modal is open. if it's open just reload content not whole modal
        //also this allows you to nest buttons inside of modals to reload the content it is in
        //the if else are intentionally separated instead of put into a function to get the 
        //button since it is using a class not an #id so there are many of them and we need
        //to ensure we get the right button and content. 
        // if ($('#modal').data('bs.modal').isShown) 
        if ($("#modal").data('modal') && $("#modal").data('modal').isShown){
            $('#modal').find('#modalContent')
                    .load($(this).attr('value'));
            //dynamically set the header for the modal
            document.getElementById('modalHeader').innerHTML = '<h4>' + $(this).attr('title') + '</h4>';
        } else {
            //if modal isn't open; open it and load content
            $('#modal').modal('show')
                    .find('#modalContent')
                    .load($(this).attr('value'));
             //dynamiclly set the header for the modal
            document.getElementById('modalHeader').innerHTML = '<h4>' + $(this).attr('title') + '</h4>';
        }
    });
});

$(function(){
//load the current page with the conten indicated by 'value' attribute for a given button.
   $(document).on('click', '.loadMainContent', function(){
            $('#main-content').load($(this).attr('value'));
    });
});

注意 modal handler codemodal-popup.js可以被其他几种模式重用,例如视图和创建表单。模态处理程序的代码位于layouts文件夹的main.php中。

1 个答案:

答案 0 :(得分:0)

我已经设法通过以下方式解决了这个问题(更多的想法仍然受到欢迎,我知道可以有更完美的方式来做到这一点):

我将以下Javascript代码添加到看管人_form.php

<?php
$this->registerJs("$('#createcaretaker').click(function() {
    var firstName = $('#caretaker-first_name').val();
    var lastName = $('#caretaker-last_name').val();
    var sex = $('#caretaker-sex').val();
    var dOB = $('#caretaker-date_of_birth').val();
    var address = $('#caretaker-address').val();
    var mobile = $('#caretaker-mobile').val();
    $('#modal').modal('hide');
    $.get('new?firstName='+firstName+'&lastName='+lastName+'&sex='+sex+'&dOB='+dOB+'&address='+address+'&mobile='+mobile, function(success){
        $('.refreshcaretaker').html(success);
    });
});");
?>

然后,同一表单上的提交按钮,我将其更改为:

<button id="createcaretaker" type="button" class="btn btn-success">Create</button>

因此,按钮ID能够触发上面的Javascript代码将数据发送到服务器端。

然后我在ApartmentBuilding控制器中创建了一个控制器动作来处理数据输入,如下所示:

public function actionNew($firstName, $lastName, $sex, $dOB, $address, $mobile)
{
    $model = new Caretaker();
    $model->company_id = Yii::$app->user->identity->company_id;

    if ($firstName != '0' && $lastName != '0' && $sex != '0' && $dOB != '0' && $address != '0' && $mobile != '0') {
        $model->first_name = $firstName;
        $model->last_name = $lastName;
        $model->sex = $sex;
        $model->date_of_birth = $dOB;
        $model->address = $address;
        $model->mobile = $mobile;
        $model->save();

        $caretakers = Caretaker::find()->all();
        foreach ($caretakers as $caretaker) {
            echo '<option value="'.$caretaker->caretaker_id.'">'.$caretaker->displayName.'</option>';
        }
    } else {
        return $this->renderAjax('caretaker_create', [
            'model' => $model,
        ]);
    }
}

完成后,我更改了父表单的下拉条目,以便在提交模式表单时通过ajax刷新其值,以创建看守模型,如下所示:

<?= $form->field($model, '[{$i}]caretaker_id',['showLabels'=>false])->dropDownList(ArrayHelper::map(Caretaker::find()->select(['caretaker_id', 'first_name', 'last_name'])->all(), 'caretaker_id', 'displayName'),['class' => 'form-control inline-block refreshcaretaker', 'prompt'=>'Select Caretaker']) ?>

请注意提交模式时由refreshcaretaker代码触发的Javascript类。

以下link更多地讨论了在Yii2中使用模态表单。