Search

Binary Jam

Simon's blog, SharePoint, Arduino type things.

Category

Javascript

Using jQuery promises with SPServices

I had reason to pull in data from three separate lists in SharePoint recently. Data in list three was dependant on lists one and two.

So I created an admin app page to manage problems with list three.  Having to pull data from all three lists, left me with some options

  • load them synchronously
  • nest the calls in successive succeeded function
  • Use jQuery promises

Perhaps someone has done this and there is a good example out there, but I couldn’t find it so I figured this out for me and am posting it because, well you can’t have enough examples.

This code is just enough of the original to demonstrate promises, I tested the original but had to change some details here which of course I havent had time to check, so I hope this works (it should with the lists in place) and give you enough insight.

In this code look at the $.when statement, the way I’m using it means that it will execute each function in turn and only continue if all functions suceed, if one fails it will execute the loadfailure function instead.

EDIT:As Marc comments below, SPServices returns a promise now so no need to build your own, see Marcs link
for more details. This code is still handy for seeing how to use promises with an async call, but this is not how to do it any more. This is quite messy code too.  When you start to use more structured code, SPA frameworks, then this method doesn’t really fit and the returned promise fits better with service or provider patterns unlike this jumble pattern here ;-).

http://js/jquery-1.7.min.js
http://js/jquery.SPServices-0.7.1a.min.js
http://js/underscore.min.js
Initialising
</div> var binaryJamPromisesTest = function ($) { //Private Members var listOne, listTwo, listThree; function main() { $("#appStatus").text("Loading"); $.when(asyncGetListOne(), asyncGetListTwo()) .fail(function () { loadFailure(); }) .done(function () { dataReady(); }); } function loadFailure() { $("#appStatus").text("Failed to Load data"); } function dataReady() { $("#appStatus").text("Processing Data"); //processLists(); //Do the main thread work here ! } function asyncGetListOne() { var dfd = $.Deferred(); $().SPServices({ operation: "GetListItems", async: true, listName: "ListOne", completefunc: function (data, status) { if (status == "success") { _listOne = $(data.responseXML).SPFilterNode("z:row").map(function () { return { id: $(this).attr("ows_ID"), title: $(this).attr("ows_Title") }; }); dfd.resolve(""); } else { dfd.reject(); } } }); return dfd.promise(); } function asyncGetListTwo() { var dfd = $.Deferred(); $().SPServices({ operation: "GetListItems", async: true, listName: "ListTwo", completefunc: function (data, status) { if (status == "success") { _listTwo = $(data.responseXML).SPFilterNode("z:row").map(function () { return { id: $(this).attr("ows_ID"), title: $(this).attr("ows_Title") }; }); dfd.resolve(""); } else { dfd.reject(); } } }); return dfd.promise(); } //Public Members return { init: main } } (jQuery); jQuery(function () { binaryJamPromisesTest.init(); });
Advertisements

jQuery mobile – Multi Pages

 

We have been playing about with jQuery mobile at the office and its a great way to deliver specific mobile content and of course it works with PhoneGap for compiling those apps to (near native).

But we had a couple of teething issues due to the documentation being a little all over the place and the examples being a little too simple from the recommended approaches, and the voodoo it does.

First Glossary, in jQuery mobile each page is a screen displayed in the browser that is transistioned (sometimes in a fancy way) to or from.  These pages are essentially (ootb)

sections with an attribute of data-role=”page”.  Now in the demos and examples you will find in the docs and other sites these “Multi-Page” demos are seperate pages displayed on the phone, but in terms of files on the file system they are all in the same htm page.

See demo MultiPage-Template

Now this is great for a couple of pages all based on ajax filled content, but where there are many pages then thats the time to split those pages out onto the file system into seperate documents.

The documentation recommends this approach because as the new page is loaded the last page is removed from the DOM thus saving memory (there are techniques to force caching of pages).  This is where the some of the confusion can arise as there are so few examples explaining whats happening.

The default behavior for jQuery mobile when navigating about these separate htm files that are defined as pages of the app is that it uses ajax to load them. It can then take that content and inject it into the DOM and then transition between the two. 

The problem we encountered due to the lack of demos and not reading docs is that where did we put the scripts the css what happens on page load etc.  Well it’s actually been made really simple and the thing to remember is this –

Taken from the documentation

Scripting pages->Scripts and styles in the head

http://jquerymobile.com/demos/1.2.0/#/demos/1.2.0/docs/pages/page-scripting.html

When the user clicks a link in a jQuery Mobile-driven site, the default behavior of the navigation system is to use that link’s href to formulate an Ajax request (instead of allowing the browser’s default link behavior of requesting that href with full page load). When that Ajax request goes out, the framework will receive its entire text content, but it will only inject the contents of the response’s body element (or more specifically the data-role="page" element, if it’s provided), meaning nothing in the head of the page will be used (with the exception of the page title, which is fetched specifically). Please note that scripts loaded dynamically in this fashion do not guarantee a load order in the same way they would if the page was loaded via a normal http request.

This means that any scripts and styles referenced in the head of a page won’t have any effect when a page is loaded via Ajax, but they will execute if the page is requested normally via HTTP. When scripting jQuery Mobile sites, both scenarios need to be considered. The reason that the head of a page is ignored when requested via Ajax is that the potential of re-executing the same JavaScript is very high (it’s common to reference the same scripts in every page of a site). Due to the complexity of attempting to work around that issue, we leave the task of executing page-specific scripts to the developer, and assume head scripts are only expected to execute once per browsing session.

This is the key to how it all works under the hood.

So when coding a simple app in jQuery mobile in multiple pages then a simple layout might be this.  This is a simplification of the jquery mobile multi-page boiler template split across two files.

The second file does not need any of the jquery, css, or other js files.  As the navigation system looks for a div of data-role page and squirts it in.  NOTE multi-page/Multiple Page combos are not allowed it will likely fall on its face, so dont stick more than one date-role=”page” into these Multiple Page designed apps.

 

Main.html

Multi-page template
http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css&#8221; />
http://ahref=
http://ahref=

   $(‘#home’).on(‘pageinit’, function () { 
       console.log(‘home page-init’);
   });

 

function Yay() {
    console.log(‘Yay’);
}

   

   
       

One

       

I have an id of “home” on my page container. I’m first in the source order so I’m shown when the page loads.

   

       

Link to Other Page:

       

Show page “two”

    
   

</div>

</body>
</html>

Page2.html

<!DOCTYPE html>
<html>
<head>

<title>Page Two</title>
</head>

<body>

$(‘#two).on(‘pageinit’, function () {

    console.log(‘page two pageinit’);

    Yay();  //Call a function in the parent container, cos Im just injected

});

   

   
       

Two

       

I have an id of “two” on my page container. I’m the second page container in this multi-page template.

   
       

Notice that the theme is different for this page because we’ve added a few data-theme swatch assignments here to show off how flexible it is. You can add any content or widget to these pages, but we’re keeping these simple.

   
       

Back to page “one”

   
   

</div>

</body>
</html>

 

So that being the case where do I stick the code.  Well consider it like this if its a library code stick it in the home page as that outer page is always there and loaded, however when you need stuff to happen that script should be in the page <div> as it will be loaded and injected into the main page container and executed at that point.

There are lots of other things to learn about events and injections but if you can get this bit right then the rest should just follow.

I strongly urge you to read all of the docs on jquery mobile especially around pages as understanding this navigation and the weird vood0o it does with the navigation is key to writing your code in the right place.

CEWP – Making Use of Coin Slider II – SPServices Version

Part II of the blog posts now, adding a quick tweak to auto populate the images from an ImageLibrary.

In the last post we created all the elements needed for this next piece, if you have that working then great.

First a couple of things

Get the latest SPServices version be sure to match the versions correctly especially where jQuery 1.7 and SPServices versions are concerned, changes in jQuery caused some problems in peoples libraries.  Put that library in the place you like to store them (_layouts, portal root, site collection, doc lib which ever I stuck it in my SPFolder in the site collection)

Add a new field to your Image Library, a checkbox and call it active.

Paste this code (after you modify the include statements to point at the places you stored them).

 

I haven’t put any error trapping in this code or loading pictures or messages to say activate at least one image you idiot but you can and I would if this was going on a real site. You could extend this code to get descriptions from the image library and if there was one add it to the slider text.

 







<div id="gamesHolder" style="width:468px;height:280px;overflow-y:hidden;">
    <div id="games">
    </div>
</div>

jQuery(function($) {
 
    $().SPServices(
       {         
         operation: "GetListItems",         
         async: true,         
         listName: "ImageLibrary", 
         CAMLQuery : "1",        
         CAMLViewFields: "",         
         completefunc: function(data) 
           {
                var theMiddle="";
                $(data.responseXML).find("z\:row, row").each(function(){
                    var getimage= "/" + $(this).attr("ows_FileRef").substring( $(this).attr("ows_FileRef").indexOf("#") +1 );

                    theMiddle +='<a href="' + getimage + '" target="_blank"><img src="' + getimage + '" /></a>';

                });

                $(theMiddle).appendTo('#games');
                $('#games').coinslider({ hoverPause: false, height:246, width:618});

            }
       }
    ); 


});


CEWP – Making use of Coin Slider jQuery

This post is how to use a small jQuery library within a CEWP to provide sliders.

First some pre-reqs.

Download jQuery (latest) and Coin Slider jQuery plugin.

Place the jQuery library in a

Choose one.

  • SPFolder
  • _layouts
  • Document Library
  • Any old web you have access to

 

You need to choose a location, I prefer master pages and putting things in _Layout, but if you dont have access to the server then you could utilise SharePoint Designer to create a folder in a site collection, again here I prefer the top top top  level Site Collection so that anywhere I use this the same js files come from the same place and get cached.

Place the CoinSlider CSS and JS files either in the same location (not master page though) or perhaps in the local site collection you are about to create this content in.

In my Code example I have already a jQuery in my masterpage, so I dont load it again.  I put the other files in an SPFolder in the site collection call jQueryExtras, you can reference them  from where you put them.

 

Next you need an Image Library, just create one somewhere, ideally unique for the content you are to display, as later on I might get to publish the next article that loads the images using SPServices, but then I might not.

In this image library place the images you want to slide, these should ideally be “landscape” style better still CinemaScope style. Those long thin pictures just work better in sliders. All these images MUST be the same size.

I used images from another sliders content (the nivo slider which I struggled to get to work, it was just easier than trying to find content) you could use images from your own stock or the demo just remember to change the image sizes in the right places (css/js).

Now that you have your JS and CSS includes in your locations and your image library populated with images we can create a CEWP, so on the page you want this go create one and hit the EDIT Source Editor

 

Paste this lot in, it is important that you set the height and width in the javascript to match your images, if you don’t expect lots of formatting issues. I tried this on MOSS and in IE7+ it wornt work in IE6, which is a pain for me as I have to find another slider now.

 <link rel="stylesheet" href="/sites/SliderDemo/jQueryExtras/coin-slider-styles.css">
<script src="/sites/SliderDemo/jQueryExtras/coin-slider.min.js"></script>

<div id="gamesHolder">
    <div id="games">
       <a href="http://www.binaryjam.com/" target="_blank">
          <img alt="Wall-E" src="/sites/SliderDemo/SliderImages/walle.jpg"> 
          <span><b>Wall-E</b><br>A Film about a robot. </span>
       </a>
       <a href="http://www.binaryjam.com/" target="_blank">
          <img alt="Finding Nemo" src="/sites/SliderDemo/SliderImages/nemo.jpg"> 
       </a>
       <a href="http://www.binaryjam.com/" target="_blank">
           <img alt="Toy Story" src="/sites/SliderDemo/SliderImages/toystory.jpg"> </a>
       <a href="http://www.binaryjam.com/" target="_blank">
           <img alt="Up" src="/sites/SliderDemo/SliderImages/up.jpg"> </a>
    </div>
</div>
<script>jQuery(function($) {
	$('#games').coinslider({ hoverPause: false, height:246, width:618});
});
</script>

<!-- -->

<!- Force Stupid blog code window to be bigger -->

<!-- -->

Have fun

Embracing the dark side – Part 3, Image browser enhancement to a form

Continuing from the previous post, Customising a List form, we are now at the point when we can start to do something useful with these techniques as let’s face it adding hello world to a form doesn’t really add value.

So in this post I am going to add a customisation to make the input forms new or edit a little more useful and therefore encouraging user adoption.

Have you ever used the URL field ?  Perhaps formatted as a picture ? It looks like this on the form

Normal Picture Link

The absolute height of usability that one. Is it better in 2010, my other dev box is off at the minute. Thing is we can make this better.  In my scenario the user needs to select an image from an existing Image Library.

By providing the users with an extra “button” we can add some javascript to give them the ability to browse the image library right there in the add new item page (or edit) and select the image, no messing about cut and pasting urls, which for some users is just a little too much for them to deal with. Instead they See a picture like this to pick an image from

CropperCapture[10]

 

Below you can see the added hyperlink, the picture field populated and a preview image.

The more observant will notice this version picks thumbnails automatically.

CropperCapture[9]

The code to do this relies on jQuery being included in a master page, if you do not do this by default in your SharePoint implementation, then

  1. Consider doing so
  2. If not, you can always add a script tag referencing it in directly in the page

The example code below relies on you determining certain things and setting the code constants to the values you have determined, e.g. the Image List Name and Guid, the jQuery field selector for the picture block, this is something that can only be done by rendering the form and figuring out the ID of that first text box of the field.

In my example the jQuery selector is

 </p> <p>var pictureFormFieldSelector='input[id$="UrlFieldUrl"]';</p> <p>

Which locates an input box with the ID ending in “UrlFieldUrl”. The Real name, in my case, happens to be “ctl00$m$g_df4349ae_3a85_4882_93ef_c7c49eb75719$ctl00$ctl04$ctl07$ctl00$ctl00$ctl04$ctl00$ctl00$UrlFieldUrl”.

I use that tag to automatically add the HTML for the “Click Here” link and determine the layout of the page for adding the preview Image.

The code for the Dialog Picker is Standard SharePoint, the Asset Picker, and I took the idea from a blog post , in this chaps blog he is using it on a toolpart.

       http://fahadzia.com/blog/2009/11/using-sharepoint-image-picker-to-select-images/

 

So here is the code I use to implement this in a page.

 

//NoConflict is enabled in my environment
//Pass to documentLoad this function 
jQuery(function ($) {

    //Constants that refer to the Image List
    //an attempt to generalise this code, fingers crossed
    var baseUrl=L_Menu_BaseUrl;
    var imageListName=”MyImageList”;
    var imageListGuid=”{F406F2AA-5518-4E46-86F5-9CDDC5CF8F38}”;
    //This is the jQuery selector to identify the specific Picture Block we are to target
    var pictureFormFieldSelector=’input[id$=”UrlFieldUrl”]’;
    //Grab the Form Element Block,
    var $formBlock=$(‘#onetIDListForm’);
    if ($formBlock.length>0)
    {

        $(pictureFormFieldSelector).parent().prepend(‘Click here for advanced browse
‘);
        with(new AssetPickerConfig(‘myAssetPickerObj’))                                            
        {{                                                 
            DefaultAssetImageLocation=’~SiteCollection/’ + imageListName;                                                 
            CurrentWebBaseUrl=baseUrl;                                                 
            OverrideDialogFeatures=”;                                                 
            OverrideDialogTitle=”;                                                 
            OverrideDialogDesc=”;                                                 
            OverrideDialogImageUrl=”;                                                 
            AssetUrlClientID=’findThatTxt’;                                                 
            AssetTextClientID=”;                                                 
            UseImageAssetPicker=true;                                                 
            DefaultToLastUsedLocation=false;                                                 
            DisplayLookInSection=true;                                                 
            ReturnCallback = null;
        }}
        $(“#advancedBrowse”).click(function() {
            APD_LaunchAssetPickerUseConfigCurrentUrl(“myAssetPickerObj”);
            if ( $(‘#findThatTxt’).val()!=”” )
            {

       var imageLocation = $(‘#findThatTxt’).val();
       var urlStart = document.location.protocol + “//” + document.location.host;
       var finalImg = urlStart + imageLocation;
       var editPoint = imageLocation.lastIndexOf(“/”);
       var previewImg = urlStart + imageLocation.substring(0, editPoint) + “/_t/” + imageLocation.substring(editPoint + 1).replace(/./g, “_”) + “.jpg”;

                $(pictureFormFieldSelector).val(previewImg);
                if($(‘#previewImg’).length==0)
                {
                    $(pictureFormFieldSelector).parent().append(‘‘);                          
                }
                else
                {
                    $(‘#previewImg’).show();
                    $(‘#previewImg’).attr(“src”,  previewImg);
                }
            }
            else
            {
                $(pictureFormFieldSelector).val(“”);
                if($(‘#previewImg’).length>0)
                    $(‘#previewImg’).hide();
            }
            return false;
        });
    }
});

 

Multiple jQuery on a page

Technorati Tags: ,

I have been doing some messing about with jQuery in SharePoint and I want to understand what is going on when there are multiple declarations of different versions on a page.

The way it seems to work is last one referenced wins.  This is because the execution of the jQuery code sets window.jQuery = the current jQuery object.

I was wondering well what happens to the docReady function pointer stack, as that is surely contained within the version of jQuery that was executed.

Well truth is it’s complicated.  The code you see below will execute 161 and 144 code and the events will occur in each ones own code block (closures), but then the values you get out of jQuery are that of the last one executed despite it being a closure, because the clousre version of $ you call in your first doc ready returns the window.jQuery object,

not your closure so this code will always spit out 1.4.41.4.4 despite executing code

from both code blocks.

What does this mean, I haven’t got a clue, but I encourage you to debug this in firebug and see what code executes where, and if someone can explain to me why I see two function pointers in my 1.4.4 readyList code, that would be nice.

UPDATE:I’ve tried this recently and I dont know what crack I was smokin when I tried this, Im convinced I remember stepping thru two sets of jquery code, but then once inside the prior closure gets the new reference once inside, this is not the case when I just did it in VS2010.   What is still interesting is that any plugins loaded after the first jquery reference are nuked on load of the second jQuery ref.  HOWEVER the doc ready function pointer list is retained and both execute.   I still stand by the next statement.

 

In conclusion I suppose I would say one version of jQuery would be nice on a page, if MS could kindly put something into sharepoint to manage it so we are all doing the same thing I’d appreciate that, and if the jQuery team could “just finish already” 😉

http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.1.js<html>
<head>

http://ahref=

</head>
<body>

The Version is

$(function (){$(‘#dave’).append($().jquery)});

http://ahref=

$(function (){$(‘#dave’).append($().jquery)});

</body>
</html>

jQuery autocomplete for SharePoint Search Box II

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).

Continue reading “jQuery autocomplete for SharePoint Search Box II”

jQuery autocomplete for SharePoint Search Box

Whether or not SharePoint actually needs an autocomplete for it’s search box could be debated, and the manner in which I’m about to implement it, well that could be debated also. 

The point of this post was to use jQuery techniques to query a list via its web services and do something flash.  I’m doing it SharePoint 2007 as that is what I have handy and working. 

I will be upfront and honest right now, the code for this is a Mashup from two sources, Jan Tielens and the jQueryUI demo itself, both needed tweaking to come up with something new, but just so you know it’s not been rocket science, hard work was done for me, cheers Jan. 

Continue reading “jQuery autocomplete for SharePoint Search Box”

Yet another Ajax Sharepoint Part

Site Map  I got chance to knock up another part, sorry no source code this time, but you might like the idea.

Using the idea from Amazon, ebuyer and MS of the SiteMap at the top of the page I thought I could do the same with my DynamicPanel.  So I created a Webcontrol (not a webpart!) that Spat out a PopperLink (see Ajax and Sharepoint) using the CreateLink method that called yet another httpHandler.

The handler iterates thru the Areas (like this)

Guid homeGUID = AreaManager.GetSystemAreaGuid(PortalContext.Current, SystemArea.Home);

Area homeArea = AreaManager.GetArea(PortalContext.Current, homeGUID);

foreach(Area area in homeArea.Areas)
{
if(!area.System)
textWriter.WriteLine (“<TD valign=’top’><TABLE><TR><TD valign=’top’><b><A href='” + area.WebUrl +”‘>” + area.Title + “</a><b></TD></TR>” + RecurseArea(area) + “</TABLE></TD>”);
}

private string RecurseArea(Area area)
{
string s=””
foreach(Area areaChild in area.Areas)
{
if(!areaChild.System)
s+= (“<TR><TD valign=’top’><A href='” + areaChild.WebUrl +”‘>” + areaChild.Title + “</a></TD></TR>”);
}

return s;
}

Simple Stuff (obviously I have surrounding tables too).

This produces a clickable partial page of links.  The HttpHandler is called by the popper and on clicking the Site Map link (see later) it Ajax calls the handler and puts the resultant html in the popup window.

Then using the techniques here Applying a Custom Banner I placed the asp.net control on the page in the new custom banner.

Hey presto Fancy Ajax dynamically populated Sharepoint 2003 Site Map.

Technorati tags: , , , ,