Marc Anderson was good enough to comment on my last post, a demo of creating a jQuery extension to the SharePoint search box to suggest Common Terms.
Marc’s comment was related to a compatability problem with safari and chrome when using the “z\:row” syntax as a selector, also to remind me of the SPServices library which makes calling sharepoints web services a little easier.
So just for him (well everyone really) here is the same example re-worked to use the SPServices library (stored locally in a Doc Library for this code).
Note again I have stripped the code out, unchained the jQuery and commented what the lines are doing as not everyone knows the extent of jQuery (myself included).
To use this code
1. Create a Site Collection
2. Create a List called CommonTerms in the rootweb
3. Add the SPServices library to a doc library
4. Add a CEWP to the page and edit it in Source Mode
5. Paste the Code (properly formatted, cut and paste from here can cause problems)
6. Edit the SPServices library script path to point at your Site Collection.
So here you go
<!-- How you store the libraries is up to you but for the purpose of this demo I just links straight to google CDN --> <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" rel="stylesheet" type="text/css"/> http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js /sites/20100928-04/docs/jquery.SPServices-0.5.8.min.js $(document).ready(function() { $().SPServices({ operation: "GetListItems", async: true, listName: "CommonTerms", CAMLViewFields: "", completefunc: AttachAutoComplete }); });//docReady function AttachAutoComplete(xmlResponse) { //xmlResponse contains an Object that contains an IXMLDOMDocument2, // you can see the raw xml soap response, if you query xmlResponse.responseXML. // As this is a list and we want its entries we use jQuery selector on it // $( "[nodeName=z:row]", xmlResponse.responseXML ) will return a jQuery // array of IXMLDOMElements matching "z:row" tags // var domElementArray=$( "[nodeName=z:row]", xmlResponse.responseXML ); //The map function is a technique for processing one array and returning another //jQuery array, in this case we are returning an array of jscript objects that map to attributes //of the XML entries. //see http://api.jquery.com/jQuery.map/ var dataMap = domElementArray.map(function() { return { value: $(this).attr('ows_Title') , id: $(this).attr('ows_Title') }; }); //In this case the autocomplete function cannot handle jQuery arrays it want POJ arrays in a specific format. //By using the get() function we return the internals of the jQuery array the core objects //see http://api.jquery.com/get/ var data = dataMap.get(); //Find the Sharepoint Portal Search Box (this is a poor selector, but it is not properly named by sharepoint, well it is but INamingContainer getrs in the way) $("input.ms-sbplain").autocomplete( { source: data });//autocomplete }
Should your completefunc call the AttachAutoComplete with parameters? Similar to:
completefunc: AttachAutoComplete(xmlResponse);
I didn’t know you could make a call without supplying the parameters to the function.
The completefunc calls whatever function reference it has whether a “real” function or a delegate with a parameter.
take the alternative
completefunc: function(xmlResponse) { … }
this is defining the function “pointer” and is the function signature at the same time.
So it’s right.
If you did do this
completefunc: AttachAutoComplete(xmlResponse);
You get xmlResponse is undefined as you are calling directly the function with xmlResponse which does not exist, so you have to pass the “function pointer”.
I think I’m confused with your call to this function:
function AttachAutoComplete(xmlResponse)
It’s called from the completefunc as:
completefunc: AttachAutoComplete
I don’t know where xmlResponse is being defined within the code. Is it one of those fancy javascript tricks? I’m finding that javascript is riddled with these, so I’d really appreciate it if you broke it down to me.
Its a fancy javascript trick.
OK thats a cop out,
We are getting deep into javascript here and I would recommend gettnig a book on Object Oriented Javascript (a quick google even points at stuff that might help explain exactly whats going on http://www.javascriptkit.com/javatutors/oopjs.shtml).
But to talk about the code here specifically, you need to understand whats going on in the SPServices library and the underlying jQuery Library. We can in some respects ignore the SPServices library here for a minute, all this is doing is abstracting the jQuery library call to $.ajax.
So look at this call to ajax
$.ajax({
url: “_vti_bin/lists.asmx”,
type: “POST”,
dataType: “xml”,
data: soapEnv,
complete: processResult,
contentType: “text/xml; charset=”utf-8″”
});
function processResult(xData, status) {….}
Again this is the same deal, but with the additional parameter of status (which I ignored, you can do that in JS).
When you make the ajax() call, you are passing a json block your own javascript object. You have defined a variable called complete (in this case) which will be called by the jQuery library. How we define what our function looks like is defined by the jQuery library.
If we look at the jQuery docs for ajax it shows you all the parameters that can be passed and what they have to look like.
In this case complete (in the SPService example completefunc is just another function defined in that library that is called by the ajax complete function) the definition in that doc looks like this
So When you create a function in your code called processResult(xmlRequest, status) your method signature has to match that as defined by the jQuery method call.
In the jQuery library when it gets that data it will execute the command
optionsPassedin.Complete(xmlHttpRequest, status)
Then your just back to the difference between an anonymous function (delegate) or a function pointer.
Hope that’s clearer.
http://www.siteexperts.com/tips/functions/ts18/page2.asp
We are getting deep into the internals of js eh? Thanks for the very thorough answer. It clears up some of the questions I have. I’ve only been writing js for 3 mos., so I have a lot of questions.
Thanks again for the excellent answer.
Matt
Hmm, contrary to your first example this one only seems to work if th SPServices js file is placed in the same site as the CEWP with the script.
After a bit of Googling around I found the “webUrl” parameter. Passing that with the path for the site where the SPServices js file resides makes the script work on a given subsite.
It looks like this:
$().SPServices({
operation: “GetListItems”,
webUrl: “/”,
async: true,
listName: “CommonTerms”,
CAMLViewFields: “”,
completefunc: AttachAutoComplete
});
/Thomas
i m not able to get it working..
how can i achieve it for another Custom Search box…
Thanks for this post.
Is it possible to get sources from 2 SharePoint lists instead of 1?