Using SPServices with jQueryUI’s Autocomplete Function on InfoPath Forms in SharePoint

Yes, that title says using jQueryUI on InfoPath forms in SharePoint. InfoPath forms are fantastic, except when they just aren’t quite able to do what you want. While InfoPath can help you take your SharePoint list forms to a whole new level, there may be times when you want to add some behavior to those forms which InfoPath simply doesn’t offer.

Guess what? jQuery and jQueryUI can come to the rescue in some of those cases, just as it can with the standard list forms.

I recently worked with a client to do a relatively simple thing, but it was a huge hit. They had a SharePoint list had a Single line of text column, to which the user could add whatever they wanted. However, there was a desire to make suggestions as the user typed, based on the contents of a different list, which had thousands of items.

A dropdown doesn’t make sense in that situation, because there are simply too many items. They also wanted to show matches to what the user had typed, regardless where those characters occurred in the list item.

This is a perfect situation in which to use the idea of autocomplete. We all are familiar with this idea, if not the actual term. You probably see it in action every single day as you use a search engine. As you type your search term(s), the search engine shows suggestions, probably based on some fairly sophisticated algorithms.

Here’s an example from Bing:

image

and from Google:

image

(I can’t help but point out that Google was more on the mark in guessing that I was searching for SPServices, but hey, who’s counting?)

When InfoPath forms are rendered in the browser, they are built of ordinary markup just like any other page, albeit fairly complicated markup, driven by a lot of script.  That doesn’t mean that you can’t add some script of your own as well to add additional capabilities. There are a few peculiarities to this situation, though, which you need to handle.

Here’s a slightly dumbed down version of the script we ended up with.

window.onload = function() {
  window.setTimeout(readyCall, 1000);
}

function readyCall(){

  var externalParties = [];

  $().SPServices({
    operation: "GetListItems",
    listName: "External Parties",
    CAMLViewFields: "",
    async: false,
    completefunc: function (xData, Status) {
      $(xData.responseXML).SPFilterNode("z:row").each(function() {
        externalParties.push($(this).attr("ows_Title"));
      });
    }
  });

  //<input tabIndex="0" title="" class="q_zwfUqJo2fRthHnM4_0 as_zwfUqJo2fRthHnM4_0 b9_zwfUqJo2fRthHnM4_0" id="ctl00_m_g_a226da68_1383_40e3_8410_1ada27d49dcf_FormControl0_V1_I1_T2" aria-invalid="true" style="position: relative;" onfocus="return (TextBox.OnFocus(this, event));" onblur="return (TextBox.OnBlur(this, event));" onpropertychange="return (TextBox.OnPropertyChange(this, event));" type="text" OriginalId="V1_I1_T2" FormId="ctl00_m_g_a226da68_1383_40e3_8410_1ada27d49dcf_FormControl0" ViewDataNode="3" direction="ltr" wrapped="true" ScriptClass="TextBox" VCARD_NAME="91161f891e59461042587839b2504693728ce05a" ?=""/>
  $("input[id$='FormControl0_V1_I1_T2'], input[id$='FormControl0_V1_I1_T3']").autocomplete({
    source: externalParties,
    minLength: 3
  });
}

When InfoPath forms load in the browser, they don’t load with the rest of the page, but instead they are loaded slightly afterward in what amounts to an asynchronous load. Because of that, using $(document).ready(), our trusted jQuery friend, doesn’t work. Instead, as you can see in lines 1-3, we simply wait for 1000 milliseconds (1 second) before we run our script. We found that this was an adequate amount of wait time for our particular form; you might need to adjust this.

In lines 9-19, we use my SPServices library to call the Lists Web Service, using the GetListItems operation. This operation simply reads items from the list based upon the criteria you specify. Once we have the data, we push each of the Title column values into an array called externalParties.

Finally, we call the jQueryUI function autocomplete, using two selectors. In line 21 above, which is commented out, you can see an example of the markup for one of the input elements rendered in the InfoPath form. One of the hardest parts of all of this was to figure out what selector to use. We settled on looking for an input element where the id contained ‘FormControl0_V1_I1_T2’.  (We actually added the autocomplete behavior to two columns in the form, thus the second selector for ‘FormControl0_V1_I1_T3’.)

We added this script into the newifs.aspx and editifs.aspx pages using a trusty Content Editor Web Part (CEWP). Since this was SharePoint 2010, and because it makes for far better code management, we stored the script in a separate file and referenced it using the Content Link.

Bingo-bango, we had a nice, little additional piece of functionality which made the users very happy. This is an example where thinking about all of the tools at your disposal and how you might glue them together into the right solution to get the job done can be the right approach rather than a lot of custom coding.

<UPDATE dateTime=”2011-08-25T23:51″>

My partner in crime for this exercise was Marcel Meth (@marcelmeth), and he’s done a post on it, too, which you can read here. I was able to steal his image of the results, which I’ve added above. Note that the image is not showing the real data but our test data, which was simply a list of the 3000 or so major cities and towns in the US.

</UPDATE>

<UPDATE dateTime=”2011-08-26T09:25″>

I got a question in the comments below about how we added the script to the InfoPath page, and I wanted to add those details here.

  • First, we opened each form in the browser, which launched it in a dialog box.
  • We got the actual URL of the page in the dialog by right-clicking and looking at its properties. The NewForm was newifs.aspx and the EditForm was editifs.aspx (as I mention above).
  • We opened the form page directly in a new browser window and used the toolpaneview=2 Query String parameter trick to put the page into edit mode. This allows you to edit a list form page and add Web Parts to it.
  • We added the CEWP, and put the reference to our script file in the Content Link.
  • Apply and done.

</UPDATE>

119 Comments

  1. Interesting stuff, Marc. The question is, while Google may have been more accurate, were you logged in with your Google account at the time? I’ve noticed that Google is surprisingly accurate when I’m logged in, must be all that data-mining of our history.

    Reply
    • Mike:

      Fair question. It looks like I was logged in, but I just logged out and got the same results. (It was just an aside. I love seeing my own stuff show up in search result.s ;+) )

      M.

      Reply
  2. Great post, very useful for something I am working on.

    How do add the jquery to the infopath form? Do you write the script in a separate file and then call it in somehow? If so, what are the details?

    Reply
  3. Hi,

    I think I setup everything properly but I get the following error in IE:
    Webpage error details

    User Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; InfoPath.3; .NET4.0C; .NET4.0E)
    Timestamp: Wed, 7 Sep 2011 09:28:22 UTC

    Message: Object doesn’t support this property or method
    Line: 787
    Char: 3
    Code: 0
    URI: http://sherepointpageurl

    This is line 787:
    $(“input[id$=’FormControl0_V1_I1_S1_I1_T1′]”).autocomplete({

    Any help would be appreciated.

    Thanks.
    Goran

    Reply
      • Hi Marc,

        Thanks for reply. I don’t have error any more but I’m still not getting list when typing. I’ll continue testing until I get it work.

        Goran

        Reply
        • Hi Marc,

          It’s me again. I’ve done some testing, and I think my problem is in passing query results to input field.

          For testing, I’m using input with id=”test”

          With this script I get ul list with SP list column values:

          $(document).ready(function() {
          $().SPServices({
          operation: “GetListItems”,
          async: false,
          listName: “{274470a0-492b-4ec8-b90b-0752ff772368}”,
          CAMLViewFields: “”,
          completefunc: function (xData, Status) {
          $(xData.responseXML).find(“[nodeName=’z:row’]”).each(function() {
          var liHtml = “” + $(this).attr(“ows_Department”) + “”;
          $(“#tasksUL”).append(liHtml);
          });
          }
          });
          });

          With this script I get autocomplete to work from manual list in the code:

          window.onload = (function(){
          try{
          $(document).ready(function(){
          var data = “Core Selectors Attributes Traversing Manipulation CSS Events Effects Ajax Utilities”.split(” “);
          $(“input[id$=’test’]”).autocomplete(data);
          });
          }catch(e){}});

          But when I try your code with correct references to list ID, column name and input ID, I don’t get anything…

          Any idea?

          Thanks.
          Goran

          Reply
  4. Hi Marc,

    Thank you very much for your time and answers. I tried a lot of changes and tests without success. Last two questions before I give up;

    1. Is there a way to debug this script?

    2. I’m able to use SPAutocomplete to pull data from the same list, and I can use it on my test input field, because I can assign title tag to it.
    But, I can’t use it on infopath form, because title tag is empty. Is there a way to assign title tag to infopath input field?

    Thanks a lot.

    Goran

    Reply
    • Goran:

      Yes, you can debug with the Developer Tools in IE or Firebug in FF. (The other browsers have similar tools, but I don’t use them.) You will need to get comfortable with these tools to be productive. They also let you dig into the DOM to identify things like the markup structures, element ids, etc.

      M.

      Reply
    • razieh:

      If I remember correctly, we added a CEWP to the page and referenced a separate .js file. This makes it a bit easier to maintain, though adding your script in the page works fine, too.

      M.

      Reply
  5. I’m still confused on how to get custom javascript in the infopath form. I don’t want to place it in the masterpage since I only want the js to load for the specific infopath form. Any help is appreciated

    Reply
    • James:

      In this case, we exposed the Infopath form in a Web Part Page so we could reference the script file in a Content Editor Web Part’s Content Link.

      M.

      Reply
  6. Hi Marc,
    Thank you for this post. However I have some questions:

    Could you please explain further the part in line 21? I didn’t understand why is it commented. Also, what are selectors? How can find the id of a field that I have in my form?

    Thanks

    Reply
    • Anas:

      Line 21 is the markup we copied out of the Infopath form, just for reference with our selectors. Selectors are a key concept if you are using jQuery. You should go to the jQuery site to read about how they work.

      M.

      Reply
  7. HI

    I am pretty new to javascript and jquery.

    I have added the content editor to the “New Item” form of my list, added the code – see below, but not getting results. can you please assist.

    window.onload = function() {
    window.setTimeout(readyCall, 1000);
    }

    function readyCall(){

    var Projects= [];

    $().SPServices({
    operation: “GetListItems”,
    listName: “test”,
    CAMLViewFields: “”,
    async: false,
    completefunc: function (xData, Status) {
    $(xData.responseXML).find(“[nodeName=’z:row’]”).each(function() {
    Projects.push($(this).attr(“ows_Title”));
    });
    }
    });

    $(“input[id$=’FormControl0_V1_I1_T9′]”).autocomplete({
    source: Projects,
    minLength: 3
    });
    }

    Reply
    • Hein:

      It’s hard for me to know what’s going wrong from this end. Have you added references to all of the appropriate CSS and JS files into your page or master page? Are you getting a script error?

      M.

      Reply
      • Not getting any error.

        I suspect that the issue is somewhere with the function readyCall. I followed your blog on the first step when adding a jquery library and the alert works fine. Should I have added any specific CSS to get the autocomplete to work? I haven’t added any CSS

        Reply
  8. After further troubleshooting, I realized that the problem is with

    $(“input[id$=’FormControl0_V1_I1_T9′]”).autocomplete({
    source: projects,
    minLength: 3
    });

    I added an alert at the bottom of the script and removed the entitis (Onload, readycall and input) one by one.

    When including the input section in the script, the alert does not pop up.

    Reply
  9. So my alert is showing now – i did not add the jqueryui.js. I now have the same problem as Goran. my values aren’t pulling through. is there anythin i should know / add regarding the jquearycss?

    Reply
    • Hein:

      I think you’ll just have to keep debugging. It’s possible your selector isn’t right or something. If you check the docs for autocomplete, you’ll see that you can bind to various events. Try some alerts there to see if autocomplete is even firing.

      M.

      Reply

Have a thought or opinion?