Yii2页面加载报错Undefined variable $searchModel,需仅点击筛选后创建该变量
解决Yii2中「Undefined variable $searchModel」错误及按需筛选实现
问题根源
加载首页时触发actionIndex,但该方法未向视图传递表单依赖的$searchModel、$genres、$authors变量,导致视图渲染表单时报错。另外你希望仅点击「Filtering」按钮后才执行筛选逻辑,而非初始化阶段就执行,需调整控制器逻辑,将列表展示与筛选逻辑合并到同一action中,这也是Yii2的常规做法。
解决方案:合并Action逻辑,按需执行筛选
修改控制器代码
将actionIndex和actionFilter的逻辑合并,仅在检测到筛选请求时应用过滤条件:
private function actionPagination($query) { $count = $query->count(); $pagination = new Pagination([ 'defaultPageSize' => 10, 'totalCount' => $count, ]); $books = $query ->orderBy('id') ->offset($pagination->offset) ->limit($pagination->limit) ->all(); return [$books, $pagination]; } public function actionIndex() { $query = Books::find(); // 初始化表单所需的下拉选项数据 $genres = Genres::find()->select(['genre_name', 'id'])->orderBy('genre_name')->indexBy('id')->column(); $authors = Authors::find()->select(['concat(first_name, " ", last_name)', 'id'])->orderBy('id')->column(); $authors = array_combine(range(1, count($authors)), $authors); // 初始化搜索模型,用于渲染表单(必须存在,否则表单无法渲染) $searchModel = new Books(); $requestParams = Yii::$app->request->queryParams; // 仅在点击筛选按钮(即表单提交后)才执行筛选逻辑 if ($searchModel->load($requestParams) && Yii::$app->request->getIsGet()) { if ($searchModel->year_filter) { $query->andWhere(['year' => $searchModel->year_filter]); } if ($searchModel->genre_filter) { $query->andWhere(['genre_id' => $searchModel->genre_filter]); } if ($searchModel->author_filter) { $query->joinWith('links') ->andWhere(['links.author_id' => $searchModel->author_filter]); } } // 处理分页 list($books, $pagination) = $this->actionPagination($query); return $this->render('index', [ 'books' => $books, 'pagination' => $pagination, 'totalPages' => max(1, ceil($pagination->totalCount / $pagination->pageSize)), 'authors' => $authors, 'genres' => $genres, 'searchModel' => $searchModel, ]); }
修改视图表单代码
将表单action指向index,并调整重置按钮逻辑,点击后清空筛选参数并返回列表页:
<?php $form = ActiveForm::begin([ 'action' => ['index'], 'method' => 'get', 'options' => ['id' => 'filter-form'] ]); ?> <?= $form->field($searchModel, 'year_filter')->textInput(['id' => 'year-filter-input']) ?> <?= $form->field($searchModel, 'genre_filter')->dropDownList( $genres, [ 'prompt' => 'All genres', 'id' => 'genre-filter-select' ] ) ?> <?= $form->field($searchModel, 'author_filter')->dropDownList( $authors, [ 'prompt' => 'All authors', 'id' => 'author-filter-select' ] ) ?> <div class="form-group"> <?= Html::submitButton('Filtering', ['class' => 'btn btn-primary']) ?> <?= Html::a('Reset filter', ['index'], [ 'class' => 'btn btn-outline-secondary reset-filter' ]) ?> </div> <?php ActiveForm::end(); ?>
关键说明
- 必须初始化
$searchModel:视图中的ActiveForm依赖$searchModel来渲染字段,所以即使未点击筛选按钮,也需要初始化该变量,否则会报变量未定义错误。我们仅控制筛选逻辑的执行时机,而非模型的初始化时机。 - 合并Action的优势:避免重复代码,同时保证分页与筛选逻辑兼容(筛选后的结果依然可以正常分页)。
- 重置按钮优化:使用
Html::a跳转回无参数的index页面,直接清空所有筛选条件,比JS重置更可靠。
内容的提问来源于stack exchange,提问作者Kadaver99
相关产品推荐
相关产品推荐

