tapestry - Tapestry 不允许动态组件?
问题描述
使用 Tapestry 5.3.7 我需要创建包含多个动态块的页面。
示例页面 tml:
<t:form>
<t:loop source="chosenBlockIds" value="blockId">
<t:delegate to="convertBlockIdToBlockObject(blockId)" myBlockId="${blockId}"/>
</t:loop>
<t:block id="blockA">
several text fields and select components here with zones
<t:textfield t:id="text1" value="dtoMap(blockId).text1">...
<t:select t:id="select1" t:zone="zone1" value="dtoMap(blockId).select1" ...>
<t:zone t:id="zone1" id="zone1" ...>
<t:select t:id="select2" value="dtoMap(blockId).select2" ...>
</t:zone>
</t:block>
<t:block id="blockB">
several text fields and select components here with zones
</t:block>
<t:block id="blockC">
several text fields and select components here with zones
</t:block>
</t:form>
在上一页,用户将从可能的块列表中选择要显示的块。每个块可以被多次选择,这意味着例如 blockA 可以被渲染两次。这意味着blockId不能简单地作为blockA,而必须是唯一值,如blockA_1,blockA_2。我已经设法在 selectedBlockIds 列表中创建了这样的值。在delegate中,convertBlockIdToBlockObject方法会解析blockId,例如从blockA_2会得到blockA,并返回blockA对应的Block对象。这一切正常,页面正在正确呈现。
每个组件的值都绑定到包含 text1、select1、select2 等字段的 DTO 类。每个 DTO 实例都存储在页面类的 Map<String, DTO> 中。地图键是blockId。
假设用户选择了 blockA 2x。因为blockA出现在页面2x上,所以每个block和block中的所有组件都需要知道block的唯一blockId。我尝试在委托上使用非正式参数 myBlockId,希望将值作为渲染变量传播。但是 Tapestry 不允许使用渲染变量作为块中任何组件的输入。如何将blockId传递给块中的所有组件?
现在问题发生在我提交表单或使用 Ajax 时,blockA_2 中的值混合到 blockA_1 中,这是要解决的问题。此外,select2 位于一个区域中,并根据使用 Ajax 的 select1 中的选定值进行刷新。错误地,当我在 blockA_2 中的 select1 中选择一个值时,它会更新 blockA_1 中的 select2。页面类中的代码包含声明的字段 Zone zone1,当在 select1 中更改值时,使用 onValueChanged 方法将返回 zone1.getBody()。但是我需要 zone1 2x,一个用于 blockA_1,第二个用于 blockA_2,但是由于 zone 被声明为字段,显然我不能动态声明 zone 字段。看起来像是 Tapestry 中无法解决的问题?我需要 zone1 的两个实例(动态创建),可能存储在另一个以 blockId 作为键的地图中。
页面类:
@Property
@Persist
private String blockId;
@Property
@Persist
private Map<String, DTO> dtoMap;
@Inject
private Block blockA;
@Inject
private Block blockB;
@Inject
private Block blockC;
@Component
private Zone zone1;
public Object onValueChanged(EventContext context) {
String blockId = context.get(String.class, 1);
// I need to return zone1 per blockId, but I can't declare fields dynamically
return zone1.getBody();
}
解决方案
你解释的是可行的,但你需要改变一些事情:
每当您将表单字段放入循环中时,您都需要使用t:SubmitNotifier,否则提交的值可能会被先前的迭代覆盖。请记住,Tapestry 具有静态结构。Jumpstart 中的示例http://jumpstart.doublenegative.com.au/jumpstart/examples/ajax/formlooptailored1
在
onValueChanged
,而不是返回每个区域的主体AjaxResponseRenderer#addRender(String clientId, Object renderer)
用于将具体块渲染到预定义的客户端区域,即:if (request.isXHR()) { ajaxResponseRenderer.addRender(getZoneIdFor(blockId), getBlock(blockId)); }
这里
getBlock()
可以返回 TML 中定义的实际块之一,请注意您t:Block
需要拥有t:id
才能注入:@Inject Block blockA; @Inject Block blockB; public getBlock(String blockId) { if (blockId.startsWith("blockA") return blockA; // etc. }
要实现 pt.2 ,您需要所有
t:Zone
组件都具有明确的.id="{getZoneIdFor(blockId)}"
t:id
blockId
推荐阅读
- apache-spark - 使用字典中的 value 列提取适当长度的每个新列
- javascript - 在 Vue JS 中完成加载前一个项目之后加载每个项目
- spring - 是否可以使用 Spring AOP 切入抽象类中的受保护方法?
- python - Spark 与 Web 异步调用和相同的上下文:问题?
- javascript - 带有 TS 的节点/续集/节点 - 如何使用 OR 运算符在映射内转换为数字并转换回字符串
- python - ´Discord Bot 下载 Youtube 视频 Python
- java - Postgres JSONB 列映射到 HashTrieMap 而不是 HashMap
- postgresql - 在docker中运行的cent os 7上找不到使用yum安装的postgresql客户端
- javascript - Google Developer Chart Timelines - 添加标题
- python - 有没有办法使用 NLP Python 从 pdf 文本中提取特定值?