You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:03:48