Infopath: OnAfterChange Event Typ “delete”

Heute hatte ich es mal wieder mit dem “onAfterChange” Event zu tun. Der wird, wie der Name vermuten lässt, immer dann gefeuert, wenn ein Element geändert wird. Default schlägt Infopath den onAfterChange Eventtyp “isUndoRedo” vor - also reine Änderungen.

onAfterChange ist auch für Insert und Delete Vorgänge zuständig und wird benötigt, wenn man programmiergesteuert bei Löschvorgängen die Konsistenz der XML Logik bzw. des Infopath Formulars im Auge behalten möchte.

Für mich festgehalten und alle anderen, die gerne mal über die Eventfalle stolpern.

Das Szenario

In einer wiederholten Tabelle soll überwacht werden, ob Einträge gelöscht werden. Aufgrund eines Löschvorgangs müssen dann automatisiert auch in anderen wiederholbaren Tabellen Einträge gelöscht und bei weiteren Elementen Werte aktualisiert werden.

Ein (mehr oder weniger sinnvolles) Beispiel, hier der XML Output:

<my:Rechnung>
<my:Posten>
<my:Menge>3</my:Menge>
<my:Bezeichnung>Einheiten</my:Bezeichnung>
<my:Preis>15,00</my:Preis>
<my:Summe><45,00/my:Summe>
</my:Posten>
<my:Posten>
<my:Menge>5</my:Menge>
<my:Bezeichnung>Einheiten</my:Bezeichnung>
<my:Preis>5,00</my:Preis>
<my:Summe><25,00/my:Summe>
</my:Posten>
</my:Rechnung>

Die Hürde

Das Infopath Event Modell empfinde ich immer wieder als spannend. Irgendwie ist es nicht so ganz klar, welches Objekt für welches Event zuständig ist und wie man mit dem Event am Besten umgeht. Noch dazu: das Hilfesystem alles andere als übersichtlich und gut gemacht…

OnAfterChange: der Event, der entweder beim Löschen (delete) oder beim Anfügen (insert) ausgelöst wird.  Dies gilt jedoch in diesem Fall nicht nur für den Tabelleneintrag, also die Zeile, sondern auch für jede Zelle, also für jedes Textfeld innerhalb dieser Zeile. Nochdazu löst jede Änderung den onAfterChange Event zweimal hintereinander aus. Bei Änderungen oder Inserts wird der Wert zunächst gelöscht (Eventtyp: delete) und dann eingetragen (Eventtyp: insert).

Das alles nicht unbedingt intuitiv und meines Erachtens auch nicht wirklich gut dokumentiert.

Für das Beispiel bedeutet das, dass der Event von “my:Posten” ebenso ausgelöst werden kann wie von “my:Menge” oder auch - und das ist das wirklich Irritierende, von “my:Rechnung” - also dem Elternelement. Dies ist der Fall, sobald ein Posten-Element gelöscht wird.

Beides muss abgefangen werden:

  1. der exakte Knoten, der den Event ausgelöst hat
  2. die zugehörige Operation

Die Lösung

Die Lösung in Variante jScript analog zum obigen Beispiel. Der erste Schritt garantiert, dass nur die Delete Events überhaupt berücksichtigt werden, der zweite garantiert, dass der richtige Delete Event erwischt wird.

function mein Element::OnAfterChange(eventObj)
{
// zunächst nur die Delete Operation berücksichtigen
if ((eventObj.Operation == "Delete"))
{
var myParent = eventObj.Parent;
if(myParent.nodeName =="my:Rechnung" ){
// tu irgendwas
}
}
}

Übrigens

Ich habe in diesem Fall “onAfterChange” die Daten des gelöschten Knotens benötigt, allein, um das passende Element einer weiteren Liste zu finden, das ich daraufhin ebenso löschen möchte. Alle Kindknoten des my:Rechnung Elements sind zum Zeitpunkt onAfterChange noch verfügbar und können wie üblich abgefragt werden.

Wozu man wirklich gelungen den onAfterChange “isUndoRedo” brauchen kann - ist mir eigentlich schleierhaft. Hier jedenfalls habe ich mit “Operation” deutlich mehr Flexibilität.

 

Auch was dazu sagen?