selectPage组件data-field与data-primary-key到底谁负责显示、谁负责提交

      发布在:前端技术      评论:0 条评论

在CRM合同模块的添加页面中,有两个签约人字段都用到了selectPage下拉选择组件,但提交的数据类型却不一样:

  • 客户签约人:提交的是联系人姓名(如"刘坤")
  • 公司签约人:提交的是管理员ID(如"2")

两个字段配置看起来差不多,为什么提交结果不同?关键就在 data-fielddata-primary-key 这两个属性上。

先看代码

客户签约人

<input type="text" name="contract[customer_signer]" 
       data-toggle="selectPage" 
       data-source="{:url('crm.customerContacts/selectpage')}"
       data-field="contact"  
       data-primary-key="contact"
       data-format-item="{contact}({phone})"
       value="{$row['customer_signer']|default=''}">

公司签约人

<input type="text" name="contract[company_signer]" 
       data-toggle="selectPage"
       data-source="{:url('admin/selectpage')}"
       data-field="username"  
       data-primary-key="admin_id"
       data-format-item="{username}({realname})"
       value="{$row['company_signer']|default=''}">

核心结论:一句话记住

data-field 管"看到什么",data-primary-key 管"提交什么"。

就这么简单,别被其他属性搞混了。

详细拆解

1. 属性映射关系

selectPage组件初始化时,会把HTML的data属性映射成内部参数:

// selectpage.js 第215行
{data: 'source', keyField: 'primaryKey', showField: 'field', ...}

对应关系:

HTML属性插件内部名干什么用
data-fieldshowField选中后,输入框里显示哪个字段的值
data-primary-keykeyField选中后,隐藏表单字段写入哪个字段的值(就是最终提交给后端的)
data-format-itemformatItem下拉列表里每条记录怎么格式化展示,比如 {contact}({phone})

2. 表单提交机制(这个很重要)

selectPage初始化的时候,会把原始的一个 <input> 拆成两个:

你写的:     <input name="contract[company_signer]">

插件拆成:   <input type="hidden" name="contract[company_signer]">        ← 存keyField的值,跟着表单提交
            <input type="text"   name="contract[company_signer]_text">   ← 存showField的值,给用户看的

源码是这样的(selectpage.js 第568-582行):

// 隐藏input:保持原始name,存储实际提交的值
elem.hidden = $('<input type="hidden">').attr({ name: hidden_name }).val('');

// 可见input:name加"_text"后缀,存储显示的文本(不会被提交,因为name不一样)
elem.combo_input.attr({ name: input_name + '_text' });

选中某项之后(selectpage.js 第738-742行):

var value = row[p.keyField];   // 取 data-primary-key 指定字段的值 → 写入隐藏input
var text = row[p.showField];   // 取 data-field 指定字段的值 → 写入可见input
self.elem.combo_input.val(text);  // 用户看到文本
self.elem.hidden.val(value);      // 表单提交的是这个值

3. 回到开头的两个字段

客户签约人公司签约人
data-fieldcontactusername
data-primary-keycontactadmin_id
用户看到的contact值,如"刘坤"username值,如"admin"
表单提交的contact值,如"刘坤"admin_id值,如"2"

客户签约人data-fielddata-primary-key 都是 contact,所以看到的和提交的都是联系人姓名。

公司签约人data-field="username"data-primary-key="admin_id",所以看到的是用户名,但实际提交给后端的是管理员ID。

4. data-format-item 的角色

这个属性只管下拉列表中每条记录的展示格式,不影响提交值。

data-format-item="{contact}({phone})"

下拉列表里会显示:刘坤(13800138000)

但选中后输入框里只显示 data-field 对应的值(刘坤),除非在 easy-admin.js 中做了特殊处理(通过 eSelect 回调和 afterInit 重写来让输入框也用 formatItem 格式化显示)。

常见坑点

  1. 想让输入框也显示格式化内容:selectPage核心的 afterInit 方法只用了 showField,没用 formatItem。easy-admin.js 里做了补丁处理,通过覆写 afterIniteSelect 回调来实现格式化回显。

  2. 后端接收到的值跟你以为的不一样:别只看输入框里显示什么,要看 data-primary-key 配的是什么。如果 data-primary-key="admin_id",后端收到的就是ID,不是用户名。

  3. 编辑回显问题:如果 data-primary-key 是ID,那 value 属性也要填ID值,不能填名称。比如公司签约人的value应该是 {$row['company_signer']}(存的是admin_id),而不是人名。

  4. data-field和data-primary-key设成一样:完全没问题,客户签约人就是这么干的。这时候看到的和提交的是同一个字段的值。

速查表

┌──────────────────────────────────────────────────────────────────┐
│  属性                 │  控制什么              │  影响范围       │
├──────────────────────────────────────────────────────────────────┤
│  data-field           │  输入框显示哪个字段     │  用户看到的     │
│  data-primary-key     │  隐藏字段存哪个字段     │  后端收到的     │
│  data-format-item     │  下拉列表每条怎么展示   │  下拉选项文本   │
│  data-source          │  数据从哪个接口加载     │  数据来源       │
│  data-params          │  额外的查询参数         │  过滤条件       │
└──────────────────────────────────────────────────────────────────┘

相关文件

  • selectPage组件源码:public/static/plugs/lay-module/selectPage/selectpage.js
  • easy-admin集成层:public/static/plugs/easy-admin/easy-admin.js(selectPage函数,约第2351行)
  • 合同添加页面:app/admin/view/crm/contract/add.html
  • 后端selectpage方法:app/admin/traits/Curd.php(selectpage方法)


热门推荐