Xpages 如何在部分更新中反转求值顺序?

Xpages 如何在部分更新中反转求值顺序?,xpages,lotus,Xpages,Lotus,我遇到过这样的情况:当对设置了部分更新的字段使用onChange事件时,部分更新的执行是在实际事件上的SSJS代码之前执行的 有没有可能扭转这种局面 在我随附的示例中,我有三个字段,一个隐藏输入和一个计算值 用户在这三个字段中输入值,隐藏组件有一个公式来计算上述字段的总和。名义*价格+费用=付款金额。 现在,客户希望有一个预定义的费用值,该值在PaymentAmount之前计算;在我的示例中,我使用0.15%的硬编码值。 然后,公式为PaymentAmount=(名义*价格*feeDef)+(名

我遇到过这样的情况:当对设置了部分更新的字段使用onChange事件时,部分更新的执行是在实际事件上的SSJS代码之前执行的

有没有可能扭转这种局面

在我随附的示例中,我有三个字段,一个隐藏输入和一个计算值

用户在这三个字段中输入值,隐藏组件有一个公式来计算上述字段的总和。名义*价格+费用=付款金额。
现在,客户希望有一个预定义的费用值,该值在PaymentAmount之前计算;在我的示例中,我使用0.15%的硬编码值。
然后,公式为PaymentAmount=(名义*价格*feeDef)+(名义*价格)

我们在一个表中设置了PaymentAmount,并将该行标记为PaymentAmountRow,以便能够更新其中的两个组件。
所有组件过去都有PaymentAmountRow的部分更新,但现在我需要组件价格来更新Fee1。我认为,如果我将部分更新更改为高于一切的组件,在本例中,周围名为dealInfo的面板将正常工作,但令我惊讶的是,部分组件的计算在计算费用的实际代码之前触发

我已经尝试了事件的所有可用参数,但没有一个有效

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
    <xp:this.resources>
        <xp:script
            src="/CommonSSJS.jss"
            clientSide="false"
        >
        </xp:script>
    </xp:this.resources>
    <xp:panel id="dealInfo">
        <xp:this.data>
            <xp:dominoDocument
                var="document1"
                formName="EquityTrade"
            >
            </xp:dominoDocument>
        </xp:this.data>
        <xp:label
            value="Nominal"
            id="label2"
        >
        </xp:label>
        <xp:inputText
            id="Nominal"
            value="#{document1.Nominal}"
        >
            <xp:eventHandler
                event="onchange"
                submit="true"
                refreshMode="partial"
                refreshId="PaymentAmountRow"
            >
                <xp:this.action><![CDATA[#{javascript:print("Nominal onChange - partial PaymentAmount");}]]></xp:this.action>
            </xp:eventHandler>
            <xp:this.converter>
                <xp:convertNumber type="number"></xp:convertNumber>
            </xp:this.converter>
            </xp:inputText>
        <xp:br></xp:br>
        <xp:label
            value="Price"
            id="label1"
        >
        </xp:label>
        <xp:inputText
            id="Price"
            value="#{document1.Price}"
        >

            <xp:this.converter>
                <xp:convertNumber type="number"></xp:convertNumber>
            </xp:this.converter>
            <xp:eventHandler
                event="onchange"
                submit="true"
                refreshMode="partial"
                refreshId="Fee1">
                <xp:this.action><![CDATA[#{javascript:print("Price onChange - update")
var Fee1:com.ibm.xsp.component.xp.XspInputText = getComponent("Fee1");
var feeDef = 0.15;
var Nominal:com.ibm.xsp.component.xp.XspInputText = getComponent("Nominal");
var Price:com.ibm.xsp.component.xp.XspInputText = getComponent("Price");
var fee = Nominal.getValue()*Price.getValue()*feeDef
Fee1.setValue(fee);
}]]></xp:this.action>
            </xp:eventHandler>
        </xp:inputText>
        <xp:br></xp:br>
        <xp:label
            value="Fee 1"
            id="label3"
        >
        </xp:label>
        <xp:inputText
            id="Fee1"
            value="#{document1.Fee1}"
        >
            <xp:this.converter>
                <xp:convertNumber type="number"></xp:convertNumber>
            </xp:this.converter>
            <xp:this.valueChangeListener><![CDATA[#{javascript:print("Value changed");
}]]></xp:this.valueChangeListener>

            <xp:eventHandler
                event="onchange"
                submit="true"
                refreshMode="partial"
                refreshId="PaymentAmountRow"
            ></xp:eventHandler>
        </xp:inputText>
        <xp:br></xp:br>

        <xp:table>
            <xp:tr id="PaymentAmountRow">
                <xp:td>
                    <xp:inputHidden
                        id="PaymentAmount"
                        value="#{document1.PaymentAmount}"
                    >
                        <xp:this.converter>
                            <xp:customConverter getAsString="#{javascript:return value.toString();}">
                                <xp:this.getAsObject><![CDATA[#{javascript:try {
    print("PaymentAmount calculation");
    var Nominal:com.ibm.xsp.component.xp.XspInputText = getComponent("Nominal");
    var Price:com.ibm.xsp.component.xp.XspInputText = getComponent("Price");
    var Fee1:com.ibm.xsp.component.xp.XspInputText = getComponent("Fee1");

    var nominal = Nominal.getValue();
    var price = Price.getValue();
    var fee1= Fee1.getValue();

    var paymentAmount = nominal * price;
    paymentAmount+=fee1;
    return paymentAmount;
} catch(e){
    dBar.info(e);
}}]]></xp:this.getAsObject>
                            </xp:customConverter>
                        </xp:this.converter>
                    </xp:inputHidden>
                    <xp:text
                        escape="true"
                        id="computedField14"
                    >
                        <xp:this.value><![CDATA[#{document1.PaymentAmount}]]></xp:this.value>
                        <xp:this.converter>
                            <xp:convertNumber type="number"></xp:convertNumber>
                        </xp:this.converter>
                    </xp:text>
                </xp:td>
            </xp:tr></xp:table>
    </xp:panel>
</xp:view>

我不能100%确定我是否理解代码或是哪个部分导致了问题,但我认为是转换器的getAsObject()在eventHandler的应用程序逻辑之前运行,没有获得正确的值。下面是:

XPages(和JSF)部分刷新生命周期分为六个阶段: 1) 还原视图重建组件树,以便我们可以将发送回的HTML映射回底层Java对象。 2) 应用请求值获取在HTML中输入的字符串值,并将其放入每个相关组件的submittedValue属性中。 3) 过程验证运行所有转换器和验证器,以确保submittedValue属性可以转换为基础数据类型,并通过服务器上定义的任何验证规则。 4) 更新模型值获取这些submittedValue(现在我们知道我们可以将它们应用到数据模型中,而不会把事情搞砸!),将字符串转换为相关的数据类型,将它们放在value属性中,并将submittedValue设置为null。(它可能在流程验证阶段转换了字符串并将其存储在内部变量中,因此在此阶段只需更新value和submittedValue,不确定。) 5) 调用应用程序运行eventHandler逻辑。 6) 呈现响应为浏览器生成更新的HTML

你不能改变顺序。因此,必须在更新模型值之前运行流程验证。否则,更新模型值可能会因为数据类型错误而中断,或者您存储了一个无效值,该值随后将写入基础文档

我认为问题在于您的转换器使用的是getComponent().getValue()。但在流程验证阶段,即转换器的getAsObject()方法正在运行时,不会设置该值

如果是这样,您实际需要的是:

  • 要使用getComponent().getSubmittedValue(),请验证转换器中其他组件的值,并相应地抛出错误

  • 只需使用一个基本的数字转换器,将设置付款金额的代码移动到eventHandler,与后端数据进行交互,从而获取document1.Price等并设置document1.paymentAmount

如果您使用后者,您应该能够避免使用INPUTHIDEN。

Thx,我将尝试一下……我向SSJS资源添加了一个方法,使用该方法计算所有字段并设置PaymentAmount。然后,正如您所说,我在没有验证/转换的情况下将字段更改为“普通”文件。