What check box was clicked?

In a previous blog post we answered the question "What button was clicked?" when a Button control is inside a repeating context like a Repeating Section control. A similar situation has a slightly different answer that's worth calling out for those readers still learning about XPaths and InfoPath's events.

Here's a different schema:

  • Root
    • People
      • Person
        • Name
        • IsApproved

And you could build a form like this:

The previous blog would have let you get from the Button's OnClick event to the data items in the row. But what about the Check Box?

The Button is an unbound control, so it doesn't have data change events, just OnClick. And in the event object, the Source is the Button's context (the Person node in this case)

The Check Box is a bound control (bound to the IsApproved node) so it has data change events instead: OnBeforeChange, OnValidate, and OnAfterChange. And the Source will be the node that actually changes.

Tricky Bit #1: In an XML DOM, the nodes aren't just elements and attributes. The text contents of elements are nodes themselves. So when a user checks the Check Box, the node that changes is not the IsApproved node, but the text node inside! So the Source will be a text node. If you add this to the OnAfterChange for the IsApproved node, you'll see that the Source is just the text node:

XDocument.UI.Alert( eventObj.Source.xml );

Tricky Bit #2: If you check the checkbox, you'll actually see two alerts - first with "false" then with "true". To make this clearer, change the code as follows:

XDocument.UI.Alert(
"Source: " + eventObj.Source.xml + "n" +
"Operation: " + eventObj.Operation
);

You'll see that the first operation was a "Delete" of the "false" value, followed by an "Insert" of the "true" value. This shows just how fine grained the InfoPath data eventing model is.

So, back to the problem at hand - how do we get at the other items in the row?

For Tricky Bit #1, you can either add an extra ".." step in your XPath to step up from the text node, or use the Site property of the event object instead. The Site is this is the node where the event is being processed, and since the event handler is on the IsApproved element, the node will be the IsApproved element. (Note that a Button's event object is a different type, and only contains Source not Site, since the event doesn't bubble.)

For Tricky Bit #2, you can simply ignore every operation type other than "Insert".

Putting all of that together, you'll end up with event-handling logic like this:

if( eventObj.Operation == "Insert" )
{
XDocument.UI.Alert( eventObj.Site.selectSingleNode( "../my:Name").text );
}

One last note - in the form shown, this event will fire and an alert will be shown whenever a new row is inserted into the table. So depending on what you are trying to accomplish, you might also want to filter out default values - such as empty strings - from further processing.