¿Cómo invertir el orden de evaluación en actualización parcial?
Frecuentes
Visto 133 equipos
0
Me he encontrado con que al usar un evento onChange en un campo con un conjunto de actualizaciones parciales, se realiza la ejecución de la actualización parcial. antes el código SSJS en el evento real.
¿Hay alguna manera posible de revertir esto?
En mi ejemplo adjunto, tengo tres campos, una entrada oculta y un valor calculado.
Los usuarios ingresan valores en estos tres campos y el componente oculto tiene una fórmula para calcular la suma de los campos anteriores. Nominal * Precio + Tarifa = ImportePago.
Ahora el cliente quiere tener un valor de tarifa predefinido que se calcule antes de PaymentAmount; en mi ejemplo utilizo un valor codificado de 0.15%.
Entonces, la fórmula será ImportePago = (Nominal * Precio * feeDef) + (Nominal*Precio)
Hemos establecido PaymentAmount dentro de una tabla donde hemos etiquetado la Fila como PagoImporteFila solo para poder actualizar ambos componentes dentro.
Todos los componentes solían tener una actualización parcial en PagoImporteFila pero ahora también necesito el componente Price para actualizar Fee1. Pensé que si cambiaba la actualización parcial a un componente por encima de todo, en este caso, el panel circundante llamado tratoInfo funcionará bien, pero para mi sorpresa, el cálculo del componente parcial se activa antes que el código real que calcula la tarifa.
Probé todos los parámetros disponibles en el evento pero ninguno de ellos funciona...
<?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 Respuestas
1
No estoy 100% seguro de entender el código o qué parte está causando el problema, pero creo que getAsObject() del convertidor se está ejecutando antes que la lógica de la aplicación eventHandler y no obtiene los valores correctos. Así que aquí va:
El ciclo de vida de actualización parcial de XPages (y JSF) se ejecuta en seis fases: 1) Restaurar vista reconstruye el árbol de componentes para que podamos mapear el HTML que se envía de vuelta a los objetos Java subyacentes. 2) Aplicar valores de solicitud toma los valores de cadena ingresados en el HTML y los coloca en la propiedad namedValue de cada componente relevante. 3) Validación del proceso ejecuta todos los convertidores y validadores para garantizar que las propiedades de namedValue se puedan convertir al tipo de datos subyacente y pasar las reglas de validación definidas en el servidor. 4) Actualizar los valores del modelo toma esos valores enviados (¡ahora sabemos que podemos aplicarlos al modelo de datos sin arruinar las cosas!), convierte las cadenas al tipo de datos relevante, las coloca en la propiedad de valor y establece el valor enviado en nulo. (Es posible que haya convertido las cadenas durante la fase de validación del proceso y las haya almacenado en variables internas, por lo que solo necesita actualizar el valor y el valor enviado en esta fase, no estoy seguro). 5) Invocar aplicación ejecuta su lógica eventHandler. 6) Respuesta de procesamiento genera el HTML actualizado para el navegador.
No puedes cambiar el orden. Por lo tanto, Process Validations debe ejecutarse antes de Update Model Values. De lo contrario, Actualizar valores del modelo podría fallar debido a que el tipo de datos es incorrecto o ha almacenado un valor no válido que luego se escribirá en su documento subyacente.
Creo que el problema es que su convertidor está usando getComponent().getValue(). Pero el valor no se habrá establecido durante la fase de validación del proceso, que es cuando se ejecuta el método getAsObject() del convertidor.
Si es así, lo que realmente necesita es:
- Para usar getComponent().getSubmittedValue(), valide los valores de los otros componentes en su convertidor y arroje los errores correspondientes.
or
- Simplemente use un convertidor de números básico y mueva su código configurando el monto del pago al eventHandler, interactuando con los datos de back-end, obteniendo document1.Price, etc. y configurando document1.paymentAmount.
Si usa este último, debería poder evitar la necesidad de inputHidden.
Respondido 08 Oct 14, 14:10
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas xpages lotus or haz tu propia pregunta.
Agregué un método a un recurso SSJS usando esto para calcular todos los campos y establecer el Monto de Pago. Luego, como dijiste, cambié el campo a un archivo "normal" sin validación/conversión. - Mikael Andersson Wigander