Grocery CRUD依赖下拉多选及批量插入至同表技术问询
实现Grocery CRUD支持全选的多选依赖下拉并保存至同一表
嘿,针对你需要在Grocery CRUD里实现支持全选的多选依赖下拉、并将选中数据存入同一数据表的需求,我整理了一套可行的解决方案,一步步来:
1. 提前准备数据表字段
首先确保你的目标表tbl_donation_ppl中有一个字段用来存储多选结果,比如fld_selected_items,建议用TEXT或JSON类型(TEXT存逗号分隔ID,JSON存数组更规范)。
2. 替换默认关联字段为自定义多选下拉
Grocery CRUD原生的set_relation只支持单选,所以我们需要用回调函数自定义表单字段,同时加入全选/取消全选按钮:
$this->load->library('grocery_CRUD'); $crud = new grocery_CRUD(); $crud->set_theme('flexigrid'); $crud->set_table('tbl_donation_ppl'); // 保留原有关联字段 $crud->set_relation('fld_home_id', 'tbl_home_name', 'fld_name'); $crud->set_relation('fld_user_id','tbl_recipient', 'fld_name'); // -------------------------- // 自定义添加页面的多选下拉 // -------------------------- $crud->callback_add_field('fld_selected_items', function() { // 初始加载所有选项(如果是依赖下拉,后续用AJAX更新) $options = $this->db->get('tbl_target_options')->result(); // 替换为你的选项表 $html = '<select multiple="multiple" name="fld_selected_items[]" id="multi-select" style="height:150px;">'; foreach($options as $opt) { $html .= sprintf('<option value="%d">%s</option>', $opt->id, $opt->fld_name); } $html .= '</select>'; // 添加全选/取消按钮 $html .= '<div style="margin-top:8px;">'; $html .= '<button type="button" onclick="toggleMultiSelect(true)" class="btn btn-sm btn-primary">全选</button>'; $html .= '<button type="button" onclick="toggleMultiSelect(false)" class="btn btn-sm btn-default" style="margin-left:5px;">取消全选</button>'; $html .= '</div>'; // 全选逻辑JS $html .= '<script> function toggleMultiSelect(isSelectAll) { const select = document.getElementById("multi-select"); Array.from(select.options).forEach(opt => opt.selected = isSelectAll); } </script>'; return $html; }); // -------------------------- // 自定义编辑页面的多选下拉(回显已选值) // -------------------------- $crud->callback_edit_field('fld_selected_items', function($value, $primary_key) { // 解析已存值:如果是逗号分隔转数组,JSON的话用json_decode($value, true) $selectedIds = explode(',', $value); $options = $this->db->get('tbl_target_options')->result(); $html = '<select multiple="multiple" name="fld_selected_items[]" id="multi-select" style="height:150px;">'; foreach($options as $opt) { $selected = in_array($opt->id, $selectedIds) ? 'selected' : ''; $html .= sprintf('<option value="%d" %s>%s</option>', $opt->id, $selected, $opt->fld_name); } $html .= '</select>'; // 同样添加全选按钮和JS $html .= '<div style="margin-top:8px;">'; $html .= '<button type="button" onclick="toggleMultiSelect(true)" class="btn btn-sm btn-primary">全选</button>'; $html .= '<button type="button" onclick="toggleMultiSelect(false)" class="btn btn-sm btn-default" style="margin-left:5px;">取消全选</button>'; $html .= '</div>'; $html .= '<script> function toggleMultiSelect(isSelectAll) { const select = document.getElementById("multi-select"); Array.from(select.options).forEach(opt => opt.selected = isSelectAll); } </script>'; return $html; });
3. 处理表单提交数据
把多选的数组值转成适合存储的格式(逗号分隔字符串或JSON):
// 新增前处理 $crud->callback_before_insert(function($postArray) { if(isset($postArray['fld_selected_items'])) { // 逗号分隔存储,JSON的话用json_encode($postArray['fld_selected_items']) $postArray['fld_selected_items'] = implode(',', $postArray['fld_selected_items']); } return $postArray; }); // 更新前处理 $crud->callback_before_update(function($postArray, $primaryKey) { if(isset($postArray['fld_selected_items'])) { $postArray['fld_selected_items'] = implode(',', $postArray['fld_selected_items']); } return $postArray; });
4. 列表页面友好显示已选内容(可选)
把存储的ID转成对应的名称,提升可读性:
$crud->callback_column('fld_selected_items', function($value, $row) { if(empty($value)) return '-'; $ids = explode(',', $value); // 获取对应名称 $names = $this->db->where_in('id', $ids)->get('tbl_target_options')->result_array(); $nameList = array_column($names, 'fld_name'); return implode(', ', $nameList); });
5. 实现依赖下拉联动(如果需要)
如果你的多选下拉需要依赖其他字段(比如fld_home_id选中后更新选项),添加AJAX联动逻辑:
在callback_add_field的HTML末尾加入:
<script> // 监听依赖字段变化 document.getElementById('fld_home_id').addEventListener('change', function() { const homeId = this.value; fetch('<?=site_url('your_controller/get_options_by_home')?>', { method: 'POST', headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: `home_id=${homeId}` }).then(res => res.json()) .then(data => { const select = document.getElementById('multi-select'); select.innerHTML = ''; data.forEach(opt => { const option = document.createElement('option'); option.value = opt.id; option.textContent = opt.fld_name; select.appendChild(option); }); }); }); </script>
然后在控制器添加方法:
public function get_options_by_home() { $homeId = $this->input->post('home_id'); // 根据home_id筛选选项 $options = $this->db->where('fld_home_id', $homeId)->get('tbl_target_options')->result(); echo json_encode($options); }
注意事项
- 确保多选下拉的
name属性是数组形式fld_selected_items[],否则PHP无法接收多个值。 - 如果用JSON存储,记得把字段类型设为JSON,并且处理时替换
explode/implode为json_decode/json_encode。 - 全选按钮的JS可以根据项目是否使用jQuery调整,比如用
$('#multi-select option').prop('selected', isSelectAll)更简洁。
内容的提问来源于stack exchange,提问作者aziz




