我有一个可以在区域中使用的组件,该区域由选择更新。
这大致与我的组件类似:
<div>
<input
t:type="textfield"
t:id="integerPart"
class="integerPart ${cssClass}"/>
</div>
这大致是该区域的样子:
<t:zone t:id="myZone" id="myZone">
<t:mycomponent />
</t:zone>
当select触发区域更新时,输入会使用给定值正确更新。提交页面时,我会对用户输入的值和数据库中的值进行一些深度计算。当触发错误时,我在ValidationTracker中记录该错误,页面将被刷新,错误将显示在我页面的全局标记中。
问题是当页面刷新并显示错误消息时,我的文本字段的值将丢失。这样做的原因是tapestry重写了区域内的id: http://tapestry.apache.org/ajax-components-faq.html
和AbstractTextField中的这两个实现方法:
@BeginRender
void begin(MarkupWriter writer)
{
String value = tracker.getInput(this);
// lots of code
}
@Override
protected void processSubmission(String controlName)
{
String rawValue = request.getParameter(controlName);
tracker.recordInput(this, rawValue);
// lots of code
}
在提交页面时调用processSubmission,并且我的textfield中的当前值存储在由id:“integerPart_12a820cc40e”标识的映射中,而当重新加载页面时再次打印它时会显示错误消息组件在地图中查找键“integerPart”。这不会产生匹配,文本字段将呈现为空(即值丢失)。
我认为这是Tapestry中的一个已知问题,应该可以快速轻松地修复它。我现在正以“不那么快速和简单”的方式解决这个问题,这种方式完全错了。
我扩展TextField,并使用id:“integerPart”而不是“integerPart_12a820cc40e”存储该值。这是由这个班级完成的:
import org.apache.tapestry5.BindingConstants;
import org.apache.tapestry5.Field;
import org.apache.tapestry5.ValidationTracker;
import org.apache.tapestry5.annotations.Environmental;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.corelib.components.TextField;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.Request;
public class ZoneFriendlyTextField extends TextField {
@Inject
private Request request;
@Environmental
private ValidationTracker tracker;
// copied from Abstract Field - to be able to use it here
@Parameter(value = "prop:componentResources.id", defaultPrefix = BindingConstants.LITERAL)
private String localClientId;
@Override
protected void processSubmission(String controlName)
{
super.processSubmission(controlName);
String submittedValue = request.getParameter(controlName);
tracker.recordInput(new TextFieldInternalField(localClientId), submittedValue);
}
/**
* This class is only used since the controlName of DateFieldset in a zone returns with a random id and
* it is not possible to match against the right value when page-errors occur and we have to present
* the user with the user-entered values again.
* Should only be used for recording input in the tracker.
*/
private static class TextFieldInternalField implements Field {
String clientId;
private TextFieldInternalField(String clientId) {
this.clientId = clientId;
}
@Override
public String getClientId() {
return null;
}
@Override
public String getControlName() {
return clientId;
}
@Override
public String getLabel() {
return null;
}
@Override
public boolean isDisabled() {
return false;
}
@Override
public boolean isRequired() {
return false;
}
}
}
如果有人能想出更好的解决方案,我真的很感激! : - )
注意:在Lance Java的回复之后我稍微提了一下这个问题。他对我原来的问题给出了一个非常好的答案 - 但我认为它不会对我有所帮助,因为我的文本字段位于一个可以在一个页面中多次使用的组件中。
答案 0 :(得分:1)
如果你提供了一个id(clientId),那么tapestry将使用它而不是生成它自己的动态值。由于您需要动态值,因此可能需要从容器传递clientId参数。注意:对于这种方法,您需要在任何ajax操作(例如eventlink)的上下文中传递clientId。
MyComponent.Java
@Parameter(required=true, defaultPrefix="literal")
private String clientId;
MyComponent.tml
<input t:type="textfield" id="${clientId}" t:id="integerPart" class="integerPart ${cssClass}"/>
MyPage.tml
<t:mycomponent clientId="instance1" ... />
<t:mycomponent clientId="instance2" ... />
<t:loop source="1..10" value="current">
<t:mycomponent clientId="prop:current" ... />
</t:loop>