Tapestry 区域更新 - 不保留页面错误的值



我有一个组件,可以在一个区域中使用,该区域由选择更新。

这大致是我的组件的样子:

<div>
    <input
            t:type="textfield"
            t:id="integerPart"
            class="integerPart ${cssClass}"/>
</div>

大致如下:

<t:zone t:id="myZone" id="myZone">
    <t:mycomponent />
</t:zone>

当选择触发区域更新时,输入将正确更新为给定值。提交页面后,我对用户输入的值和数据库中的值运行一些深入的计算。当触发错误时,我会在 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
}

processSubmit在提交页面时被调用,我的文本字段中的当前值存储在由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的回复之后,我稍微尖锐了这个问题。他对我最初的问题给出了一个很好的答案 - 但我认为这对我没有帮助,因为我的文本字段位于一个可以在一个页面中多次使用的组件中。

如果您提供 id (clientId),tapestry 将使用该 ID 而不是生成自己的动态值。由于需要动态值,因此可能需要从容器传递 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}"/>

我的页面.tml

<t:mycomponent clientId="instance1" ... />
<t:mycomponent clientId="instance2" ... />
<t:loop source="1..10" value="current">
    <t:mycomponent clientId="prop:current" ... />
</t:loop>

相关内容

最新更新