$.each用法---取出form中所有的数据

jQuery表单序列化与JSON转换
本文介绍如何使用jQuery的serializeArray方法从表单中获取数据,并将其转换为JSON格式,通过示例代码展示了数据处理的过程。
<script>
    $(function() {
        $('#btnLogin').click(function() {
            var d = {};
            var t = $('form').serializeArray();//t:数组对象、存放了从form中取出的所有数据
            // alert(t[0].name + '.....' + t[0].value)
            $.each(t, function() {

                d[this.name] = this.value;   //填充数组d
                // alert('.....' + d[this.name])
            });
            // d['sex'] = '男';
            alert(JSON.stringify(d));
        });
    });
</script>

 

<think>问题分析: 在PrimeFaces中,使用`p:column selectionMode="multiple"`会为每一行生成一个复选框用于选择行。同时,在另一列中有一个自定义的单选框(`.usable-checkbox`)。问题描述中,使用JavaScript函数`selectAllAndCheckUsable`试图实现两个功能: 1. 全选行(即选中所有行的复选框) 2. 将每一行中的自定义单选框(可用单选框)设置为选中状态。 但是,在操作后,当取消某些单选框的选中状态,然后点击查询(刷新数据)后,发现之前通过JS设置的单选框又回到了选中状态。而通过全选行选中的复选框状态在刷新后可能没有保留(因为数据表重新加载了)。 问题的核心在于: 1. 通过JS设置的单选框状态(.usable-checkbox)并没有与后台的模型数据同步,仅仅是在前端设置了选中状态。因此,当重新查询(重新加载数据表)时,后台模型数据并没有改变,所以重新渲染后,单选框的状态又回到了最初的值(即未改变之前的状态)。 2. 全选行(PF('dtList').selectAllRows())是PrimeFaces数据表的选择功能,它会更新数据表组件的内部选择状态(与后台的selection属性绑定)。但是,自定义的单选框(.usable-checkbox)并没有与任何后台数据绑定(或者绑定方式未知),所以通过JS设置其选中状态并不会更新后台模型。 因此,需要确保: - 自定义单选框(.usable-checkbox)应该与后台的某个属性绑定,这样在重新查询时,后台可以返回更新后的状态。 - 在JS中设置单选框状态的同时,需要更新后台模型,或者至少在前端设置的状态能够被提交到后台,并在重新加载时保留。 但是,从代码中看到,在设置单选框选中状态后,触发了一个change事件(`checkbox.trigger('change')`),这可能是为了触发p:ajax事件。如果这个p:ajax事件能够正确更新后台模型,那么问题可能在于重新查询时没有保存这些状态。 然而,重新查询(比如重新执行查询方法,重新加载数据)会从后台获取最新的数据,如果后台没有记录这些单选框的状态(即这些状态是临时在页面上的,没有保存到数据库或会话中),那么重新加载后,状态自然就丢失了。 解决方案: 1. 确保每次设置单选框状态后,通过Ajax更新后台模型,并且后台将这些状态保存起来(例如,在会话中或临时对象中),这样在重新查询时,这些状态能够被正确设置。 2. 或者,在重新查询时,不要重置整个数据表,而是保留这些状态(但这样可能不现实,因为查询可能会改变数据)。 3. 另一种思路:将自定义单选框的状态与行选择状态分离。行选择状态(复选框)是PrimeFaces内置的,可以通过`selection`属性绑定到后台,在重新查询时,如果数据项相同,PrimeFaces可以自动恢复选择状态(需要设置`rowKey`并且重新绑定的数据项与之前选中的项匹配)。但是自定义单选框的状态需要单独处理。 具体到代码: 在`selectAllAndCheckUsable`函数中,我们做了两件事: - 全选行:这更新了数据表组件的选择状态(会更新后台的`selection`属性,如果配置了Ajax更新的话)。 - 设置自定义单选框:这需要单独更新后台模型。通过触发change事件,如果该单选框有对应的p:ajax监听器,那么会执行更新后台模型的操作。但是,如果重新查询后,后台返回的数据并没有包含这些更新(因为可能没有保存到数据库),那么重新渲染后,状态就会丢失。 因此,我们需要确保在重新查询之前,所有对单选框的更改已经保存到后台(比如在会话中),然后在重新查询时,将这些状态重新应用到数据上。 但是,如果重新查询是从数据库加载的数据,那么这些临时状态(比如单选框选中状态)不会在数据库中,所以需要单独存储。 建议: 如果这些单选框的状态只是临时的(不需要永久保存),那么可以考虑在客户端保存状态(比如在浏览器的sessionStorage或localStorage中),在重新加载数据后,再根据保存的状态重新设置。但是,这需要在前端处理,并且要考虑到数据行的唯一标识。 步骤: a. 在用户更改单选框状态时,将状态和对应的行标识(如rowKey)存储到sessionStorage中。 b.数据表加载完成后(比如在onComplete事件中),从sessionStorage中读取状态,重新设置单选框。 但是,这种方法比较复杂,且需要维护客户端状态。 另一种更合理的方式:在后台维护这些状态。例如,在支持全选和设置可用状态的场景中,后台应该有一个集合来记录哪些行被设置为可用。在重新查询后,根据这个集合来设置每行的状态。 因此,需要修改: 1. 在JS函数中,触发change事件后,通过p:ajax事件更新后台对应行的可用状态(保存到后台的一个Map中,key为行标识,value为状态)。 2. 在重新查询时,查询方法除了获取数据,还要为每一行设置可用状态(从后台的Map中取出,如果存在则设置为选中,否则不选中)。 具体到代码实现: 假设自定义单选框的p:ajax事件已经绑定到一个后台方法,比如: <p:ajax event="change" listener="#{bean.onUsableChange}" update="@form" /> 在`onUsableChange`方法中,将当前行的状态保存到后台的一个Map中: private Map<Long, Boolean> rowUsableMap = new HashMap<>(); // 假设行标识为Long类型 public void onUsableChange(AjaxBehaviorEvent event) { UIComponent component = event.getComponent(); // 获取当前行 // 假设行数据对象有一个唯一标识id // 将状态保存到map: rowUsableMap.put(row.getId(), currentState); } 然后在数据表的每行中,根据当前行的id从rowUsableMap中取出状态,设置单选框的选中状态。 但是,在重新查询后,数据表会重新绑定数据,此时我们需要在渲染时设置单选框的状态。可以通过在数据对象中添加一个临时属性(如`usable`)来实现,然后在查询后,根据rowUsableMap设置这个属性。 步骤: - 修改数据对象,添加一个Boolean类型的usable属性。 - 在查询方法中,遍历查询到的数据列表,根据rowUsableMap设置每个对象的usable属性(如果map中有则设置,否则设为默认值)。 - 在页面上,将单选框的选中状态绑定到该对象的usable属性。 这样,当重新查询时,每行的usable属性就会被正确设置,单选框状态也就正确了。 但是,这需要修改数据对象和查询方法。 如果不想修改数据对象,也可以使用一个单独的Map来存储状态,并在页面上通过EL表达式来设置选中状态。例如: <p:selectBooleanCheckbox value="#{bean.rowUsableMap[row.id]}"/> 其中,`row`是当前行的数据对象,有一个id属性。这样,单选框的值就会绑定到bean的rowUsableMap中对应id的值。这样,在重新查询后,由于rowUsableMap在后台会话中,所以状态会保留。 注意:需要确保rowUsableMap在会话中存活,并且不会因为其他操作而被清空。 因此,修改JS函数可能不是根本问题,根本问题在于如何保存和恢复状态。 回到原始问题:为什么更改单选框后,重新查询状态又回来了? 原因:重新查询后,数据表重新绑定数据,而单选框的状态是通过后台模型数据初始化的,如果后台模型数据没有改变(即没有保存之前设置的状态),那么就会显示原来的状态。 所以,我们需要确保在JS中设置单选框状态时,同时更新后台模型,并且这些更新能够在重新查询后反映出来。 总结: 1. 确保自定义单选框的值绑定到后台的一个支持保存状态的变量(如会话作用域的Map)。 2. 在重新查询时,这个Map不会被清除(或者重新设置)。 3. 在JS函数中,我们通过触发change事件来更新后台模型,这样在重新查询后,单选框的状态就会从Map中获取,从而保持之前设置的状态。 因此,修改建议: 步骤1:在后台Bean中(会话作用域)创建一个Map,用于存储每行的可用状态。 步骤2:将单选框的值绑定到这个Map中,以行唯一标识为键。 步骤3:在JS函数中,触发change事件后,会更新后台Map。 步骤4:在重新查询时,由于Map还在会话中,所以单选框的状态会正确设置。 代码示例: 后台Bean(会话作用域): ```java @Named @SessionScoped public class Bean implements Serializable { private Map<Long, Boolean> rowUsableMap = new HashMap<>(); // 存储每行的可用状态 // 在查询方法中,可能会重新设置数据列表,但不需要清除rowUsableMap,因为我们希望保留状态 // 但是注意:如果查询结果的行标识和之前不同,那么之前的状态不会影响新的行。 public Map<Long, Boolean> getRowUsableMap() { return rowUsableMap; } // 可以提供一个方法用于更新单个行的状态(由p:ajax调用) public void onUsableChange(RowToggleEvent event) { // 假设事件对象可以获取行数据和状态 // 实际上,我们需要在页面上传递行标识 } // 或者,通过f:attribute传递行标识 } ``` 页面单选框列: ```xhtml <p:column> <p:selectBooleanCheckbox value="#{bean.rowUsableMap[row.id]}" > <p:ajax event="change" update="@this" /> </p:selectBooleanCheckbox> </p:column> ``` 这样,当JS函数触发change事件时,就会更新后台Map中对应行的状态。 但是,在JS函数中,我们通过遍历行来设置单选框并触发事件,这样就会更新后台Map中每一行的状态为true。 重新查询后,由于rowUsableMap中保存了之前设置的状态,所以单选框会显示为之前设置的状态(包括全选后设置为true,以及之后手动设置为false的也会保留)。 注意:rowUsableMap可能会越来越大,因为存储了所有操作过的行的状态。为了避免内存泄漏,可以在重新查询后,移除那些不在当前数据列表中的行的状态。或者,在离开页面时清空Map。 另外,全选行(复选框列)的状态是由PrimeFaces的selection机制管理的,它绑定到后台的另一个属性(比如`selectedRows`),这个属性在重新查询后,如果数据表设置了`rowKey`并且重新绑定的数据项与之前选中的项匹配(即相同的对象或相同的rowKey值),那么选中的状态会自动恢复。所以不需要额外处理。 因此,修改后的JS函数不需要改变,因为它会触发change事件,从而更新后台的rowUsableMap。而重新查询后,单选框的状态由rowUsableMap决定,所以会保持之前设置的状态。 但是,如果重新查询后,行的id发生了变化(比如新查询的数据行id和之前不同),那么状态不会恢复。这需要根据业务需求处理。 最后,检查JS函数中触发change事件的部分:`checkbox.trigger('change')`,这应该能够触发p:ajax的change事件,从而更新后台。 所以,修改后的代码结构: 后台:增加Map<String, Boolean> rowUsableMap(假设行标识为String类型),并提供getter。 页面:将单选框的值绑定到`#{bean.rowUsableMap[row.id]}`。 这样,问题应该可以解决。 但是,原始问题描述中,在重新查询后,单选框的状态没有被保留,就是因为没有将状态保存到后台的会话作用域中,并且在重新查询后,没有根据保存的状态来设置单选框。 因此,按照上述修改后,状态应该能够保留。 注意:如果数据量很大,rowUsableMap可能会占用较多内存,需要权衡。 如果问题仍然存在,请检查: - 重新查询时,数据表是否重新设置了rowKey?确保rowKey是唯一的且不变。 - 重新查询后,rowUsableMap中是否包含当前行的id?如果没有,那么单选框就不会被选中。 另外,在JS函数中,我们通过类选择器`.usable-checkbox`来查找单选框,请确保这个类已经正确添加到单选框上。 示例: ```xhtml <p:selectBooleanCheckbox styleClass="usable-checkbox" ... /> ``` 最后,修改JS函数,确保它能够正确触发事件。但是,如果单选框的值已经绑定到后台Map,并且通过JS设置选中状态并触发change事件,那么后台Map就会更新。 所以,修改后的JS函数保持不变: ```javascript function selectAllAndCheckUsable() { // 1. 全选行 PF('dtList').selectAllRows(); // 2. 获取表格中的所有行 var table = PF('dtList').getJQ(); // 3. 遍历每一行,设置可用单选框为选中 table.find('tr').each(function() { var checkbox = $(this).find('.usable-checkbox input[type="checkbox"]'); if (checkbox.length > 0) { // 设置选中状态 checkbox.prop('checked', true); // 触发change事件(确保p:ajax监听器执行) checkbox.trigger('change'); } }); } ``` 注意:全选行(复选框列)和自定义单选框列是两个不同的列,它们的状态是独立的。全选行操作不会影响自定义单选框列,所以需要JS单独设置。 综上所述,通过将自定义单选框的状态保存到会话作用域的Map中,并在重新查询后根据Map设置状态,可以解决重新查询后状态丢失的问题。 但是,如果问题描述中的“取消点击查询”是指重新执行查询操作,那么确保在查询方法中不要重置rowUsableMap,并且查询后数据表会重新渲染,此时单选框的状态由`rowUsableMap[row.id]`决定,所以之前设置的状态会保留。 因此,修改后的流程: 1. 用户点击“全选并设置可用”按钮,调用JS函数,该函数会: - 全选行(更新行选择状态) - 设置每一行的自定义单选框为选中,并触发change事件 2. change事件更新后台Map,将对应行的状态设置为true。 3. 用户手动取消某些行的单选框,触发change事件,更新后台Map,将对应行的状态设置为false。 4. 用户点击“查询”按钮,重新执行查询。 5. 查询方法从数据库获取数据,然后遍历这些数据,根据row.id从Map中取出状态(如果有,则设置到数据对象中,或者通过Map直接绑定)。 6. 页面重新渲染,单选框的状态为Map中保存的状态。 这样,之前手动取消的单选框就不会被选中了。 所以,关键在于将单选框的状态与后台的Map绑定,并在重新查询后使用这个Map来设置状态。 如果按照上述修改后,问题仍然存在,请检查: - 后台Map是否被正确更新(可以在onUsableChange方法中打印日志) - 重新查询后,单选框的值是否从Map中获取(可以在页面上打印EL表达式:#{bean.rowUsableMap[row.id]},看是否为false) - JS函数是否正确地触发了change事件(可以在浏览器控制台观察Ajax请求是否发出) 希望这能解决问题。</think>您的问题涉及 PrimeFaces 数据表(DataTable)中的复选框状态管理问题。核心问题是:通过 JavaScript 函数 `selectAllAndCheckUsable()` 设置的状态在查询后无法保持。以下是详细分析和解决方案: ### 问题原因分析 1. **状态管理不一致**: - `p:column selectionMode="multiple"` 使用 PrimeFaces 内部状态管理 - 自定义的 `.usable-checkbox` 使用独立的状态管理 - 两者没有关联,导致状态不同步 2. **数据表刷新机制**: - 查询操作会重新渲染整个数据- JavaScript 修改的状态是临时的客户端状态 - 重新渲染后,状态会从服务器端模型数据恢复 3. **事件处理缺失**: - 自定义复选框的 change 事件没有正确更新服务器端状态 - 全选操作只更新了客户端状态,没有同步到服务器 ### 完整解决方案 #### 1. 统一状态管理(推荐方案) ```java // 后台Bean中添加状态管理 @Named @ViewScoped public class YourBean implements Serializable { // 存储所有行的选择状态 private Map<Long, Boolean> rowSelectionMap = new HashMap<>(); // 存储所有行的可用状态 private Map<Long, Boolean> rowUsableMap = new HashMap<>(); // 全选操作 public void selectAllAndCheckUsable() { for (YourDataObject item : dataList) { rowSelectionMap.put(item.getId(), true); rowUsableMap.put(item.getId(), true); } } // 查询操作 public void search() { // 执行查询逻辑... // 查询后保留之前的状态 for (YourDataObject item : dataList) { // 保留之前的选择状态 Boolean selected = rowSelectionMap.get(item.getId()); if (selected != null) { item.setSelected(selected); } // 保留之前的可用状态 Boolean usable = rowUsableMap.get(item.getId()); if (usable != null) { item.setUsable(usable); } } } // Getters and Setters } ``` ```xhtml <!-- 更新前端页面 --> <p:dataTable id="dtList" value="#{yourBean.dataList}" var="item" selection="#{yourBean.selectedItems}" rowKey="#{item.id}"> <!-- 选择列 - 绑定到后台状态 --> <p:column selectionMode="multiple" style="width:20px;text-align:center" selected="#{rowSelectionMap[item.id]}"/> <!-- 可用状态列 - 绑定到后台状态 --> <p:column> <p:selectBooleanCheckbox value="#{rowUsableMap[item.id]}"> <p:ajax update="@form" /> </p:selectBooleanCheckbox> </p:column> <!-- 其他列... --> </p:dataTable> <!-- 更新JavaScript函数 --> <h:outputScript> function selectAllAndCheckUsable() { // 触发后台全选操作 PF('yourWidgetVar').callFunction(function() { #{yourBean.selectAllAndCheckUsable()} }); // 更新前端显示 PF('dtList').selectAllRows(); $('.usable-checkbox input').prop('checked', true); } </h:outputScript> ``` #### 2. 客户端状态保持方案 ```javascript // 在页面加载时恢复状态 $(document).ready(function() { restoreCheckboxStates(); }); // 保存状态到SessionStorage function saveCheckboxStates() { let states = { selection: [], usable: [] }; // 保存选择状态 PF('dtList').getSelectedRows().forEach(row => { states.selection.push(row.getAttribute('data-rowkey')); }); // 保存可用状态 $('.usable-checkbox:checked').each(function() { states.usable.push($(this).closest('tr').attr('data-rowkey')); }); sessionStorage.setItem('checkboxStates', JSON.stringify(states)); } // 从SessionStorage恢复状态 function restoreCheckboxStates() { const states = JSON.parse(sessionStorage.getItem('checkboxStates') || '{}'); // 恢复选择状态 PF('dtList').clearSelection(); states.selection.forEach(rowKey => { const row = $(`tr[data-rowkey="${rowKey}"]`); if (row.length) { PF('dtList').selectRow(row); } }); // 恢复可用状态 $('.usable-checkbox').prop('checked', false); states.usable.forEach(rowKey => { $(`tr[data-rowkey="${rowKey}"] .usable-checkbox`).prop('checked', true); }); } // 更新查询按钮 <p:commandButton value="查询" action="#{yourBean.search}" oncomplete="restoreCheckboxStates()"/> ``` #### 3. 增强的JavaScript函数 ```javascript function selectAllAndCheckUsable() { // 1. 获取数据表组件 var dataTable = PF('dtList'); // 2. 全选行 dataTable.selectAllRows(); // 3. 更新内部选择状态 var selectedRowKeys = []; dataTable.getRows().forEach(row => { var rowKey = $(row).data('rowkey'); selectedRowKeys.push(rowKey); }); dataTable.selection = selectedRowKeys; // 4. 设置可用单选框 $('.usable-checkbox').each(function() { $(this).prop('checked', true); // 5. 触发状态更新事件 var event = new Event('change', { bubbles: true, cancelable: true }); this.dispatchEvent(event); }); // 6. 通知PrimeFaces更新 PF('ajaxWidget').update(); } ``` ### 关键问题解决点 1. **状态同步机制**: - 使用 `Map` 在后台统一管理所有行的状态 - 前端通过 `rowKey` 绑定到具体行的状态 2. **数据表刷新处理**: - 在查询方法中保留之前的状态 - 使用 `oncomplete` 事件恢复客户端状态 3. **JavaScript增强**: - 全选时更新 PrimeFaces 内部状态 `dataTable.selection` - 手动触发 change 事件确保监听器执行 - 使用 `data-rowkey` 属性保持行标识一致性 4. **组件标识优化**: ```xhtml <p:dataTable ... rowIndexVar="rowIndex"> <p:column> <p:selectBooleanCheckbox styleClass="usable-checkbox" value="#{yourBean.rowUsableMap[item.id]}"> <p:ajax update="@this" /> </p:selectBooleanCheckbox> </p:column> </p:dataTable> ``` ### 最佳实践建议 1. **使用PrimeFaces内置选择机制**: ```xhtml <p:dataTable selection="#{bean.selectedItems}" ...> <p:column selectionMode="multiple" /> </p:dataTable> ``` 2. **状态管理优化**: ```java // 在ViewScope中维护状态 private Map<String, Boolean> selectionState = new HashMap<>(); @PostConstruct public void init() { // 初始化状态 dataList.forEach(item -> { selectionState.put(item.getId(), false); }); } ``` 3. **部分更新优化**: ```xhtml <p:commandButton value="查询" action="#{bean.search}" update="dtList" partialSubmit="true"/> ``` 4. **行键优化**: ```java // 确保每个数据项有唯一标识 public class YourDataObject { private Long id; // 唯一标识符 // 其他字段... } ``` ### 总结 问题根源在于: 1. 选择列和自定义复选框状态分离 2. JavaScript修改的状态未同步到服务器 3. 查询操作重置了所有状态 解决方案核心: - **统一状态管理**:后台使用Map管理所有行状态 - **双向绑定**:前端组件直接绑定到后台状态 - **状态持久化**:查询时保留状态,使用rowKey关联 - **事件完整性**:确保所有操作触发完整事件链
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值