Handling Multiple Notifications [InfoPath 2003 SDK Documentation]

Applies to:

Microsoft Office InfoPath 2003

Microsoft Office InfoPath 2003 Service Pack 1

The InfoPath event model can cause multiple event notifications to occur when changes are made to the elements in the XML document associated with a form. This topic describes how to handle multiple notifications caused by:

  • Text changes in leaf elements and attributes
  • Event propogation

Handling Notifications for Text Changes in Leaf Elements and Attributes

The InfoPath event model is based on changes to the XML Document Object Model (DOM). Every time the text value of a node is changed in a form open in InfoPath, two notifications occur for the two operations that are performed in the XML document associated with the form: a deletion and an insertion. When the text of a node is changed, InfoPath first deletes the node, then inserts a new node in its place that contains the new value. Because the InfoPath event model is based on the actual changes in the XML DOM, it does not behave like events in applications such as Microsoft Office Word or Microsoft Office Excel where you would receive a single notification for changes to the value of a field or cell.

When a user adds a new node to the XML DOM, such as when adding a new section to a repeating section by selecting Insert <section name> below, the events are fired only once for the action of adding a new node. In the same scenario, if the user changes the node's value by changing the text of a field bound to a Text Box control, the events are fired twice because in the XML DOM the following actions occur:

  1. The old text node is removed from the XML DOM (the Operation property of the DataDOMEvent event object will return "Delete").
  2. A new text node is added to the XML DOM (the Operation property of the DataDOMEvent event object will return "Insert").

Developers need to bear this in mind when they write event handlers for the OnBeforeChange and OnAfterChange events. Otherwise, their code may be executed twice. The notification behavior of InfoPath is summarized in the following table, where leaf node refers to a node that has only text content, that is an attribute (attribute field) or an element with a simple type (element field). The properties referenced are the Operation, Source, and Parent properties of the DataDOMEvent object.

Action Operation Property Source and Parent Properties
Changing the value of a non-blank leaf node Delete, Insert Source = text child of the leaf node
Parent = the node itself
Changing the value of a blank leaf node Insert Source = text child of the leaf node
Parent = the node itself
Inserting a node (element or attribute) Insert Source = the node
Parent = the parent element into which the node was inserted
Deleting a node (element or attribute) Delete Source = the node
Parent = the parent element from which the node was deleted

In all cases, the Site property of the DataDOMEvent object returns the node where the event and operation are handled, for example a repeating section (that may contain multiple elements) where an OnAfterChange event is firing. This will typically be the element that you will be interested in working with. For more complex scenarios, see "Handling Multiple Notifications Due to Event Propogation" later in this topic.

For example, assume you have the following XML structure, where a Product is composed of multiple Items. For every change in the Product node you need to update the value of the TotalItems element to reflect the total number of Item elements.

<Products>
    <Product productID="12">
         <Item description="Item1 description" />
         <Item description="Item2 description" />
        <TotalItems/>
    </Product>
    <Product productID="13">
         <Item description="Item1 description" />
         <Item description="Item2 description" />
         <TotalItems/>
    </Product>
 </Products>

The following example shows how to account for double notifications when changes are made to the value of a leaf node by checking the value of the Operation property to make sure that event handler code will only run for "Insert" operations. It also uses the Site property to access the value of the node to work with.

function msoxd_my_productID::OnAfterChange(eventObj)
{
    // The value returned by the Site property in this event handler is 
    // the productID attribute of the Product element.

    // If the change did not occur to the text node child of this attribute
    // (nodeType = 3), or if it is a delete operation, then ignore it. 
    // This means that only insert or update operations on
    // text changes will be handled.
    if((eventObj.Source.nodeType != 3) || (eventObj.Operation == "Delete"))
        return;

    // At this point, the value of the Source property is the text value 
    // of the productID attribute. Your code to handle this change
    // goes here.
    XDocument.UI.Alert("Product ID changed");
}

Handling Multiple Notifications Due to Event Propogation

Additionally, when working with non-leaf nodes (groups), there are scenarios where InfoPath will fire multiple events due to event bubbling. This occurs when an event "bubbles up" from node to node through the XML DOM tree hierarchy from the source of the event up to the document root. Wherever an event handler is associated with a node along the path on which the event is being bubbled, InfoPath invokes that handler. For event handlers attached to non-leaf nodes, you can avoid notifications caused by changes deeper down in the tree by adding the following if statement to your code.

if (eventObj.Site != eventObj.Parent)
{
    return;
}

Using the Products XML structure defined in the previous section as an example, if you want to make sure that the value of the TotalItems element is calculated correctly when a user changes a value, use the following strategy:

  • Add an event handler to the Product element's OnAfterChange event to recalculate the total number of Item elements.

Because of event bubbling, the OnAfterChange event of the Products element will be fired every time the nodes lower in the XML hierarchy are modified (updated, inserted, or deleted), for example when a user changes the value of an Item's description attribute.

To avoid recalculating the total number of Item elements when it is not strictly necessary, add an event handler that uses the if statement shown at the beginning of this section to the Product node's OnAfterChange event.

function msoxd_my_Product::OnAfterChange(eventObj)
{
    // The value returned by the Site property in this event handler is 
    // the productID attribute of the Product element.

    // The change is ignored if it does not involve
    // immediate children of the Product element. 
    if(eventObj.Site != eventObj.Parent)
    {
        return;
    }

    // At this point, the value of the Source property will be any 
    // child node of the Product element (in particular, any Item
    // node).
    
    // Add code here to update the total number of Item elements here.
}

The If statement determines if the node that is firing the event (the node returned by the Source property) is an immediate child of the site node that is listening for event notifications (in the case for this example, the Site property will return the Product node). As a result, the OnAfterChange event handler for the Products element will do nothing for all the changes that happen below the level of the Item elements.