如何在部分更新中颠倒评估顺序?

时间:2014-10-07 13:14:34

标签: xpages lotus

我遇到过在部分更新设置的字段上使用onChange事件时,部署更新的执行是在之前执行实际事件的SSJS代码。

有没有办法扭转这种局面?

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

用户在这三个字段中输入值,隐藏组件有一个公式来计算上面字段的总和。标称*价格+费用= PaymentAmount。
现在,客户希望在PaymentAmount之前获得预先计算的费用值;在我的例子中,我使用0.15%的硬编码值 公式将是PaymentAmount =(标称*价格*费用)+(标称*价格)

我们已将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>

1 个答案:

答案 0 :(得分:1)

我不是100%确定我理解代码或导致问题的部分,但我认为转换器的getAsObject()在应用程序逻辑之前运行eventHandler并没有得到正确的值。所以这里:

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

您无法更改订单。因此,必须在更新模型值之前运行流程验证。否则,更新模型值可能会因为数据类型错误而中断,或者您存储了无效值,然后将其写入基础文档。

我认为问题是你转换器正在使用getComponent()。getValue()。但是在过程验证阶段(即转换器的getAsObject()方法正在运行时)已经设置了值。

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

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

  • 只需使用基本数字转换器并将代码设置为eventHandler,并与后端数据进行交互,从而获取document1.Price等并设置document1.paymentAmount。

如果使用后者,则应该能够避免使用inputHidden。