Yii2基于Gii实现带父级ID的多类别下拉框开发求助
Yii2 实现产品表单联动多级类别下拉选择(基于Gii生成代码)
我来帮你一步步搞定这个Yii2里的联动类别下拉选择功能,结合你用Gii生成的代码,咱们从模型、控制器到视图逐一完善,实现选择parent_id为0或1的父类别时,动态加载对应子类别:
1. 完善 Category 模型
首先在Category模型里添加两个方法,分别用来获取顶级类别(parent_id为0或1)和指定父类别的子类别:
// models/Category.php use yii\db\ActiveQuery; class Category extends \yii\db\ActiveRecord { // ... Gii生成的其他代码 ... /** * 获取parent_id为0或1的顶级类别 * @return ActiveQuery */ public function getCategoryParents() { return $this->find() ->where(['in', 'parent_id', [0, 1]]) ->orderBy('name ASC') ->all(); } /** * 根据父类别ID获取子类别列表 * @param int $parentId * @return array */ public static function getChildrenCategories($parentId) { return static::find() ->where(['parent_id' => $parentId]) ->orderBy('name ASC') ->select(['id', 'name']) ->indexBy('id') ->column(); } }
2. 完善 Product 控制器的 actionCreate 方法
把你给出的控制器片段补全,获取顶级类别并传递到视图,同时处理表单提交逻辑:
// controllers/ProductController.php use yii\helpers\ArrayHelper; public function actionCreate() { $model = new Product(); $categoryModel = new Category(); $time = time(); $model->created_at = $time; $model->updated_at = $time; // 获取符合要求的顶级类别 $parentCategories = $categoryModel->getCategoryParents(); // 处理表单提交 if ($model->load(Yii::$app->request->post()) && $model->save()) { return $this->redirect(['view', 'id' => $model->id]); } return $this->render('create', [ 'model' => $model, 'parentCategories' => $parentCategories, ]); }
注意:如果需要在actionUpdate里也实现联动,只需要在更新方法里添加同样的$parentCategories获取逻辑,并且如果产品已有子类别,还要在视图里预加载对应父类别的子类别(可以在JS里初始化时触发一次change事件)。
3. 完善产品表单视图(create.php)
在Gii生成的表单视图里添加两个下拉框,通过JavaScript实现联动效果:
// views/product/create.php use yii\helpers\Html; use yii\widgets\ActiveForm; use yii\helpers\Url; use yii\helpers\ArrayHelper; <?php $form = ActiveForm::begin(); ?> <!-- 父类别下拉选择框 --> <?= $form->field($model, 'parent_category_id')->dropDownList( ArrayHelper::map($parentCategories, 'id', 'name'), [ 'prompt' => '请选择父类别', 'id' => 'parent-category', ] ) ?> <!-- 子类别容器,初始隐藏 --> <div id="child-category-container" style="display:none;"> <?= $form->field($model, 'category_id')->dropDownList( [], // 初始为空,通过AJAX加载 [ 'prompt' => '请选择子类别', 'id' => 'child-category', ] ) ?> </div> <!-- 这里放Gii生成的其他产品字段,比如名称、价格等 --> <div class="form-group"> <?= Html::submitButton('保存产品', ['class' => 'btn btn-success']) ?> </div> <?php ActiveForm::end(); ?> <!-- 联动逻辑的JavaScript --> <?php $this->registerJs(" // 监听父类别选择变化 $('#parent-category').on('change', function() { const parentId = $(this).val(); const childContainer = $('#child-category-container'); const childSelect = $('#child-category'); if (parentId) { // AJAX请求获取子类别 $.ajax({ url: '" . Url::to(['category/get-children']) . "', type: 'GET', data: {parentId: parentId}, success: function(data) { // 清空并重新填充子类别选项 childSelect.empty().append('<option value=\"\">请选择子类别</option>'); $.each(data, function(id, name) { childSelect.append(`<option value=\"${id}\">${name}</option>`); }); childContainer.show(); }, error: () => { childContainer.hide(); childSelect.empty(); } }); } else { // 未选择父类别时隐藏子类别容器 childContainer.hide(); childSelect.empty(); } }); // 如果是更新页面,初始化时自动加载已有父类别的子类别 const initialParentId = $('#parent-category').val(); if (initialParentId) { $('#parent-category').trigger('change'); } "); ?>
4. 添加 Category 控制器的AJAX接口
新增一个动作用来响应子类别获取的AJAX请求:
// controllers/CategoryController.php use yii\web\Response; public function actionGetChildren($parentId) { // 设置响应格式为JSON Yii::$app->response->format = Response::FORMAT_JSON; // 返回对应父类别的子类别列表 return Category::getChildrenCategories($parentId); }
5. 补充 Product 模型的验证规则(可选)
如果需要确保选择父类别后必须选子类别,可以在Product模型里添加条件验证:
// models/Product.php public function rules() { return array_merge(parent::rules(), [ // 父类别和子类别为整数类型 [['parent_category_id', 'category_id'], 'integer'], // 选择父类别后,子类别为必填项 [['category_id'], 'required', 'when' => function($model) { return !empty($model->parent_category_id); }, 'whenClient' => "function(attribute, value) { return $('#parent-category').val() !== ''; }" ], ]); }
这样一套下来,就能实现你需要的联动多级类别选择功能了,测试一下选择不同的顶级类别,子类别下拉框会自动加载对应的选项~
内容的提问来源于stack exchange,提问作者Ice
相关产品推荐
相关产品推荐

