Domino 9 und frühere Versionen > ND8: Entwicklung - XPages

Partial refresh aktualisiert auch andere Elemente

(1/5) > >>

eknori (retired):
Bin letzte Woche im Zuge einer Fehleranalyse auf ein Problem gestossen, das auch für andere relevant sein könnte. Im XPages Forum bei IBM habe ich das Problem schon gepostet; dort hält man sich aber liever vornehm zurück.

Ich erkläre die Situation am besten einmal anhand eines kleinen code snippets,mit dem ich den Fehler unter 8.5.3UP1 reproduzieren kann


--- Code: ---<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:button value="Label" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="col1" />
</xp:button>
<xp:table>
<xp:tr>
<xp:td id="col1">
<xp:text escape="true" id="computedField2" value="#{javascript:@Now()}">
<xp:this.converter>
<xp:convertDateTime type="both" />
</xp:this.converter>
</xp:text>
</xp:td>
<xp:td id="col2">
<xp:text escape="true" id="computedField1" value="#{javascript:@Now()}">
<xp:this.converter>
<xp:convertDateTime type="both" />
</xp:this.converter>
</xp:text>
<xp:dataTable id="dataTable1" rows="30">
<xp:this.value><![CDATA[#{javascript:
print('You shall not refresh');
}]]></xp:this.value>
<xp:column id="column1" />
</xp:dataTable>
</xp:td>
</xp:tr>
</xp:table>
</xp:view>

--- Ende Code ---

EinfacheXPage mit einer 2 spaltige Tabelle

col1 enthält ein computedText control mit @Now()
col2 enthält ein computedText control mit @Now() + einer datatable. In den Values der datatable gibt es lediglich ein print statement.

Das erwartete Verhalten ist:

Click auf den Button, der sich über der Tabelle befindet; dies löst einen partial refresh auf col1 aus. Die Anzeige wird dort aktualisiert. Die Anzeige in col2 nicht.
Das funktioniert.

Was aber ist mit der datatable? Man könnte erwarten, daß diese nicht vom partial refresh aktualisiert wird; sie befindet sich ja in col2

Aber weit gefehlt: Blick auf die ServerConsole. Und was sehen meine Augen dort bei jedem Click auf den Button?

Richtig: You shall not refresh

Das kann doch nicht wirklich richtig sein, oder ??

Sven Hasselbach:
Hallo,

ich habe im XPages Forum eine kurze, aber einfache Antwort gegeben  ;)

Es ist leider ein "normales" Verhalten seit es XPages gibt: Alle Datencontainer (Datatable, Repeats, Datacontexts ) werden bei Partial Refreshs neu berechnet, sogar mehrfach, auch Partial Execution hilf da nicht.

Für Datatables geschieht dies in der "Apply Request Values"-Phase, als auch in der "Render Response"-Phase, bei Data Context-Variablen sieht das ganz noch übler aus (in JEDER Phase findet die Berechnung statt).

Beispel Code für eine "verzögerte" Data Context-Variable, da kann man das auf der Konsole besser sehen:


--- Code: ---<xp:this.dataContexts>
   <xp:dataContext var="x">
      <xp:this.value><![CDATA[#{
         javascript:print( java.lang.System.currentTimeMillis() + " -> DC Recalc! ");
         java.lang.Thread.currentThread().sleep(100);
         '1'}]]>
      </xp:this.value>
   </xp:dataContext>
</xp:this.dataContexts>

--- Ende Code ---

Das Beispiel verdeutlich auch nochmal, das die Berechnung wirklich mehrmals ausgeführt wird. Richtig ist das nicht...

Ich habe mir damit beholfen, die Refresh-Id abzufangen, und dann die Berechnung ggf. Abzubrechen


--- Code: ---<xp:repeat id="repeat1" rows="30" var="rCol">
   <xp:this.value><![CDATA[#{javascript:
      function calculate(){
         var data:java.util.Vector = new java.util.Vector();
         data.add(java.lang.System.currentTimeMillis());
         return data;
      }

      if( viewScope.containsKey("data") == false){
         viewScope.data = calculate();
         return viewScope.data;
      }
      if( com.ibm.xsp.ajax.AjaxUtil.isAjaxPartialRefresh(facesContext) === true ){
         var pId = com.ibm.xsp.ajax.AjaxUtil.getAjaxComponentId( facesContext  );
         if( pId !== getClientId( 'repeat1' ) )
            return viewScope.data;
      }

      viewScope.data = calculate();
      viewScope.data}]]>
   </xp:this.value>
   <xp:label value="#{javascript:rCol }" id="label1"></xp:label>
</xp:repeat>

--- Ende Code ---

Sven

eknori (retired):
Danke für die Antwort (und die Bestätigung meiner beobachtungen)


--- Zitat ---werden bei Partial Refreshs neu berechnet, sogar mehrfach,
--- Ende Zitat ---

--- Zitat ---bei Data Context-Variablen sieht das ganz noch übler aus (in JEDER Phase findet die Berechnung statt).

--- Ende Zitat ---
Genau da ist das Problem bei uns aufgetreten; da wurden ~ 2.500 Dokumente insgesamt 8 mal komplett neu berechnet.  Und dann das Ganze gleich 1 - n fach, da wir mehrere Dokumente im TabContainer öffnen. Das geht dann ganz schnell in Richtung "Unbrauchbarkeit".

Dann wird also nichts weiter helfen, als das abzufedern. Gut, dann weiss ich wenigstens, dass es kein Bug, sondern ein feature ist.

Ist das eigentlich irgendwo "offiziell" dokumentiert, oder hast du es auch über den schmerzhaften Weg herausgefunden?


Würde dann also bedeuten, daß die Neuberechnungen auch dann ausgeführt werden wenn ich ein simple binding auf eine view mache. Nur daß es da nicht "auffällt", weil man dort nichts per print auf der Konsole ausgeben kann.
Wundert mich echt, daß das noch niemandem so wirklich aufgestossen ist. Offensichtlich enthalten die Applikationen bei anderen nur ein paar Datensätze. Dann ist das Verhalten sicher zu verschmerzen.
Bei uns kam schnell die Denke auf, "wenn das da passiert, dann möchte ich gerne mal wissen, wo solche versteckten Bremsen noch überall eingebaut sind". Und über mangelhafte Performance in manchen Situationen müssen wir uns dann auch nicht weiter wundern.
Das verkaufe mal dem Auftraggeber ... Selbst wenn sich im Idealfall ein paar leute finden, die gewillt sind auf den Zug PMR aufzuspringen, habe ich aus Erfahrung die Vermutung, daß das seitens IBM als "works as designed" abgetan wird. In JEDE Datenquelle eine Abfrage einzubauen ist ein netter Workaround, aber auf Dauer nicht der richtige Weg.

Auf der einen Seite freut es mich, daß ich nicht wieder der Einzige bin, auf der anderen Seite hat mir die Antwort den Tag echt vermiest.

Sven Hasselbach:
Tut mir leid, Dir den gestrigen Tag vermiest zu haben.

Ich habe das auch über den schmerzvollen Weg rausbekommen und ich denke nicht, dass das näher dokumentiert ist. "Works as designed" ist das Stichwort, denn das Verhalten ist durchaus erklärbar und es ist (glaube ich) auf die nicht JSF-konforme Implementierung des SSJS zurückzuführen.

Beispielsweise das dürfte nicht gehen, geht aber:
${'#'}{javascript:Java.lang.System.currentTimeMillis()}

Ein Compute On Page Load wird zu einem Computer Dynamically aber das Binding ist weiterhin im Page Load... Gemäß Unified EL Spezifikation nicht zulässig.

Eine "saubere" EL hingegen könnte funktionieren, d.h. simple Bindings bzw. Managed Beans müssten ohne Neuberechnung funktionieren. Aber das muss ich noch ausprobieren, mache ich die Tage.

Zwei Tipps noch:
1. Partial Refreshs möglichst mit GET ausführen, das vermindert die Anzahl der Neuberechnungen (oder mit execMode="partial" arbeiten)
2. Datenquellen nach Möglichkeit mit Computer On Page Load berechnen

Einen schönen Sonntag noch
Sven

eknori (retired):
Jetzt kapier ich es gar nicht mehr, Habe in beiden Buttons PartialExecutionMode gesetzt und schon funktioniert es, wie beabsichtigt.
Ich bin mir 100% sicher, daß es in dieser Konstellation vorher nicht funktioniert hat.
Also, Testreihe noch einmal von vorne.

Navigation

[0] Themen-Index

[#] Nächste Seite

Zur normalen Ansicht wechseln