datatable.js之tab切换(添加,删除)

datatables中tab切换,思路1:通过ajax获取所有的数据,在将不同数据分配到不同表格

其中tab切换采用的是bootstrap中的方法具体用法请参考官方文档,本文重点是ajax请求之添加删除

其他细节请忽略

1.必要的js,css文件

 <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
   <link rel="stylesheet" href="bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css">
   <script src="bower_components/jquery/dist/jquery.min.js"></script>
   <script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
   <script src="bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
   <script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>

2.HTML结构

<div style="width: 800px;margin: 0 auto">
	  <!-- Nav tabs -->
	<ul class="nav nav-tabs" role="tablist">
		<li role="presentation" class="active"><a href="#personInfo"  role="tab" data-toggle="tab">个人信息</a></li>
    <li role="presentation"><a href="#shopInfo"  role="tab" data-toggle="tab">店铺信息</a></li>
	</ul>
	 <!-- Tab panes -->
	  <div class="tab-content">
    <div role="tabpanel" class="tab-pane active" id="personInfo">
    	<table id="example1" class="table table-striped table-bordered" cellspacing="0" width="100%">
		<thead>
			<tr>
				<th>姓名</th>
				<th>性别</th>
				<th>邮件</th>
				<th>年龄</th>
				<th></th>
			</tr>
		</thead>
		<tfoot>
			<tr>
				<td>
					<div class="input-group">
  						<span class="input-group-addon" >姓名</span>
  						<input type="text" class="form-control" id='pname'>
					</div>
				</td>
				<td>
					<div class="input-group">
  						<span class="input-group-addon" >性别</span>
  						<input type="text" class="form-control" id='psex' placeholder="(0)女,(1)男">
					</div>
				</td>
				<td>
					<div class="input-group">
  						<span class="input-group-addon" >邮件</span>
  						<input type="text" class="form-control" id='pemail'>
					</div>
				</td>
				<td>
					<div class="input-group">
  						<span class="input-group-addon" >年龄</span>
  						<input type="text" class="form-control" id='page'>
					</div>
				</td>
				<td>
					<button class="btn btn-success" id='padd'>添加</button>
				</td>
			</tr>
		</tfoot>
	</table>
    </div>
    <div role="tabpanel" class="tab-pane" id="shopInfo">
    	<table id="example2" class="table table-striped table-bordered" cellspacing="0" width="100%">
		<thead>
			<tr>
				<th>店铺名称</th>
				<th>店铺地址</th>
				<th>店铺号码</th>
				<th>店铺简介</th>
				<th></th>
			</tr>
		</thead>
		<tfoot>
			<tr>
				<td>
					<div class="input-group">
  						<span class="input-group-addon" >店铺名称</span>
  						<input type="text" class="form-control" id='sname'>
					</div>
				</td>
				<td>
					<div class="input-group">
  						<span class="input-group-addon" >店铺地址</span>
  						<input type="text" class="form-control" id='saddress'>
					</div>
				</td>
				<td>
					<div class="input-group">
  						<span class="input-group-addon" >店铺号码</span>
  						<input type="text" class="form-control" id='snum'>
					</div>
				</td>
				<td>
					<div class="input-group">
  						<span class="input-group-addon" >店铺简介</span>
  						<input type="text" class="form-control" id='sinfo'>
					</div>
				</td>
				<td>
					<button class="btn btn-success" id='sadd'>添加</button>
				</td>
			</tr>
		</tfoot>
	</table>
    </div>
  </div>
</div>

3.json文件

{
"employees": [
{"name":"名字1","sex":"0","email":"123@163.com","age":"20"},
{"name":"名字2","sex":"1","email":"163@163.com","age":"50"},
{"name":"名字3","sex":"0","email":"132@163.com","age":"12"},
{"name":"名字4","sex":"0","email":"222@163.com","age":"55"}
],
"shops":[
{"sname":"小陈店铺","saddress":"地址1","snumber":"888888","sinfo":"简介啊啊"},
{"sname":"小卖部","saddress":"地址2","snumber":"666666","sinfo":"简介啊啊"},
{"sname":"杂货铺","saddress":"地址3","snumber":"22222","sinfo":"简介啊啊"}
]
}

4.js结构

$(function(){  
            let perdata, shopdata  
            let perArr=[];let shopArr=[]  
            $.ajax({  
                "url":'data.json',  
                "type":'get',  
                "dataType":'json',  
                "success":function(data){  
                    perdata=data.employees  
                    shopdata=data.shops  
                    showPer(perdata)   
                    showShop(shopdata)  
                }  
            })//先ajax获取所有的数据  
            function showPer(data){  
                $.each(data,function(index,item){  
                perArr.push([item.name,item.sex,item.email,item.age])//item为数组中的每一项  
            })  
                let options={  
             "paging":false,//不分页  
             "searching":false,//不搜索  
             "info":false,//不显示信息  
             "ordering":false,//不排序  
             "lengthChange":false,//不显示分页下拉列表  
             'destory':true,  
             "retrieve":true,  
             "data":perArr,  
             "columnDefs":[{"targets":[1],render:function(data,type,full){  
                return parseInt(data)===0?'女':'男'  
             }},{"targets":[4],render:function(data,type,full){  
                return "<button class='btn btn-danger del' >删除</button>"  
             }}]  
        }  
            let table1=$("#example1").DataTable(options)  
            return table1  
            }  
              
            function showShop(data)  
            {  
                $.each(data,function(index,item){  
                shopArr.push([item.sname,item.saddress,item.snumber,item.sinfo])//item为数组中的每一项  
            })  
                let options={  
             "paging":false,//不分页  
             "searching":false,//不搜索  
             "info":false,//不显示信息  
             "ordering":false,//不排序  
             "lengthChange":false,//不显示分页下拉列表  
             'destory':true,  
             "retrieve":true,  
             "data":shopArr,  
             "columnDefs":[{"targets":[4],render:function(data,type,full){  
                return "<button class='btn btn-danger del'>删除</button>"  
             }}]  
        }  
            let table2=$("#example2").DataTable(options)  
            return table2  
            }  
//动态添加员工信息  
$("#padd").click(function(){  
    let pname=$("#pname").val();  
    let psex=$("#psex").val();  
    let pemail=$("#pemail").val();  
    let page=$("#page").val()  
    showPer(perdata).row.add([pname,psex,pemail,page]).draw()  
})  
//动态添加店铺信息  
$("#sadd").click(function(){  
    let sname=$("#sname").val();  
    let saddress=$("#saddress").val();  
    let snum=$("#snum").val();  
    let sinfo=$("#sinfo").val()  
    showShop(shopdata).row.add([sname,saddress,snum,sinfo]).draw()  
})  
//删除信息 
$("#example1").on("click",".del",function(){  
    showPer(perdata).row($(this).parents('tr')).remove().draw()//找到当前点击按钮的那一行tr删除  
})  
$("#example2").on("click",".del",function(){  
   showShop(shopdata).row($(this).parents('tr')).remove().draw()//找到当前点击按钮的那一行tr删除  
}) 

})  

遇到的问题:

在这里插入图片描述

解决方法:在参数设置中加入

destory:true,
retrieve:true

2.若点击方法写成如下则无效果

$(".del").click(function(){

 showPer(perdata).row($(this).parents('tr')).remove().draw()

 showShop(shopdata).row($(this).parents('tr')).remove().draw()

})

可能原因:点击按钮是通过datatables方法动态生成,浏览器自上而下解析代码,可能找不到类名为del的按钮

解决办法:给父元素加点击事件,通过事件冒泡,子元素的点击事件触发父元素的点击事件

结构:

$(父元素).on('click',function(){})
$(父元素).on('click',ele,function(){})//只有子元素为ele的点击事件才能触发父元素的点击事件

效果:

在这里插入图片描述

在这里插入图片描述

<think> 我们面对的问题是:在使用PrimeFaces的tabview后,p:commandButton的update属性设置为@form:createStatisticsData时,无法将值返回到datatable。 根据引用[2]中提到的,PrimeFaces提供了`PrimeFaces.escapeClientId`函数来正确获取组件的客户端ID。在tabview中,由于每个tab的内容可能被动态加载,组件的客户端ID可能会发生变化,特别是当tabView处于动态模式(dynamic=true)时。因此,直接使用固定的ID字符串可能无法正确找到组件。 另外,引用[1]和引用[3]展示了p:commandButton和p:dataTable的用法,但没有直接解决tabview中的更新问题。 解决方案: 1. 确保datatable组件的ID在update属性中正确指定。在tabview中,由于组件可能被嵌套,需要指定从表单开始的完整路径。 2. 使用绝对ID路径,即从表单ID开始,到datatable的ID,中间用冒号分隔。例如:`:formId:tabViewId:tabId:datatableId`。 3. 如果不知道确切的ID路径,可以使用相对路径,但要注意在tabview中,每个tab的内容都是表单的一部分,因此使用@form可能会更新整个表单,但这可能不是最有效的方式,而且可能会更新不需要更新的部分。 4. 使用PrimeFaces的选择器(如引用[2]所示)来获取组件的客户端ID,然后使用这个ID来更新。但是注意,update属性需要的是字符串形式的客户端ID,因此我们可以使用JavaScript函数来动态计算,但这通常需要在oncomplete等事件中处理,而不是直接写在update属性中。 然而,我们的问题中update属性写的是`@form:createStatisticsData`,这可能是相对当前表单的某个组件的ID。但请注意,在tabview中,如果datatable位于不同的tab中,并且这个tab不是当前激活的,那么它可能不会被更新(因为非激活的tab可能没有被渲染)。 因此,我们尝试以下步骤: 步骤1:确认datatable所在的tab是否在更新时处于激活状态?如果不是,需要先激活该tab(可以通过设置tabView的activeIndex属性或使用PrimeFaces的widget方法来切换tab)。 步骤2:使用绝对客户端ID来更新datatable。为了确保正确,我们可以使用`PrimeFaces.escapeClientId`函数在JavaScript中获取客户端ID,但update属性是服务器端属性,所以不能直接使用JavaScript函数。因此,我们可以在服务器端获取组件的客户端ID,然后赋值给update属性。但是这样不太灵活。 另一种方法是使用PrimeFaces的选择器(PFS),例如:`update=":#{p:component('createStatisticsData')}"`。但注意,这需要PrimeFaces的EL函数支持。在页面顶部需要声明: xmlns:p="http://primefaces.org/ui" 然后在update属性中写: update=":#{p:component('createStatisticsData')}" 这样,PrimeFaces会在渲染时计算组件的客户端ID。 步骤3:如果datatable位于tabview中,并且tabview是动态加载的(dynamic=true),那么非活动tab中的内容在服务器端可能不存在,因此更新将不起作用。解决方法是确保datatable所在的tab在更新时是活动的,或者将dynamic设置为false(这样所有tab的内容都会被渲染,但可能影响性能)。 步骤4:如果问题依旧,可以尝试更新整个tabview,例如:`update=":formId:tabViewId"`,但这可能会更新整个tabview中的所有组件,包括其他tab,可能会带来不必要的刷新。 步骤5:考虑使用PrimeFaces的`update`属性支持的关键字,如`@form`(更新整个表单)或`@all`(更新整个页面),但要注意性能。 但是,根据问题描述,我们只想更新ID为`createStatisticsData`的datatable。因此,我们优先尝试步骤2。 示例代码: 假设我们的datatable的id是`createStatisticsData`,并且它位于一个id为`myTab`的tab中,而tabView的id是`myTabView`,表单的id是`myForm`。那么绝对路径是`:myForm:myTabView:myTab:createStatisticsData`。 在p:commandButton中,我们可以这样写: update=":myForm:myTabView:myTab:createStatisticsData" 但是,如果tabView是动态的,那么非活动tab中的组件在客户端可能不存在,所以更新会失败。因此,我们需要确保该tab在更新前是活动的。 我们可以在执行更新之前,先激活该tab。可以通过在p:commandButton的onclick事件中切换tab,或者使用PrimeFaces的API来切换tab。 例如,在按钮的onclick事件中激活tab: <p:commandButton ... onclick="PF('tabViewWidgetVar').select(索引);" update=":myForm:myTabView:myTab:createStatisticsData" /> 其中,`tabViewWidgetVar`是tabView的widgetVar,索引是要激活的tab的索引(从0开始)。 但是,注意:在客户端激活tab并不会让服务器端知道,除非设置`dynamic=false`。如果tabView是动态的,那么激活tab需要向服务器发送请求来加载tab内容,这可能会使问题复杂化。 因此,如果可能,建议将tabView的dynamic属性设置为false,这样所有tab的内容都会在初始渲染时加载,然后更新datatable就不会有问题。 总结解决方案: 1. 如果tabView不是动态的(dynamic=false),则直接使用绝对路径更新datatable: update=":formId:tabViewId:tabId:createStatisticsData" 2. 如果tabView是动态的(dynamic=true),则需要在更新前确保datatable所在的tab是活动的。可以通过在按钮的action中设置tabView的activeIndex属性,然后在更新时更新整个tabView(或者至少更新包含datatabletab)。但是这样可能会导致tab重新加载(因为动态tab在激活时才会加载内容),所以datatable的数据需要在激活tab时加载。 另一种做法是:在按钮的action方法中,我们激活对应的tab(设置activeIndex),然后更新整个tabView(或该tab的内容)。例如: <p:commandButton action="#{bean.method}" update=":formId:tabViewId" /> 在method方法中,我们设置activeIndex到包含datatabletab。 具体步骤: 在支持bean中: private int activeIndex; // getter and setter public void method() { // 执行一些操作 activeIndex = 包含datatabletab的索引; } 在tabView中绑定activeIndex: <p:tabView id="myTabView" dynamic="true" activeIndex="#{bean.activeIndex}"> ... tabs ... </p:tabView> 然后按钮更新整个tabView(或者更新包含datatabletab面板,但注意动态tab的更新可能需要更新整个tabView以确保切换)。 但是,更新整个tabView可能会刷新所有tab的内容,如果其他tab有输入内容,可能会丢失。所以,需要根据实际情况权衡。 3. 使用PrimeFaces的EL函数来获取组件的客户端ID,确保ID正确: update=":#{p:component('createStatisticsData')}" 但是,这要求组件在当前的视图(view)中,如果组件在非活动tab中(动态tab),则可能无法找到。 因此,对于动态tab,最好的做法是确保在更新之前激活tab(通过设置activeIndex),然后更新整个tabView或该tab的内容面板。 考虑到问题中的update属性为`@form:createStatisticsData`,这表示它试图更新当前表单中ID为`createStatisticsData`的组件。在tabview中,每个tab的内容都是表单的一部分,所以如果datatable在当前活动的tab中,那么`@form:createStatisticsData`应该可以工作。如果datatable不在当前活动的tab中,那么就不会被更新。 所以,问题可能在于datatable不在当前活动的tab中。因此,我们需要在点击按钮时激活datatable所在的tab。 最终建议的解决方案: 方案一(推荐,简单): 将tabView的dynamic属性设置为false(这样所有tab的内容都会在初始时渲染),然后使用绝对路径更新datatable,或者使用`@form:createStatisticsData`(如果它在同一个表单中)。 例如: <p:tabView dynamic="false"> ...你的tabs... </p:tabView> 然后按钮的update属性可以写:`update=":createStatisticsData"` 或者 `update="@form:createStatisticsData"`(注意:`@form`后面跟的是组件的id,但通常`@form`表示整个表单,所以`@form:createStatisticsData`表示更新表单中id为`createStatisticsData`的组件,这是正确的吗?实际上,`@form`是一个关键字,它代表当前表单,但后面再跟一个冒号和组件id,这应该是更新表单中某个特定的组件。但请注意,在PrimeFaces中,`@form`关键字通常单独使用,表示更新整个表单。而更新特定组件,直接写组件的绝对路径或相对路径即可。) 实际上,`update="createStatisticsData"` 可能就足够了,如果datatable和按钮在同一个命名容器内(如同一个tab)。但如果不在,则需要绝对路径。 方案二: 如果必须使用动态tab(dynamic=true),那么: - 在按钮的action方法中,设置activeIndex为包含datatabletab的索引。 - 然后更新整个tabView(id为myTabView)或者更新包含datatabletab的面板(如果有的话)。 - 同时,确保在激活tab后,重新加载datatable的数据(因为动态tab在激活时才会加载内容,所以需要在tab切换事件中加载数据,或者在该按钮的action方法中加载数据)。 例如: 支持bean: private int activeIndex; // 有getter和setter 按钮的action方法: public void actionMethod() { // 执行你的业务逻辑 // 设置要激活的tab索引 activeIndex = 1; // 假设第二个tab // 加载datatable的数据(如果还没有加载的话) } tabView: <p:tabView id="myTabView" dynamic="true" activeIndex="#{bean.activeIndex}"> <p:tab id="tab1" ...> ... </p:tab> <p:tab id="tab2"> <p:dataTable id="createStatisticsData" ...> ... </p:dataTable> </p:tab> </p:tabView> 按钮: <p:commandButton action="#{bean.actionMethod}" update=":formId:myTabView" /> 注意:更新整个tabView可能会刷新所有tab的头部(包括活动状态的改变),但不会刷新每个tab的内容,除非动态设置为false(动态设置为true时,内容在激活时加载,但更新整个tabView不会重新加载内容,除非使用tabView的updateContent方法)。但是,当我们更新整个tabView时,它会根据activeIndex重新渲染tab的头部(活动tab会改变),而tab的内容面板不会被更新(因为动态tab的内容是延迟加载的)。所以,我们需要在tab切换事件中加载数据,或者单独更新该tab的内容面板。 另一种做法是单独更新tab的内容面板。我们可以给包含datatabletab的内容面板设置一个id,比如`tab2_content`,然后更新这个面板。但是,动态tab的内容面板的id我们可以通过查看生成的HTML来找到,通常它会是`myForm:myTabView:tab2_content`,但我们不能直接写死,因为涉及到命名容器。 所以,我们可以使用: update=":formId:myTabView:tab2_content" 但是,这要求我们给tab的内容部分设置一个明确的id。我们可以使用tab的content标签: <p:tab id="tab2"> <h:panelGroup id="tab2_content"> <p:dataTable id="createStatisticsData" ...> ... </h:panelGroup> </p:tab> 然后按钮更新这个panelGroup:update=":formId:myTabView:tab2_content" 同时,在按钮的action方法中设置activeIndex,这样tab就会切换到第二个,并且内容面板会被更新。 由于问题描述有限,以上提供了多种解决方案。请根据具体场景选择。 如果问题仍然存在,请提供相关的代码结构(尤其是tabView和datatable的嵌套结构),以便进一步分析。 最后,注意:在PrimeFaces中,使用`@form`后跟冒号和组件id的写法(如`@form:createStatisticsData`)并不是标准的关键字用法。标准的关键字包括`@form`(整个表单)、`@this`(当前组件)、`@none`(不更新)等。所以,直接写组件的绝对路径是最可靠的。 因此,我建议使用绝对客户端ID来更新组件。可以通过查看页面生成的HTML来确定datatable的客户端ID,然后在update属性中写这个ID(注意要加上冒号前缀,表示从根开始查找)。例如,如果生成的id是"j_idt5:myTabView:tab2:createStatisticsData",那么update属性可以写:`update=":j_idt5:myTabView:tab2:createStatisticsData"`。但注意,如果表单的id是动态生成的(如j_idt5),那么每次运行可能会改变,所以最好给表单设置一个固定的id。 给表单设置固定id: <h:form id="myForm"> ... </h:form> 然后,在update属性中使用绝对路径:`:myForm:myTabView:tab2:createStatisticsData`。 综上所述,请尝试以下步骤: 1. 给表单设置固定id。 2.tabView设置固定id,给包含datatabletab设置固定id(如果有多个tab,每个tab最好设置固定id)。 3.datatable设置固定id(如`createStatisticsData`)。 4. 在p:commandButton中,使用绝对路径更新:`update=":myForm:myTabView:tabId:createStatisticsData"`。 如果tabView是动态的,同时要确保在更新前该tab是活动的(可以通过在按钮的action中设置activeIndex,然后更新整个tabView或该tab的内容面板)。 如果问题仍然存在,请检查是否因为动态加载导致datatable在更新时尚未被渲染。 希望这些建议能帮助解决问题。 </think> 在使用 PrimeFaces 的 `<p:tabView>` 后,`<p:commandButton>` 的 `update` 属性无法正确更新目标组件是常见问题。主要原因是 **TabView 的嵌套命名容器**导致客户端 ID 变化。以下是系统解决方案: ### 解决方案 1. **使用绝对客户端 ID 路径** 通过表单 ID + 目标组件的完整路径(参考引用[2]的客户端ID处理方式): ```xhtml <p:commandButton update=":formId:tabViewId:tabId:createStatisticsData" .../> ``` 2. **使用 PrimeFaces 搜索表达式**(推荐) 结合 `@parent` 和 `@namingcontainer` 定位目标(类似引用[3]的表格更新逻辑): ```xhtml <p:commandButton update="@parent:@namingcontainer:createStatisticsData" .../> ``` 3. **JavaScript 动态获取客户端 ID** 使用 PrimeFaces 的 `escapeClientId()` 函数(如引用[2]所示): ```xhtml <p:commandButton onclick="PrimeFaces.update(PrimeFaces.escapeClientId('formId:createStatisticsData'))" .../> ``` ### 完整示例 ```xhtml <h:form id="mainForm"> <p:tabView id="myTabView"> <p:tab id="inputTab"> <p:commandButton value="提交" action="#{bean.generateData}" <!-- 方案1:绝对路径 --> update=":mainForm:myTabView:resultTab:createStatisticsData" <!-- 方案2:搜索表达式(推荐) --> update="@parent:@namingcontainer:createStatisticsData" /> </p:tab> <p:tab id="resultTab"> <p:dataTable id="createStatisticsData"> <!-- 数据表内容 --> </p:dataTable> </p:tab> </p:tabView> </h:form> ``` ### 关键点说明 1. **命名容器规则** TabView 作为命名容器会修改子组件客户端 ID(如 `myTabView:resultTab:createStatisticsData`),直接使用原始 ID 会失效[^1]。 2. **动态 Tab 处理** 如果使用 `dynamic="true"`,需在按钮事件中预加载目标 Tab: ```java // Bean 方法中激活目标 Tab public void generateData() { //...业务逻辑 RequestContext.getCurrentInstance().execute("PF('tabViewWidget').select(1)"); } ``` 3. **部分更新优化** 避免使用 `@form` 更新整个表单(如引用[1]),否则会导致 TabView 状态重置。 > **提示**:使用浏览器开发者工具检查渲染后组件的真实客户端 ID(通常为 `formId:tabViewId:tabId:componentId` 格式)[^3]。 [^1]: TabView 作为命名容器会修改子组件客户端 ID [^2]: 使用 `PrimeFaces.escapeClientId()` 获取动态 ID [^3]: 检查渲染后的真实客户端 ID 结构
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值