March 2006 - Posts - Matt Faus
in

InfoPath Dev

Matt Faus

March 2006 - Posts

  • Add Custom Buttons to the Repeating Table and Section Widget

    A powerful technique to add extra functionality to a form without cluttering up a design that has been perfected is to add custom buttons to the widget menus of repeating tables and sections. Although this is not an easy task, it is definitely attainable through InfoPath’s open standard application model, and once completed will provide a very powerful and clean addition to your form.


    Figure 1. A preview of the final product of this How-To.

    In this task we will edit the manifest.xsf of a form template to add a button to the widget icon of a repeating table and add a custom event handler function that will execute upon the clicking of the custom button. Then, we will extend our form to respond to context-specific widget events. Let’s start by designing a new blank form.

    Design the form:

    1. In the Controls task pane click Repeating Table to insert a repeating table with 3 columns.
    2. Type Name, Department, and E-mail into the repeating table headings. Refer to Figure 2.
    3. Open the Data Source task pane and edit the names of the automatically generated schema nodes to match Figure 3. This is done by double-clicking the node in the Data Source task pane, editing the Name field, and then clicking OK.


    Figure 2. The form design.


    Figure 3. The data source.

    Make the Department column a drop-down list:

    In order to predefine the options for the Department field and simplify the code that will run behind our form, it is a good idea to only allow a predefined set of values for the Department field. In order to this we will change the textbox control to a drop-down list.

    1. Right-click the Department textbox control on the view, select Change To, and then click Drop-Down List Box.
    2. Double-click the new drop-down list in the view to open the Drop-Down List Box Properties dialog.
    3. In this dialog, click Add in the List box entries section, and then type Sales in the box that pops up. This will add the Sales option to the drop-down box.
    4. Repeat step 3 for the following options: Marketing, Management, Research. Refer to Figure 4.


    Figure 4. Adding the drop-down list items.

    Extract the form files:

    InfoPath .xsn files are actually a compressed package file that contains quite a few other files, such as sample data files and configuration files. In order to edit the manifest.xsf file and add custom widget buttons we must extract these form files so that we can work with them individually. To repackage the files into an .xsn file you will publish the form to a new location.

    1. In the Form Designer, choose Extract Form Files from the File menu.
    2. Create a new folder somewhere where you can easily find the folder again and name it HowTo – Custom Widget Buttons.
    3. Click OK.
    4. Close the InfoPath Designer.
    5. Browse to the HowTo – Custom Widget Buttons folder.

    Edit manifest.xsf:

    In order to edit the form files directly, we must close the InfoPath Designer so InfoPath will release the lock and these files. In the next few steps we will be editing the manifest.xsf (which stores XML) directly.

    1. Open manifest.xsf in a text editor.
    2. Move the insertion point to the end of line 69, type Enter, and then paste the following code into the manifest.xsf.

    Note: The XSF file is automatically generated by InfoPath, so the insertion point might not be exactly at line 70. Please use Figure 5, which displays a large section of the XSF, to determine to the appropriate context for your form.

    <!-- Custom widget buttons -->
    <xsf:button name="widgetEmailThisContact" caption="Email this Contact"/>       
    <xsf:button name="widgetEmailAll" caption="Email all Contacts"/>
    <xsf:menu caption="&amp;Email Department...">
        <xsf:button name="widgetEmailSales" caption="Sales"/>
        <xsf:button name="widgetEmailMarketing" caption="Marketing"/>
        <xsf:button name="widgetEmailManagement" caption="Management"/>
        <xsf:button name="widgetEmailResearch" caption="Research"/>           
    </xsf:menu>
    <!-- End custom widget buttons -->

    1. Save and close the manifest.xsf file.
    2. Browse to the HowTo – Custom Widget Buttons folder in Windows Explorer, right-click manifest.xsf, and then select Design to open the InfoPath Designer.


    Figure 5. Editing the XSF file.

    Add code to handle the button click events:

    1. From the Tools menu choose Programming | Microsoft Script Editor to open the code editor.
    2. At the very bottom of the file that is created in Microsoft Script Editor paste the following code.

    function widgetEmailAll::OnClick()
    {
        var sEmailAddresses = compileEmailString( "All" );   
        XDocument.UI.Alert( sEmailAddresses );
    }

    function widgetEmailSales::OnClick()
    {
        var sEmailAddresses = compileEmailString( "Sales" );   
        XDocument.UI.Alert( sEmailAddresses );
    }

    function widgetEmailMarketing::OnClick()
    {
        var sEmailAddresses = compileEmailString( "Marketing" );   
        XDocument.UI.Alert( sEmailAddresses );
    }

    function widgetEmailManagement::OnClick()
    {
        var sEmailAddresses = compileEmailString( "Management" );   
        XDocument.UI.Alert( sEmailAddresses );
    }

    function widgetEmailResearch::OnClick()
    {
        var sEmailAddresses = compileEmailString( "Research" );   
        XDocument.UI.Alert( sEmailAddresses );
    }

    function compileEmailString( department )
    {
        var sEmailString = "";
       
        // Grab e-mail regardless of department.
        if( department == "All" )
        {
            var nlContactsEmail = XDocument.DOM.selectNodes( "/my:AddressBook/my:Contacts/my:Contact/my:Email" );
           
            while( (nContactEmail = nlContactsEmail.nextNode()) != null )
                sEmailString += nContactEmail.text + "; ";       
        }
        // Department has been specified.
        else
        {
            var nlContactsEmail = XDocument.DOM.selectNodes( "/my:AddressBook/my:Contacts/my:Contact[my:Department = '" + department + "']/my:Email" );
           
            while( (nContactEmail = nlContactsEmail.nextNode()) != null )
                sEmailString += nContactEmail.text + "; ";       
        }

        return sEmailString;   
    }

    Try it:

    The actual code to send e-mails from within InfoPath is not within the scope of this document, and the pop-up displaying the e-mail address string is displayed in an alert box to demonstrate the ability of the custom widget button.

    1. Save the JScript file by choosing Save from the File menu, and then switch back over to the InfoPath Designer.
    2. Click Preview Form, insert a few contacts with e-mail addresses and then click the widget buttons to see a pop-up corresponding to the appropriate e-mail addresses.


    Figure 6. The result of clicking the Email all Contacts custom widget button.

    Add context-specific functionality for the Email this Contact button:

    As you were trying out the form, it is important to note that the widget buttons created so far are not related to a specific row in the table and performed functions related to the form as a whole. To add functions that relate to the specific context of the widget button clicked (such as the Email This Contact button), you must add a OnContextChange event handler and a private variable in your code to maintain where the user is currently in the form.

    Add the OnContextChange event handler and private variable:

    1. In the InfoPath Designer choose Programming | On Context Change Event from the Tools menu. This will open the Microsoft Script Editor again and generate an OnContextChange event handler function.
    2. Replace the content of the event handler with the following code:

    if (eventObj.Type == "ContextNode")
    {       
        var nContextNode = eventObj.Context;
       
        // This node might actually be one of the column nodes for the
        // row, but we always want to work with the Contact.
       
        // If this is a child node, change reference to parent node
        if( nContextNode.parentNode.nodeName == "my:Contact" )
            nContextNode = nContextNode.parentNode;
       
        // Update the global variable with the current row node.
        nCurrentRow = nContextNode;
        return;
    }

    1. At the very top of your code, add this line to declare a global variable:

    var nCurrentRow;

    1. Now we must add the function to handle the event of the Email This Contact button. To do this, paste the following function directly below the OnContextChange event handler.

    function widgetEmailThisContact::OnClick()
    {
        // Use the nCurrentRow node (which is continually kept up-to-date
        // by the OnContextChange event handler) to get the e-mail
        // of the current contact.
        var nEmail = nCurrentRow.selectSingleNode("my:Email");   
        XDocument.UI.Alert( nEmail.text );
    }

    With another preview of the form you will notice that clicking the Email This Contact button in the widget menu now displays the e-mail address of the Contact on which the widget was accessed.

    Gotchas:

    One limitation of adding custom widget menu buttons is that they cannot be conditionally shown for only one repeating table or section in the view. If there are custom widget buttons they will be shown on every widget menu in the entire view. This is because we are calling custom code instead of using one of the xCollection or other operations. Please see the XSF Schema documentation for more detail.

Copyright © 2003-2019 Qdabra Software. All rights reserved.
View our Terms of Use.