JSF composite component存在重复代码,如何参数化实现新增/编辑p:dialog复用?
解决方案
你可以通过动态EL绑定的方式合并弹窗,不需要大改现有代码,核心思路是把两个弹窗的差异(绑定对象、标题、提交动作)都做成运行时可切换的动态值,只保留一套布局代码,后续修改只需调整一处。
方案1:最小改动版(仅修改复合组件xhtml,后端仅需加2个状态属性)
前置后端小改动
仅需在现有viewBean类中新增2个属性,无需修改原有业务逻辑:
taskDialogVisible:布尔值,控制弹窗的显示/隐藏,提供getter/setterdialogMode:字符串,取值"add"/"edit",标识当前是新增还是编辑场景,提供getter/setter
打开弹窗的触发逻辑对应调整:
- 点击「新增」按钮时:设置
dialogMode = "add"、taskDialogVisible = true - 点击某行的「编辑」按钮时:将当前行对象赋值给原有
selectedTask,再设置dialogMode = "edit"、taskDialogVisible = true
合并弹窗的xhtml代码
直接替换原来两个重复的p:dialog,所有动态逻辑都通过EL三元判断实现:
<p:dialog id="taskDialogId" header="#{cc.attrs.viewBean.dialogMode == 'add' ? 'Add Task '.concat(cc.attrs.viewBean.employeeToView ne auth.employee ? ' for '.concat(cc.attrs.viewBean.employeeToView.lname) : '') : 'Edit task '.concat(cc.attrs.viewBean.selectedTask.id)}" dynamic="true" widgetVar="taskDialogWv" visible="#{cc.attrs.viewBean.taskDialogVisible}"> <h:form id="taskFormId"> <!-- 所有表单组件完全复用,仅绑定值改为动态判断 --> <p:outputLabel id="taskTitleLbl" value="Task Title : " for="taskTitle" /> <p:inputText id="taskTitle" value="#{cc.attrs.viewBean.dialogMode == 'add' ? cc.attrs.viewBean.newTask.title : cc.attrs.viewBean.selectedTask.title}" /> <!-- 其余原有表单项全部按同样规则替换绑定路径即可 --> <!-- 比如隐藏的任务ID字段:编辑模式下回显,新增模式下隐藏 --> <h:inputHidden id="taskId" value="#{cc.attrs.viewBean.dialogMode == 'add' ? cc.attrs.viewBean.newTask.id : cc.attrs.viewBean.selectedTask.id}" rendered="#{cc.attrs.viewBean.dialogMode == 'edit'}" /> <!-- 底部操作按钮的提交动作也做动态判断 --> <p:commandButton value="Save" action="#{cc.attrs.viewBean.dialogMode == 'add' ? cc.attrs.viewBean.saveNewTask() : cc.attrs.viewBean.updateSelectedTask()}" update="taskFormId" oncomplete="PF('taskDialogWv').hide()" /> <p:commandButton value="Cancel" immediate="true" onclick="PF('taskDialogWv').hide()" /> </h:form> </p:dialog>
方案2:更清爽的优化版(后端加通用引用,前端不用写重复三元)
如果觉得前端写重复的dialogMode == 'add' ?三元太冗余,可以在后端viewBean中新增一个通用的activeTask属性,直接返回当前场景对应的任务对象:
// 后端新增方法,原有属性都不用改 public Task getActiveTask() { // 新增模式返回newTask,为空时自动初始化避免空指针 if ("add".equals(dialogMode)) { if (newTask == null) { newTask = new Task(); } return newTask; } // 编辑模式直接返回选中的任务 return selectedTask; }
此时前端的绑定可以大幅简化,完全不用写三元判断:
<!-- 输入框绑定直接用activeTask --> <p:inputText id="taskTitle" value="#{cc.attrs.viewBean.activeTask.title}" /> <h:inputHidden id="taskId" value="#{cc.attrs.viewBean.activeTask.id}" />
标题也可以简化为:
header="#{cc.attrs.viewBean.dialogMode == 'add' ? 'Add Task '.concat(cc.attrs.viewBean.employeeToView ne auth.employee ? ' for '.concat(cc.attrs.viewBean.employeeToView.lname) : '') : 'Edit task '.concat(cc.attrs.viewBean.activeTask.id)}"
注意事项
- 保存操作完成后记得把
taskDialogVisible设为false、dialogMode置空,避免下次打开弹窗时状态错乱 - 如果原有新增/编辑逻辑有特殊的预处理(比如编辑时要查关联数据),可以在对应触发按钮的action里做,不影响复用逻辑
- 如果使用的PrimeFaces版本不支持p:dialog的
visible属性,直接在打开弹窗的触发按钮上添加onclick="PF('taskDialogWv').show()"即可,不需要绑定visible属性 - 原有两个弹窗的
dynamic="true"属性保留,避免不必要的渲染开销
内容的提问来源于stack exchange,提问作者jeff
相关产品推荐
相关产品推荐

