【问题标题】:Tapestry zone update - does not retain value on page errorTapestry 区域更新 - 不保留页面错误的值
【发布时间】:2013-12-17 14:58:28
【问题描述】:

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

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

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

这大概是区域的样子:

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

When the select triggers the zone update the input is correctly updated with the given value.提交页面后,我对用户输入的值和数据库中的值进行了一些深入的计算。当触发错误时,我会在 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,并且我的文本字段中的当前值存储在由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 的回复后,我对这个问题进行了一些改进。他对我最初的问题给出了很好的回答 - 但我认为这对我没有帮助,因为我的文本字段位于一个组件中,可以在一页中多次使用。

【问题讨论】:

    标签: tapestry


    【解决方案1】:

    如果您提供一个 id (clientId),tapestry 将使用它而不是生成它自己的动态值。由于您需要一个动态值,因此您可能需要从容器传递一个 clientId 参数。注意:对于这种方法,您需要在任何 ajax 操作(例如 eventlink)的上下文中传递 clientId。

    我的组件.Java

    @Parameter(required=true, defaultPrefix="literal")
    private String clientId;
    

    我的组件.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>
    

    【讨论】:

    • 这是一个很好的观点 - 但我忘了提到它在我的情况下不一定正确。我过于简单化了。我的文本字段是可以在同一页面上多次使用的组件的一部分,其中一些实例可能在它们周围有一个区域。如果我指定一个 ID - 我很可能会遇到 ID 冲突?
    • 我将重新表述我原来的问题,以澄清有关区域和组件的部分。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多