Yii2 內建 yii\bootstrap\Modal (或 yii\bootstrap5\Modal) 封裝了 Bootstrap Modal,支援 AJAX 遠端載入內容、表單驗證提交與 GridView 列表操作。本文完整示範建立、載入、提交、關閉的生命週期處理。
<?php
use yii\helpers\Html;
use yii\bootstrap\Modal;
use yii\helpers\Url;
// 1. 觸發按鈕
echo Html::a('建立新項目', '#', [
'id' => 'create-btn',
'class' => 'btn btn-success',
'data-toggle' => 'modal',
'data-target' => '#create-modal',
'data-url' => Url::toRoute(['create']), // 可選:儲存 URL 供 JS 使用
]);
// 2. Modal 容器 (放在視圖檔案底部)
Modal::begin([
'id' => 'create-modal',
'title' => '<h4>建立新項目</h4>',
'headerOptions' => ['class' => 'bg-primary text-white'],
'footer' => Html::a('關閉', '#', ['class' => 'btn btn-secondary', 'data-dismiss' => 'modal']),
'size' => Modal::SIZE_LARGE, // 或 SIZE_SMALL, 預設
'clientOptions' => [
'backdrop' => 'static', // 點擊背景不關閉
'keyboard' => false, // ESC 不關閉
],
]);
Modal::end();
<?php // 在 Modal::begin() 之後、Modal::end() 之前註冊 JS $requestUrl = Url::toRoute(['create']); $js = <<載入中...
<?php // 繼續在同一個視圖檔案註冊提交函式 $js = <<' + messages[0] + '
<?php
// SiteController.php
public function actionCreate()
{
$model = new Project(); // ActiveRecord 模型
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
if ($model->validate() && $model->save()) {
return ['success' => true, 'id' => $model->id];
} else {
return ['success' => false, 'errors' => $model->getErrors()];
}
}
// 非 AJAX 或首次載入:渲染部分視圖 (無 layout)
return $this->renderAjax('_form', ['model' => $model]);
}
<?php
use yii\widgets\ActiveForm;
use yii\helpers\Html;
$form = ActiveForm::begin([
'id' => 'project-form',
'enableAjaxValidation' => true, // 可選:支援欄位級即時驗證
'validationUrl' => Url::toRoute(['validate']), // 需實作 validate action
]);
?>
<div class="modal-body">
<?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'description')->textarea(['rows' => 4]) ?>
<?= $form->field($model, 'status')->dropDownList([1 => '啟用', 0 => '停用']) ?>
</div>
<div class="modal-footer">
<?= Html::submitButton('儲存', ['class' => 'btn btn-primary']) ?>
<?= Html::a('取消', '#', ['class' => 'btn btn-secondary', 'data-dismiss' => 'modal']) ?>
</div>
<?php ActiveForm::end(); ?>
<?php
use yii\grid\GridView;
use yii\helpers\Html;
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'id' => 'gridview-pjax', // 對應 Pjax 容器 ID
'columns' => [
'id',
'name',
'status:boolean',
[
'class' => 'yii\grid\ActionColumn',
'template' => '{view} {update} {delete}',
'buttons' => [
'update' => function ($url, $model, $key) {
return Html::a('', '#', [
'class' => 'btn-update',
'data-url' => $url,
'data-id' => $key,
'title' => '編輯',
]);
},
'delete' => function ($url, $model, $key) {
return Html::a('', '#', [
'class' => 'btn-delete',
'data-url' => $url,
'data-id' => $key,
'title' => '刪除',
'data-confirm' => '確定刪除?',
]);
},
],
],
],
]);
<?php $js = <<編輯項目'); \$modal.modal('show'); // 載入表單 (同上 AJAX 邏輯) // ... }); // 刪除按鈕 (AJAX 刪除) $(document).on('click', '.btn-delete', function (e) { e.preventDefault(); if (!confirm($(this).data('confirm'))) return; var \$btn = $(this); var url = \$btn.data('url'); $.post(url, function (response) { if (response.success) { $.pjax.reload({container: '#gridview-pjax'}); } else { alert(response.message || '刪除失敗'); } }, 'json'); }); JS; $this->registerJs($js, \yii\web\View::POS_READY);
success 回呼中重新綁定 submit 事件。Pjax::begin(['id' => 'gridview-pjax']) 實現無刷新刷新。errors 陣列,JS 需對應欄位顯示 is-invalid 樣式。data-bs-* (BS5) 或 data-* (BS4) 屬性前綴。