Tag Archives: JavaScript

SPRESTSearchParser

As part of my Pluralsight course on programming SharePoint 2013 with JavaScript, I tossed together a quick little utility to make search programming a little easier.  It’s all detailed in the course, but the source code is available on GitHub: https://github.com/Sector43/SPRestSearchParser

Basically, it works like this:

  1. Make your REST call to get search results from SharePoint
  2. Create an instance of the S43.SearchResultParser object:
    SNAGHTML19611eb
  3. Take the parameter returned from SharePoint (In the image its oneSample ) and pass it to the parseResults method in the SPRESTSearchParser object, as shown in the second line in the above image 
  4. The return value from that method call is a JSON object which contains an array of SearchResult objects.  Each SearchResult object is simply a representation of a single result from SharePoint that is easier to work with than the raw results.  It looks like this in the Chrome dev tools:
    image
    Each property from the result set is available directly on the SearchResult object within the array by name – much easier than remembering the position of each property in the result set.
  5. Right now the following properties are available from the PrimaryQueryResult.RelevantResults collection:
  • rank
  • docId
  • title
  • author
  • size
  • url
  • description
  • created
  • collapsingStatus
  • hitHighlightedSummary
  • contentclass
  • fileExtension
  • contentTypeId
  • parentLink
  • isDocument
  • lastModified
  • fileType
  • isContainer

Adding new properties is simply as easy as adding them as new properties to the SearchResult object definition in SearchResult.ts (yes, this is written in TypeScript).  One important thing to realize is that the property names on the SearchResult object must follow the typical JavaScript coding convention and start with a lowercase letter.

 

Accessing the results now looks like this:

SNAGHTML19c8b44

In the future, I’d like to clean this up and expand it to make use of additional result sets and other search capabilities.  Feel free to fork the code and adapt to meet your needs.  If you do something interesting, please submit a pull request to allow others to take advantage of it as well.

All Developers Can Be SharePoint Developers

That’s the title for a full-day session I’m doing at the upcoming Philly Code Camp (October 10, 2015, Philly MTC in Malvern – more information).  Registration is only $76 and includes breakfast and lunch, raffles, guaranteed admission to the Saturday regular Code Camp (which will sell out), and more.  Register here.

Here’s the synopsis for the day:

Until recently, SharePoint was the red-headed stepchild of the Microsoft web development world, requiring intimate knowledge of SharePoint and it’s gargantuan object model. This made SharePoint a very specialized skill-set that stood off to the side on its own. It’s lack of support for standard web-development practices made it difficult for new developers to learn – or to even want to learn.

Fortunately, this has changed.

SharePoint 2013 has joined the rest of the web-development world – supporting standard technologies such as REST, and languages ranging from .NET to Perl, PHP, Ruby, etc. JavaScript is now a first-class citizen. Gone are the days when “doing SharePoint” required extensive, arcane knowledge. For developers, SharePoint is now just another data store accessible via a robust, REST-based API.

In this full-day session, SharePoint MVP David Mann will introduce the SharePoint REST API and show how it can be used to build client-side applications using JavaScript, utilizing popular frameworks such as Angular and libraries such as JQuery, common tools like Node, Bower, Gulp and Yeoman, as well as rich-client applications using C#. This includes both on-premises installations of SharePoint as well as cloud-based environments such as Office 365.

Bring your laptops as this is a hands-on session. No SharePoint experience is necessary, but basic programming skills would be a big help. This is a great opportunity to add SharePoint to your toolkit, or to take your SharePoint skills to the next level. Individuals and teams are welcome.


I’m still tweaking the material, but here is the current agenda:

  1. Introduction & Getting Started (including why SharePoint? )
  2. Setting up the Environment
  3. Setting up the Environment (Lab)
  4. Tools & Frameworks
  5. Tools & Frameworks (Lab)
  6. The SharePoint REST API
  7. Hello (SharePoint REST) World (Lab)
  8. CRUD Operations
  9. CRUD Operations (Lab)
  10. Provisioning
  11. Provisioning (Lab)
  12. Language Agnostic – C#, Ruby, [Insert favorite language here]
  13. Language Agnostic (Lab)
  14. Wrap Up and Next Steps

I’ll post more details as we get closer.

To follow along with the labs, you’ll need:

  • a laptop with Visual Studio (2013 or 2015)  installed

That’s it.  You will not need SharePoint installed

Speaking at SPC14

I’m happy to announce that I’ll be speaking at the SharePoint Conference in March. My session is Deep Dive: REST and CSOM Comparison, which fits in nicely with the Pluralsight course I made that just went live (and it’s successive parts coming in Q1).

Here’s the synopsis for my session: SharePoint 2013 is fully embracing the world of client-side technologies, both on-premises and in the cloud. This means JavaScript; but which API should you use – REST or CSOM? This session will briefly introduce each, and then quickly move into a demo-heavy comparison of both approaches, citing the pros and cons of each API. By the end of the session, you’ll have a solid understanding of when and why you would use one over the other (and some situations where you combine them into a hybrid approach) as well as plenty of examples of each in action.

 

Details available here: http://www.sharepointconference.com/content/sessions/SPC423

 

I’ll post more information here as the conference gets closer.  See you in Vegas!

“this” and Function.createDelegate in JSOM

There are two prevailing methods of registering a callback for the executeQueryAsync function:

context.executeQueryAsync(

    Function.createDelegate(this, _onSucceed), 

    Function.createDelegate(this, _onFail)

);

and:

context.executeQueryAsync(_onSucceed, _onFail);

As you can see, the difference is simply the inclusion or exclusion of the Function.createDelegate call.  If you’ve always wondered what the difference between the two was, as I have, the answer is pretty simple: the former allows you to override what the value of the this variable will be inside the function.

In the latter case, not using Function.createDelegate, when you are inside either the _onSucceed or _onFail  callbacks, this will reference the callback function itself – onSucceed or onFail  respectively.

In the former case, using Function.createDelegate, when you are inside either the _onSucceed or _onFail callbacks, this will reference whatever you pass in as the first parameter to the createDelegate function.  In this example, we’re passing in the current value of this, so inside the callback, this will be the same as in the function that made the call to createDelegate.  It’s important to note that you can pass any object in as that first parameter:

Function.createDelegate(window, _onSucceed) 

Function.createDelegate(new myWidget(), _onSucceed)

Function.createDelegate({}, _onSucceed)

Function.createDelegate(someOtherObject, _onSucceed)

 

will all work fine, making this equal to window, a new instance of myWidget, an empty object, and whatever object is represented by someOtherObject, respectively.

Custom Field Types in SharePoint 2013 Apps

Synopsis and Key Take-Aways

Custom field types in SharePoint provide the ability to customize all aspects of SharePoint form fields– from how they are displayed, to how values are validated to how values are stored within SharePoint and a couple of other things along the way. They provide significant capability for enforcing business rules and providing a much more user friendly experience than what is available via the out-of-the-box field types.  Unfortunately, this power has never been available in a cloud-hosting scenario such as Office 365.  Things are changing for the better, however, with new capabilities available in SharePoint 2013 Preview.  We now have the ability to provide the same functionality to our end users without running custom code on the server.  With SharePoint 2013 Preview, we can modify the presentation and validation of a custom field (or technically any field) on any form in SharePoint as well as in Views simply via JavaScript.  This is an incredibly powerful capability.  It provides a nice, easy, standard (and supported) way of customizing the end user experience to be more efficient and friendly.

This article introduces the scenario, walks through the end user experience using a sample custom field and then dives into a code-level review of how to implement this new functionality.  The commented source code listing for the required JavaScript is available for download.

Note that as of the initial publication of this article (October 2012), this is based on the SharePoint 2013 Public Preview.  Once I can download RTM I’ll look to revisit this and update the article as necessary.

Introduction

Custom field types in SharePoint provide the ability to customize all aspects of SharePoint form fields– from how they are displayed, to how values are validated to how values are stored within SharePoint and a couple of other things along the way.  They provide significant capability for enforcing business rules and providing a much more user friendly experience than what is available via the out-of-the-box field types (single line of text, yes/no, date/time, user, url, etc.)

Unfortunately, this power and flexibility is simply not available in a cloud scenario such as Office 365 because they require that files be deployed to the server file system which you can’t do in a cloud solution.  For the 2010 release of SharePoint, there have been various attempts at simulating custom field types in a cloud scenario, but all have suffered from varying degrees of fragility or other problems.

Fast-forward to SharePoint 2013 and Microsoft has made things much easier for developers and much less fragile all around with regard to custom field types.  For the first time, it is possible to truly get most of the value of custom field types in a cloud scenario such as Office 365 or an on-premises scenario (without all of the work of doing it the old way).  Notice that I said most of the value.  There are some things that are still not possible and two major caveats of which you must be aware.  First the caveats:

  1. Even though we are building things which look and act like custom field types, we are not technically building custom field types.  We are technically just customizing the rendering and validation of the out of the box field types.  More on this later; just remember it for now
  2. All of our customizations are happening on the client side via JavaScript.  There are implications to this for your data and business rules.  What happens if a user has JavaScript turned off and therefore your customizations do not run?  What are the implications to the security and validity of your data?  We will touch briefly on custom validation later, but just keep it in mind – it’s not guaranteed to run)

Acknowledgements

Before going any further, I need to give credit where credit is due.  Andrew Connell and I hacked up the first portion of this together.  I took the rough POC AC and I had pulled together that almost did everything we wanted, finished it off and cleaned it up to produce the samples in this article.  Keep an eye on AC’s blog as he’ll be posting a follow-up article taking some of this in new directions.

Overview of the Solution

With all of that said, let’s see what it is that we’re going to get at the end of this.  Here are some screenshots and descriptions of what we’re going to build out in the rest of this article:

The New Item Form

In this example, we’ve customized the rendering of our custom field:

image_thumb40


Site Column 1 is our custom field.  Technically, it is just a simple text field.  Without our customizations, it would render as a textbox.  Our customizations change it’s rendering to a dropdown list.

The choices available in the dropdown (One through Five) are added dynamically.  In a real world scenario, these could come from a web service call.  To keep things simple and focused here, I’m simply hardcoding an array.  You’ll see when we get to the code how simple it would be to make this truly dynamic.

We’ve also added some rudimentary validation.  For the sake of this demo, FOUR is not a valid choice:

image_thumb20


(Michael Palin would be so proud)

Notice, too, that our field is marked as required in SharePoint and regular field validation continues to function:

image_thumb38


One of the things I’d like to play with in a later version of this is the possibilities for additional validation via CSOM and perhaps even some event receiver work to provide additional server-side validation.

Display in Views

Once we’ve entered a legal value, our item is shown in a SharePoint View.  We also have the opportunity to customize the rendering here as well:

image_thumb36


For the sake of this demo, I’m not actually showing the field value in the View. Instead, I show a JavaScript link that pops up a simple alert when clicked to show the field value:

image_thumb28

The Display Form

Again, for the sake of this demo, I’m customizing the presentation of our field on the Display form as well.  Instead of showing the actual value, I show it’s numeric equivalent:

image_thumb32

The Edit Form

The Edit form looks largely identical to the New form (internally, it’s actually rendered via the same code).  The only difference is that we have to make sure that the current value of the field shows as selected in the dropdown:

image_thumb34

Technical Walkthrough

Now that we’ve seen what we’re building, let’s dive into how to make it all work.  Once you’ve figured it all out, it’s actually pretty easy.  (Figuring it all out, though, that was a royal PITA, especially during a beta cycle).

The heart of everything we’re doing here is a new property on the out-of-the-box  SPField class (and all of it’s children) within the SharePoint server object model: JSLink (don’t  bother clicking on the link – there is NO documentation worth anything there right now – just a placeholder).  Similar to the JSLink property on SPView, SPField.JSLink gives us the opportunity to specify a custom JavaScript file that will be used to render our field.  Cool.

From our SharePoint 2013 App (or, really, any SharePoint 2013 solution), we add an attribute to the Elements file that defines our custom Field to specify the JSLink value:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

  <Field

       ID="{23d7e8ae-29c3-4f05-ac4a-08bbf2bc2b1d}"

       Name="SiteColumn1"

       DisplayName="Site Column 1"

       Type="Text"

       Required="TRUE"

       JSLink="~site/Scripts/SampleJSField.js"

       Group="Custom Site Columns">

  </Field>

</Elements>

 

The SampleJSField.js file will now be used to render our field wherever it is used.  The full SampleField.js file is available at the end of this article for your reading pleasure..I’ve added some comments to explain what is going on, but the following sections spell out the highlights

IIFE

Because we are only specifying a JavaScript filename in our JSLink attribute, and not a particular method to be called, we need some way to actually execute our code.  We do this via an IIFE (Immediately Invoked Function Expression) declared right at the top of the file:

(function () {

    initFieldTypes();

    var r = new JSFieldText("SiteColumn1", viewFunc, editFunc, editFunc, displayFunc);

    r.initField()

})();

 

You could do this different ways, but this is the most concise and easiest.  Basically, in one shot, I’m declaring an anonymous JavaScript function and invoking it.  No magic inside the IIFE itself, it simply calls a function to set up our custom field objects (initFieldTypes), creates an instance of my custom JSFieldText object (passing in the field name and a couple of function objects – more on these later) and then initializes the field.

I’m not going to go into details on the whole initFieldTypes function here.  It’s in the full source listing and it’s a bunch of pretty funky JavaScript at this point.  I plan on cleaning this all up but there’s no sense in doing that until I’m working with RTM bits.  Eventually, I’d like to centralize all of this in a common JavaScript library that can be used by multiple fields, but that will come later.  For now, it was enough just to build out a POC to show that this all works.  A good chunk of the  code in the “Global Code” section of the full source listing is based on some code from http://www.ruzee.com/blog/2008/12/javascript-inheritance-via-prototypes-and-closures but I’m not sure whether I’ll stick with that.  It introduces some complexity and I’m not sure it gets me a lot.  In the short term, however, it filled a void and let me focus on more pressing things.

Registering Our Custom Rendering

I will, however, focus on a few key areas within the initFieldTypes function.  The first is where we actually override the default rendering and tell SharePoint to use our custom rendering.  This is done via the initField function on the JSFieldText object:

if (hasValue(this.get_fieldName())) {

      var newCtx = {};

 

      newCtx["Templates"] = {};

      newCtx.Templates["Fields"] = {};

      newCtx.Templates.Fields[this.get_fieldName()] = {};

      //Views are handled slightly differently because of the way they are called by SP

      newCtx.Templates.Fields[this.get_fieldName()]["View"] = hasValue(this.viewCallback) ? this.viewCallback : null;

      newCtx.Templates.Fields[this.get_fieldName()]["NewForm"] = this.renderForNew;

      newCtx.Templates.Fields[this.get_fieldName()]["EditForm"] = this.renderForEdit;

      newCtx.Templates.Fields[this.get_fieldName()]["DisplayForm"] = this.renderForDisplay;

 

      SPClientTemplates.TemplateManager.RegisterTemplateOverrides(newCtx);

}

 

This code sets up an object hierarchy in a manner prescribed by SharePoint 2013 and registers the new functions to render each of our possible views of this field:

  • Views
  • Display Form
  • Edit Form
  • New Form

The last line of the snippet is what actually registers our custom handlers with  SharePoint.

Views are handled slightly differently because of how they are called internally by SharePoint.  For Views, we simply pass the callback that was supplied in the constructor of our field. Note that we do check for null and undefined via some helper functions.  If we set the View or any of the Forms to a null or undefined value, SharePoint will use it’s default rendering.

The Forms all use a function on our JSFieldText object because we need to do a little processing before invoking the callback.

Once the callbacks are registered, they’ll be called by SharePoint instead of the default rendering mechanisms.

One of the things that you’ll notice about all of these callbacks is that we’re not dealing with HTML objects.  In each case, we need to return the actual HTML text to render our desired UI, so we’re doing a lot of string manipulation.  That’s just the way SharePoint expects things to be, so we just run with it.

Technical Details: Views

The View callback is a simple method that modifies the value written into the standard SharePoint View as we saw in the screenshots above.  Here’s the code for that:

/// Function called to render the field in a View

function viewFunc(renderCtx, field, listItem, listSchema) {

    var currentVal = '(null)';

    if (renderCtx != null && renderCtx.CurrentItem != null)

        currentVal = eval('renderCtx.CurrentItem.' + field.Name);

    return "<a href="javascript:alert('This field has a value of: " + currentVal + "')">Show Field Value</a>";

}

 

Notice that the name of our function (viewFunc in this case) was the value passed into our JSFieldText constructor earlier.  The other callbacks operate the same way.  Note also the use of the eval statement in there.  I’m not thrilled with that and would like to find a way around it but haven’t come up with anything yet.

Technical Details: Edit Form

The Edit Form callback is used to render the field on an Edit Form.  Here’s the code for the sample I built:

/// Function called to render the NewForm & EditForm view of the field

function editFunc(renderCtx) {

    var fieldHtml = '<select ';

    fieldHtml += 'id="myNiftySelect" onchange="moveValue('' + this.get_fieldId() + '')">';

    fieldHtml += getSelectOptions(this.get_fieldValue());

    fieldHtml += '"</select>';

    fieldHtml += getStandardInputHtml(this, "hidden");

    return fieldHtml;

}

 

This one is a little more complex than the View, but it is still just building up an HTML string to be returned to SharePoint and ultimately stuffed down the pipe to the client’s browser.  There are a couple of helper functions that you can review in the full source code listing.  In the listing above, all I’m rendering is the select box to present the choices.  The actual field used by SharePoint is handled in the getStandardInputHtml function.  Remember, it renders as a hidden field and I use a simple JavaScript function (moveValue, shown below) to copy the selected value from the dropdown list to the hidden field so it is available to SharePoint.

The moveValue function also handles my custom validation:

function moveValue(targetId) {

    var mySelect = document.getElementById('myNiftySelect')

    var hiddenField = document.getElementById(targetId);

 

    var selectedVal = mySelect.options[mySelect.selectedIndex].text

    if (customValidationPasses(selectedVal)) {

        hiddenField.value = selectedVal;

    }

    else {

        mySelect.selectedIndex = mySelect.selectedIndex - 1;

        selectedVal = mySelect.options[mySelect.selectedIndex].text

        hiddenField.value = selectedVal;

    }

}

 

function customValidationPasses(newValue) {

    if (newValue === "Four") {

        alert("Four is right out!  Counteth thou to THREE and then lobbeth thou the holy handgrenade of Antioch at thy foe, who, being naughty in my sight, shall snuff it.");

        return false;

    }

    return true;

}

There’s a fair amount going on in the editFunc function, but none of it is very complex.  This is another area I’d like to work on tweaking a bit.

As I said before, for the sake of this demo, I have hardcoded in an array to provide the choices for the dropdown:

//keeping it simple for the sake of this demo code - not really calling a service to get values

function getOptionsFromSimulatedWebServiceCall() {

    return ["One", "Two", "Three", "Four", "Five"];

}

 

If you needed to make this dynamic, simply change the code in that method (and probably its name, too) to do whatever you need.

Technical Details: New Form

The New Form rendering is actually handled by the editFunc function.  Notice back in the IIFE when we create the JSFieldText object that we pass editFunc in twice:

var r = new JSFieldText("SiteColumn1", viewFunc, editFunc, editFunc, displayFunc);

The first one is actually the New Form callback.  If you needed to render your field differently on the New Form, simply pass in a unique callback here.

Technical Details: Display Form

Last but not least is the Display Form.  Remember this shows the numeric representation of our field’s value (kind of lame, I know, but I wanted to show something different for each type of rendering and this was the best I could come up with).  The displayFunc function handles this for us:

/// Function called to render the DisplayForm view of the field

function displayFunc(renderCtx) {

    if (renderCtx != null && renderCtx.CurrentFieldValue != null) {

        var fieldVal = renderCtx.CurrentFieldValue.toString();

        switch(fieldVal)

        {

            case "One":

                return "1";

                break;

            case "Two":

                return "2";

                break;

            case "Three":

                return "3";

                break;

            case "Four":

                return "4";

                break;

            default:

                return "5";

        }

    }

    return '';

}

 

The Future’s So Bright…

I’m quite excited about the possibilities being opened up for developers with changes like the JSLink property in SharePoint 2013.  While a number of folks are bemoaning the move to the cloud and the changes that brings, I’m quite bullish on the whole thing.  Sure, there are some things I don’t like, but all in all, as a developer, I’m happy.  At least in the 2013 release, I don’t really lose anything very important for my on-premises deployments and I pick up significant ground in my cloud implementations.  A win all around.

Specifically for custom field types, I see this capability as incredibly powerful.  A nice, easy, standard (and supported) way of customizing the end user experience to be more efficient and friendly opens up a lot of possibilities.  I predict a small segment of the app store will be based around custom fields utilizing this capability.

Conclusion

That’s all there is to this.  As I said at the beginning, with it all laid out and explained, there’s not a lot to this and it is pretty easy.  I think that bodes well for this type of customization in the future.  I plan on spending a lot more time on this once the RTM bits are available.  Once I get it all working and cleaned up, I’ll integrate it into my JavaScript series and probably into a SharePoint 2013 version of the CKS:ScriptLibrary project as well.

Comments and ideas for additional functionality are welcome.  I do realize that a lot of the code in this needs to be cleaned up and like I said, I’ll get to that with the RTM bits.  If you have specific comments about something that doesn’t work, or could be refactored to make this better, I’d specifically like to hear those.

Source File: SampleJSField.js.zip

The SharePoint JavaScript Object Model–Resources and Real World Examples

Series Contents

  • Part 1: Introduction and Basics
  • Part 2: Deploy & Download
  • Part 3: The Client Side Object Model  (this post)
  • Part 4: Functions, Objects and Classes
  • Part 5: Avoid the Global Namespace *
  • Part 5: Download & Caching *
  • Part 6: Efficiency & Performance*
  • Part 7: Testing *
  • Part 8: Professional JavaScript Development *
  • Part 9: Error Handling *
  • Part 10: Advanced Topics *
  • Part 11: Security *
  • Part 12: Implementing Business Logic *
  • Part 13: Tools and Resources *
  • Part 14: Wrap-Up *
  • Bonus: JavaScript in SharePoint 2013 *

*: Coming Soon…

Synopsis and Key Take-Aways

This article introduces the JavaScript client-side object model (CSOM) added to SharePoint 2010, covering a discussion of when and why you would use the JavaScript CSOM and some important aspects that impact the performance and scalability of your application.  It finishes with a handful of examples of the CSOM in action performing typical (and perhaps not so typical) actions as well as links to other examples and reference material.

Introduction

If you’re new to the JavaScript CSOM, the best place to start learning about it is a decent overview.  You need to get an

Why Use the JavaScript CSOM?

There are a few key pieces of information about the JavaScript CSOM that will help to answer this question:

  • The code runs off of the SharePoint server in the users browser
  • The code can still interact with SharePoint at a pretty low level – retrieving content from SharePoint, creating and modifying content stored in SharePoint, modifying aspects of SharePoint itself (managing lists and libraries, pages web parts, etc.)
  • The code can be combined with other JavaScript libraries – most importantly JQuery

With that initial understanding, you can start to see benefits offered by the JavaScript CSOM: we can provide the rich, engaging user experience that our user’s want while still interacting with SharePoint in a way that maintains the integrity of our SharePoint server environment.

To give you an idea of what is possible before going into detail, here are a few things that can be done from the CSOM:

  • Full CRUD (Create, Read, Update & Delete) capabilities for List Items, Lists, Content Types, Webs and other key objects.
  • Add web parts to a page
  • Remove web parts form a page
  • Create new workflows associations for existing workflow templates
  • Work with user permissions for securable objects
  • Manage security groups
  • Activate/deactivate Features from a given scope
  • Manage fields on lists, libraries and content types
  • Work with files in document libraries
  • …and a whole lot more…

Why Would You NOT Use the JavaScript CSOM?

Not everything is available in the CSOM – some areas of SharePoint simply cannot be accessed by code utilizing the CSOM.  More on this in a moment.  In addition, some requirements are best met with server side code – see below for details.

What Can We Access?

In general, CSOM code can interact with SharePoint at the site collection level and below.  This means that the following are available:

  • SPSite (although we can’t reach outside of our current site collection)
  • SPWeb
  • SPList
  • SPDocumentLibrary
  • SPListItem
  • SPFile
  • SPField
  • SPUser
  • web parts
  • security
  • etc.

The The Official JavaScript Object Model Reference lists out all of the available objects.  It is important to note that not all aspects of some of these objects are available – some properties and methods available in the server side object model are blocked.  For example, you can access the Site object to get to a site collection, but not the SPSite constructor, which would allow you to connect to a different site collection; it is blocked.  One final note, the SPSecurity object is not available as well.  This means that you cannot do any type of elevation of privilege from the JavaScript CSOM.  All code runs as the current user.

When analyzing requirements to determine whether CSOM is an option, consider the level of access required.  In general, if it is within a single collection, you can probably do it with CSOM.

What Scenarios Don’t Work?

Even if you are only using allowed objects in your JavaScript code, there are some scenarios that just don’t lend themselves to client-side processing.  For example:

  • Processing large amounts of data – pulling all of that data across the wire down to the client may not be a good way to process it
  • Security concerns – pulling data across the wire to process it without some type of encryption (e.g. SSL) may present security problems
  • Code that needs to run whether users are connected to and browsing your site or not, for example workflows and timer jobs. 
  • Code that must respond to server-side events, such as after an item has been added to the database
  • Code that must run, and must run exactly as written.  This is a hard one.  User’s can turn off JavaScript.  Malicious users could also modify the cached version of the JavaScript file on their machine and run their modified code instead of the code you intended for them to run.  What happens to your data integrity and environment if your JavaScript code doesn’t run, or doesn’t run the way you expect it to run?  Understand that large portions of SharePoint will stop functioning or at least have a severely reduced level of functionality, but it is not impossible to use SharePoint with JavaScript turned off.  What happens to your environment then?  It seems to me that this is a largely ignored area, but that doesn’t mean it isn’t important.  Honestly, I don’t have a really good answer for this yet. It’s just an area you need to think about – what are the implications?

Requirements

To make use of the JavaScript CSOM in your SharePoint site, you need to make sure that the CSOM library is loaded by your page.  This will be done for you from the Master Page if you use one of the out-of-the-box  Master Pages.  If you use a custom Master Page, you must make sure that the sp.js file is loaded.  Part 2: Deploy & Download covers some aspects of this.  Additional material will be covered in later modules.

Advanced Topics

With a basic understanding of the JavaScript CSOM and what is and is not possible, we can move on to some more advanced topics.

Batch processing

All commands in the JavaScript CSOM are not executed immediately when the JavaScript engine in your browser evaluates the line of code.  Instead, the command is added to a batch and executed along with the other commands in the batch at a point in the future.  This is one of the fundamental paradigms of JavaScript CSOM programming that must be understood.  The hardest part of this whole operation is understanding when you must commit a batch and how to do so. 

At the most basic level, you must commit a batch of commands prior to interacting with the properties of any objects referenced in the commands.  An example will help to clarify this:

   1: function runCode() {

   2:   var ctx = new SP.ClientContext(); 

   3:   //Store the Announcements list in a variable:

   4:   var list = ctx.get_web().get_lists().getByTitle('Announcements');

   5:   //Store a list item in a variable

   6:   listItem = list.getItemById(4);

   7:   //Load the list item so we have access to its 

   8:   //properties

   9:   ctx.load(listItem);  

  10:   //To this point, we have not left the client and 

  11:   //none of our code has actually "done" anything.  

  12:   //All of the commands have simply been added to a 

  13:   //batch.  The next line sends the batch to the 

  14:   //server so all of our commands will execute.  

  15:   //After the following line has returned from its 

  16:   //call to the server, the list and list item we 

  17:   //"retrieved" are available for us to access and 

  18:   //work with its properties

  19:   ctx.executeQueryAsync(onQuerySucceeded, onQueryFailed);

  20: }

  21:  

  22: function onQuerySucceeded() {

  23:     alert('Item Title is ' + listItem.get_item('Title'));

  24: }

  25:  

  26: function onQueryFailed(sender, args) {

  27:   alert('Request failed.');

  28: }

Don’t worry about the details of what’s going on in that code sample for now.  We’ll look into those details later.  Read the comments to get an understanding of the code, but here are the things you need to know to understand the batch process:

  • All of the code from line 1 to line 18 runs on the client and has no interaction with the server.  For example, on line 4, the call to getItemById does not actually connect to the server and grab a reference to the SPListItem.  It simply adds the command(s) to the list of commands queued up to be committed (this is the “batch” referred to earlier)
  • Line 19 commits the batch to the server.  When this line executes, the batch is packaged up and sent across the wire to the server.  The server executes the code we’ve told it to run and returns a result to our page.
  • Line 19 also registers 2 callback methods – one for if the batch runs successfully (on lines 22-24), one if the batch fails (on lines 26-28).  After the batch has returned form the server, the appropriate callback method is run and the items collected in lines 1-18 (list & listItem) are available for use.
  • Line 23 references one of the properties from the listitem (specifically the Title property) that is now available to us because we have committed the batch to the server and gotten a populated ListItem back.

Why Batches?

The JavaScript CSOM code runs on the client machine, inside their browser.  As we saw above, it commits batches of commands to the server to be executed.  It then receives data from the server.  By operating in batches like this, the number of round trips across the wire is minimized.  Sending data to the server and getting a response is the slowest part of the CSOM; traversing the network is inherently slow.  The batch operation keeps our CSOM applications from being excessively chatty which would slow things down considerably.

Things to Know About Batching and Objects

The batch operations have a couple of quirks that are important to know.

Scalar and Collection Properties

Besides the fact that CSOM operates in batches like this, the only really important thing to know about the batched nature of CSOM operations is how we go about accessing objects and their properties in a CSOM application. 

For example, consider the following code:

var ctx = new SP.ClientContext(); 

var web = ctx.get_web();

ctx.load(web);

This code is responsible for filling up the (in this case) web object so that we can access its properties.  It is important to note, however, that not all properties of the object are filled up (populated) by this command.  It is only the scalar (i.e. non-collection) properties that will have data after a load command and its corresponding executeQueryAsyc command.  In other words, simple properties – ones with data types like string, int, bool, etc. are populated.  Properties that contain collections are not populated; they must be explicitly filled up.  In the case of the Web object, the following are examples of properties that would be populated after a call to load like we have in the code above:

  • id
  • rootFolder
  • serverRelativeUrl
  • title
  • etc.

These are all simple scalar properties.  (Note that this is not an exhaustive list of the scalar properties, and each object has its own collection of scalar properties.)

On the other hand, collection properties such as the following are not populated by the call to load shown above:

  • lists
  • folders
  • features
  • fields
  • availableContentTypes
  • etc.

These properties all represent a collection of items.  In order to populate these properties, we need to explicitly load the collection property:

var ctx = new SP.ClientContext(); 

var web = ctx.get_web();

var lists = web.get_lists();

ctx.load(lists);

ctx.executeQueryAsync(onQuerySucceeded, onQueryFailed); 

We can now work with the collection of lists from the Web.  Notice that we don’t need to load up the web object because we don’t access any of its properties, except the lists collection property, which we are explicitly loading.

If you don’t fill up a collection property and commit the batch before trying to access the collection property, you will get an error message that says The collection has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.

Performance: Property/Column Values and RowLimit

A key tenet of querying SharePoint data server-side is to only pull from the database the minimum you need to accomplish your requirement.  In other words, don’t pull back all of the columns on a list item if you’re only going to work with, for example, the Title and Body column values.  A similar approach is important for retrieving content from SharePoint with the JavaScript CSOM, with one additional reason – as stated previously, sending data across the wire is expensive in terms of performance.  The more data that has to traverse the wire, the greater the performance impact.  Therefore, it is important to only extract and pull down the values we need to work with.  In the JavaScript CSOM, this is done in one of two ways:

  1. Listing the property names we need in the load statement
  2. Trimming our queries to retrieve only the columns we need

The latter is the same concept as what we’ve done using SPQuery for years, although the syntax is slightly different, as you’ll see in a moment.  The former is new to CSOM. Unlike the load statements shown above which do not specify the properties we need, and therefore pull down all properties, a more efficient load statement would look like this:

ctx.load(lists, 'Include(Title,DataSource)');  

This would limit the properties that are populated on our lists object to just the Title of each list and the DataSource. If you do limit the properties that are populated in this way, you need to make sure that you specify every property that you need.  Similar to the error above if a collection property is not populated, if you attempt to access a scalar property that has not been populated, you will get an error The property or field has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.

The syntax for trimming the columns sent down to the client is similar to what we use on the server, but just slightly different syntactically:

var ctx = new SP.ClientContext();

targetList = ctx.get_web().get_lists().getByTitle('Announcements');

query = new SP.CamlQuery();

query.set_viewXml("<View><ViewFields><FieldRef Name='Title'/></ViewFields><RowLimit>2</RowLimit></View>");

listItems = targetList.getItems(query);

ctx.load(listItems); 

ctx.executeQueryAsync(onQuerySucceeded, onQueryFailed);

You can see the way the ViewFields elements are set into the query, which is stored in the viewXml property of the CamlQuery object.  This example will only retrieve the Title column value from the database and send it down the wire.

This example also shows how to limit the number of records that are sent down to the client.  This is another important aspect of maintaining performance. In this example, the result set is limited to the first two records by use of the RowLimit element..

Examples of Real World Tasks

There are only a certain number of core operations that are typically going to be done via the JavaScript CSOM.  There are dozens or hundreds of other operations to perform in CSOM, but the majority of the time, your operations will involve the following in some form and then add the other operations on top of these.

NOTE: I wrote some of these samples for MSDN back during the beta of 2010 and some of them are available in the SDK, although I tweaked some of them a little and tested them all for this blog post.

Get ListItem By ID

If you know the ID of a ListItem, this sample demonstrates how to retrieve it.  It also demonstrates how to retrieve a List by name.

 

var itemId = 4;   

var targetListItem;

 

function runCode() {

  var ctx = new SP.ClientContext(); 

  var targetList = ctx.get_web().get_lists().getByTitle('Announcements');

  targetListItem = targetList.getItemById(itemId);

  ctx.load(targetListItem, 'Title');  

  ctx.executeQueryAsync(onQuerySucceeded, onQueryFailed);

}

 

function onQuerySucceeded() {

    alert('Request Succeeded. nRetrieved Item Title is ' + targetListItem.get_item('Title'));

}

 

function onQueryFailed(sender, args) {

  alert('Request failed. nError: ' + args.get_message() + 'nStackTrace: ' + args.get_stackTrace());

}

Submit a CAML Query

This sample shows you how to query a list using CAML and iterate through all items in a collection.

 

var listItems;

 

function runCode() {

  var ctx = new SP.ClientContext();

  var targetList = ctx.get_web().get_lists().getByTitle('Announcements');

  var query = new SP.CamlQuery();

  query.set_viewXml("<View><Query><Where><Contains><FieldRef Name='Title'/><Value Type='Text'>MyValue</Value></Contains></Where></Query></View>");

  listItems = targetList.getItems(query);

  ctx.load(listItems);

  ctx.executeQueryAsync(onQuerySucceeded, onQueryFailed);

}

 

function onQuerySucceeded() {

  var listEnumerator = listItems.getEnumerator();

  while (listEnumerator.moveNext()) {

    alert("Found matching Item! nTitle=" + listEnumerator.get_current().get_item("Title"));

  }  

}

 

function onQueryFailed(sender, args) {

  alert('Request failed. nError: ' + args.get_message() + 'nStackTrace: ' + args.get_stackTrace());

}

Paging Through a ListItemCollection

This sample pages through the items in a list two at a time, unlike the previous example which iterates through all items in the returned collection in one operation.

var listItems;                   //holds retrieved list items

var query;                       //must continue to reuse the same query object for paging to work

var targetList;                  //list from which to retrieve items

var ctx;

               

 

function runCode() {

  ctx = new SP.ClientContext();

  targetList = ctx.get_web().get_lists().getByTitle('Announcements');

  query = new SP.CamlQuery();

  query.set_viewXml("<View><ViewFields><FieldRef Name='Title'/></ViewFields><RowLimit>2</RowLimit></View>");

  listItems = targetList.getItems(query);

  ctx.load(listItems); 

  ctx.executeQueryAsync(onQuerySucceeded, onQueryFailed);

}

 

function onQuerySucceeded() {

  var message = "Found Matching Items! ";

  var listEnumerator = listItems.getEnumerator();

  while (listEnumerator.moveNext())  {

    message += "nTitle=" + listEnumerator.get_current().get_item("Title")

  }

  alert(message);

  var position = listItems.get_listItemCollectionPosition();

  if (position != null) {

    query.set_listItemCollectionPosition(position);

    listItems = targetList.getItems(query);

    ctx.load(listItems);  

    ctx.executeQueryAsync(onQuerySucceeded, this.onQueryFailed);

  }

  

}

 

function onQueryFailed(sender, args) {

  alert('Request failed. nError: ' + args.get_message() + 'nStackTrace: ' + args.get_stackTrace());

}

 

Retrieve a Web – #1

This sample just retrieves the current web (whichever Web hosts the page containing the JavaScript.)

var targetWeb;

 

function runCode() {

    var ctx = new SP.ClientContext();

    targetWeb = ctx.get_web();

    ctx.load(targetWeb);

    ctx.executeQueryAsync(onQuerySucceeded, onQueryFailed);

}

 

function onQuerySucceeded() {

    var message = "Web retrieved:";

    message += "n Title: " + targetWeb.get_title();

    message += "n ID: " + targetWeb.get_id();

    message += "n Language: " + targetWeb.get_language();

    message += "n UI Version: " + targetWeb.get_uiVersion();

    message += "n Description: " + targetWeb.get_description();

    message += "n Created: " + targetWeb.get_created();

    alert(message);

}

 

function onQueryFailed(sender, args) {

    alert('Request failed. nError: ' + args.get_message() + 'nStackTrace: ' + args.get_stackTrace());

}

Retrieve a Web – #2

This sample shows how to retrieve a Web based on its server-relative URL.  Note: the Web being retrieved must be in the same site collection.

var targetWeb;

 

function runCode() {

    var ctx = new SP.ClientContext('/relative_url');

    targetWeb = ctx.get_web();

    ctx.load(targetWeb);

    ctx.executeQueryAsync(onQuerySucceeded, onQueryFailed);

}

 

function onQuerySucceeded() {

    var message = "Web retrieved:";

    message += "n Title: " + targetWeb.get_title();

    message += "n ID: " + targetWeb.get_id();

    message += "n Language: " + targetWeb.get_language();

    message += "n UI Version: " + targetWeb.get_uiVersion();

    message += "n Description: " + targetWeb.get_description();

    message += "n Created: " + targetWeb.get_created();

    alert(message);

}

 

function onQueryFailed(sender, args) {

    alert('Request failed. nError: ' + args.get_message() + 'nStackTrace: ' + args.get_stackTrace());

}

Retrieve a Web – #3

This sample shows how to retrieve the site at the root of a site collection from a child web somewhere else in the site collection.

var targetWeb;

 

function runCode() {

    var ctx = new SP.ClientContext('/');

    targetWeb = ctx.get_web();

    ctx.load(targetWeb);

    ctx.executeQueryAsync(onQuerySucceeded, onQueryFailed);

}

 

function onQuerySucceeded() {

    var message = "Web retrieved:";

    message += "n Title: " + targetWeb.get_title();

    message += "n ID: " + targetWeb.get_id();

    message += "n Language: " + targetWeb.get_language();

    message += "n UI Version: " + targetWeb.get_uiVersion();

    message += "n Description: " + targetWeb.get_description();

    message += "n Created: " + targetWeb.get_created();

    alert(message);

}

 

function onQueryFailed(sender, args) {

    alert('Request failed. nError: ' + args.get_message() + 'nStackTrace: ' + args.get_stackTrace());

}

 

Additional Examples From the SDK

There’s a section in the SDK with some good examples of common tasks.  Rather than completely reinvent the wheel, I’ll just link to them:

Reference Material

SDK: The Official JavaScript Object Model Reference (object/class reference)

SDK: CSOM Introduction (covers all three client object models and gets pretty deep pretty fast, but not a bad read)

JavaScript: Deployment and Download

Series Contents

  • Part 1: Introduction and Basics
  • Part 2: Deploy & Download (this post)
  • Part 3: The Client Side Object Model *
  • Part 4: Functions, Objects and Classes
  • Part 5: Avoid the Global Namespace *
  • Part 5: Download & Caching *
  • Part 6: Efficiency & Performance*
  • Part 7: Testing *
  • Part 8: Professional JavaScript Development *
  • Part 9: Error Handling *
  • Part 10: Advanced Topics *
  • Part 11: Security *
  • Part 12: Implementing Business Logic *
  • Part 13: Tools and Resources *
  • Part 14: Wrap-Up *
  • Bonus: JavaScript in SharePoint 2013 *

*: Coming Soon…

Synopsis and Key Take-Aways

This article covers important considerations for the mechanics of using JavaScript in your custom solutions and concludes with the recommendations for using a SharePoint Document Library as the repository for your script files, and the Custom Action approach to getting the files downloaded to the user’s browser.  Other approaches are reviewed briefly and discarded

 

Deploy and Download

In the first part of this series, we did a very basic overview of JavaScript, not really touching on SharePoint at all.  In this posting, we’re going start touching upon some SharePoint-specific aspects of working with JavaScript.  So far, all we’ve done is type some JavaScript directly in to the Console of our browser, we haven’t needed a server.  Obviously, that is not realistic for a production scenario.

In a real-world situation, we will have one or more JavaScript files, called libraries, which contain our code and need to be deployed to the server and then downloaded to the user’s browser when we need to access the functionality provided by the library.  Typically these libraries will have a .js extension and will be included along with other files in our Visual Studio project.  That project will generate a WSP (solution) file which will be deployed to our server environment at either the sandbox or the farm level.  When the WSP is deployed, it will make our JavaScript file available for download.  We then need to make sure that the file is downloaded.

Getting Started

For the sake of this post, I’ll assume that you have already created a VS project using one of the SharePoint project templates.  It doesn’t matter whether you create a farm solution or a sandbox solution.  I’ve used the Empty SharePoint Project template.  Create a new JavaScript library by right-clicking on your project node in Solution Explorer and select Add | New Item on the context menu.  In the dialog box that pops up, click Web in the template category listing on the left and then select JScript File:

image

This produces a blank JavaScript file in the root of your project, which is fine for now; we’ll move it in a little bit.  The name of my file is the default JScript1.js and I’ll refer to this name throughout this post.  If you use a different filename, you’ll need to adjust references later in the post as appropriate.  Add the following very basic JavaScript code to the new file and save it:

function sayHello(){

    alert("Hello World");

}

This is about the simplest JavaScript function you could imagine, but it is sufficient for our needs – we’re focusing on getting our JavaScript deployed and downloaded in this post, not on actually writing JavaScript.

Now that we have a file with some JavaScript in it, we can move ahead with deployment and then getting it downloaded to the user’s browser.  First we need to explore some options for deployment to understand the best option for the majority of the scenarios we will encounter.

Deployment Options

In a production scenario, we need to place the file which contains our JavaScript functions on the server and have it downloaded to the client to be executed.  The first thing this means is that we need to identify a location on the server to which our JavaScript file can be deployed.  The only real requirement for this location is that it be URL-addressable so that the user’s browser can request it and download it.  In SharePoint, there are several locations that could fit this bill:

  1. The _layouts virtual directory
  2. Ghosted site pages
  3. A Document Library

We’ll touch upon each of those in the following sections, and rule out all but the last.  A few notes about the criteria used to rate each option:

  • Performance is a consideration, though not necessarily a huge one thanks to browser caching
  • I’d prefer to keep my approach to JavaScript downloading as simple as possible so I’m looking for the broadest applicability of each approach. Approaches that work across a wide range of scenarios will rank higher.
  • Ease of maintenance is important
  • Supporting multiple versions of a library is important
  • Supporting metadata about the libraries is important
  • Flexibility is important – I don’t want my choice for deployment to dictate anything about the approach to usage of the libraries if at all possible

_Layouts

Deploying our .js files to the _layouts virtual directory is the most like a “regular” ASP.Net site.  When the user’s browser requests the file, it is delivered to them straight from the file system of the server.  In SharePoint, deploying to the _layouts virtual directory is easy – especially if we are using the Visual Studio Tools for SharePoint.  While it is arguably the easiest location to which we can deploy our .js files, as well as the location which delivers the best download performance, it is unfortunately not the best location for our script files.  For one thing, it is not sandbox compatible.  It is not possible to deploy files to the _layouts folder in a sandbox solution.  Another problem is that it offers the least capability from a metadata and management point of view.  For these reasons, it is not a recommended location to which to deploy JavaScript files.

 

Site Pages

The next option is to deploy our script files as ghosted site pages using a SharePoint Feature.  This overcomes some of the limitations of _layouts pages but not all of them.  Unlike _layouts, site pages are fully sandbox compatible.  That’s a good thing.  From a performance point of view, in non-sandbox solutions (i.e. farm solutions), performance will be comparable to _layouts pages as the site pages will be delivered from the file system, even though we deploy them as site pages.  In sandbox solutions, performance will not be quite as good as the content will be served from the content database instead of the file system.  That’s not necessarily a bad thing, but it is worth mentioning.  The one thing that site pages does not address is the manageability of the script libraries.  Managing our files requires SharePoint Designer and there is still no effective means for managing metadata about our script files when deployed as site pages, so we will not be exploring this option any further.

Document Library  **Recommended**

The final choice for deploying script files is to push them to a document library via a Feature.  This is the recommended location for our script files.  Primarily this is because it offers us the most capabilities for managing those script libraries, as we’ll see in just a moment.  It is important to note, however, that deploying to a document library will have a slight performance impact when our files are requested and downloaded to the user’s browser.  Normally a known performance impact is something we would try to avoid.  However, in this case it is OK for one main reason –   JavaScript files are cached on the user’s machine and so they do not get downloaded with every page.  This means that we typically only incur that slight performance hit once per user.  The rest of the time, when the browser needs our JavaScript file, it pulls it from the local cache instead of re-requesting it from the server.  Thus the performance impact is avoided on all subsequent page loads.  If the user clears their browser cache, the file will be automatically redownloaded.

This works so long as you have repeat visitors (so the JavaScript files will be cached on the client), such as in an intranet or perhaps an extranet.  In Internet-facing sites, the performance implications may be more severe and the benefits of the document library somewhat lessened.  In that case, the _layouts folder may be a better option.

Deploying to a Document Library

Deploying JavaScript files to a document library is trivially easy, as you’re about to see.  We’ll begin from our very basic SharePoint project discussed above, containing just the single JavaScript library.  In order to deploy this file to a document library, we first need to make sure that the document library exists in our site. 

Note: If you know that this document library already exists in your site, you can skip this step.

 

Creating the Scripts library

In SharePoint 2010, we can very easily add an instance of the Scripts document library to our project:

  1. Right click on your project name in Solution Explorer
  2. Select Add | New Item
  3. Select the SharePoint | 2010 category from the list of installed template categories
  4. Select the List Instance template
  5. Change its name to Scripts
  6. Click Add

image

In the next dialog box, configure the options as shown and click Finish:

image

Add the JavaScript file to the Scripts document library

Whether we just created the document library or it existed already, we add our JavaScript file to it in the same manner:

  1. Right click on your project name in Solution Explorer
  2. Select Add | New Item
  3. Select the SharePoint | 2010 category from the list of installed template categories
  4. Select the Module template
  5. Change its name to ScriptFiles
  6. Click Add
  7. In Solution Explorer, delete the Sample.txt file included in the ScriptFiles module
  8. In Solution Explorer, click on the JavaScript file we created earlier, drag it and drop it on the ScriptFiles node.
  9. If the Elements.xml file for the ScriptFiles module is not open, double click it in Solution Explorer to open it
  10. Notice that the Elements.xml file has been updated to include a reference to the file we just added to the module
  11. Change the XML in the Elements.xml file to look like this:
<?xml version="1.0" encoding="utf-8"?>

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

  <Module Name="ScriptFiles" Url="Scripts" List="101">

      <File Path="ScriptFilesJScript1.js" Url="JScript1.js" Type="GhostableInLibrary" />

</Module>

</Elements>

     

That’s all you need to do to make sure that your JavaScript file is properly deployed to your SharePoint environment.  If you’d like to test it out, hit F5 and when the browser comes up, navigate to <site URL>/Scripts.  You will see your JavaScript file listed:

image

Getting the file deployed is only half the battle.  Now we need to get it downloaded to the users browser so it can be used.

Downloading Options

JavaScript libraries are useless if they never leave the server; they must be downloaded to the user’s browser in order for the code they contain to be executed.  Similar to getting our library deployed, there are several options for getting it downloaded.  We’ll explore each option, discussing its pros and cons before declaring a winner.

A couple notes about the criteria I’m using to evaluate these options:

  1. Performance is a consideration, though not necessarily a huge one thanks to browser caching
  2. I’d prefer to keep my approach to JavaScript downloading as simple as possible so I’m looking for the broadest applicability of each approach.  Approaches that work across a wide range of scenarios will rank higher.
  3. I’m looking for the broadest reach when deploying.  I want one place to manage all of my JavaScript downloads.  I am not interested in deploying specific libraries only to specific pages in my application or conditionally downloading libraries based upon some criteria.  The vast majority of your JavaScript is likely to be used in multiple places so combining it together and downloading it in a small number of requests and taking advantage of browser caching makes sense.  While it is true that some JavaScript will only be needed on certain pages, it is far better to use a delayed loading or script-on-demand approach (discussed in part 11 in this series) to control those downloads.
  4. Compatibility with a delayed-loading scheme such as SharePoint’s Script On Demand is important

ScriptLink Control

The ScriptLink control was introduced in SharePoint 2007 and is still available in 2010.  Its main responsibility is to cause a JavaScript file to be downloaded to the user’s browser.  It does this by ensuring that the proper <script> tag is written into the HTML stream.  While the ScriptLink control is often recommended, I am going to shoot it down for two reasons:

  • it is not sandbox compatible.  Say what you will about the sandbox, and even toss in the fact that it is not a recommended approach for SharePoint 2013, it is an option in 2010, is the only option for server-side code in Office 365 and therefore important, at least for now.  As SharePoint and SharePoint Online evolve, this will need to be revisited.
  • it is hard to maintain as needs change.  In this way, it is similar to adding the <script> tags directly to the master page – changing it requires editing the master page in SharePoint Designer, which is something that should be avoided.

It is unfortunate that the ScriptLink suffers from these drawbacks, because it does provide value that we’re going to be hard-pressed to replicate.

Master Page Script Tags

Adding <script> tags to your master page is just not a good idea.  They’re hard to maintain, hard to work with initially, don’t travel well if you switch master pages, require SharePoint Designer to edit and various other problems.  While they may seem initially like a good idea, they’re just not in the long run.  Don’t do it.

Web Part

This option entails using the dreaded Content Editor Web Part to add a <script> tag directly to a page.  This is troublesome for a few reasons:

  • It is page-specific.  It only impacts the page to which you add it.  While this may seem like a good thing, it is not.  There are many pages in SharePoint that you can not add a web part to – how will you get your JavaScript onto those pages?  It also means that you need to add this web part on to every page upon which you want the JavaScript available.  If your needs change, there are a lot of places that you will now need to change.
  • It does not version well, cannot be included in source control and makes debugging more difficult.  These all fall under an umbrella of professional development disciplines and the CEWP fails miserably here.

Custom Action   **Recommended**

Adding the HTML to our page via the SharePoint Custom Action element offers many advantages and no disadvantages.  It is easily the best option:

  • It is fully sandbox compatible and fully farm compatible.  This means that I can use the same approach no matter how my solution is being deployed.
  • It is global – all pages in the scope at which we activate its Feature (Site or Site Collection) will have the appropriate HTML added to it
  • It is flexible and easy to maintain.  We take advantage of the SharePoint Feature framework to be able to turn the functionality on and off at whatever scope we need it
  • There are no performance penalties to using the Custom Action
  • It is fully compatible with SharePoint’s Script on Demand functionality and various other delayed loading schemes we’ll talk about in part 11 of this series. 

Therefore it is easy to declare the Custom Action as the best option for getting our JavaScript files downloaded.  The next section walks through how to accomplish this.

Downloading with a Custom Action

Adding the necessary HTML to our pages to cause our JavaScript files to be downloaded with a Custom Action element is easy:

  1. Right click on your project name in Solution Explorer
  2. Select Add | New Item
  3. Select the SharePoint | 2010 category from the list of installed template categories
  4. Select the Empty Element template
  5. Change its name to MyJSFile
  6. Click Add

Add the following to the Elements.xml file that Visual Studio creates and opens for you (placing it between the opening and closing Elements tags):

<CustomAction

    Location="ScriptLink"

    ScriptSrc="~Site/Scripts/JScript1.js"

    Sequence="10"

    Id="MyScriptLibrary"

/>

That’s it. SharePoint will now add the following to every HTML page in our site:

document.write('<script type="text/javascript" src="/scripts/jscript1.js"></' + 'script>');

This will cause our custom JavaScript library to be download (if it is not already cached on the client) and made available for use.  The functions in our library are now available to be called and executed.  Notice in the Custom Action element the use of the token ~Site.  When activated within SharePoint, this will be replaced with the URL of the site at which the Feature is activated.  Another useful token is ~SiteCollection, which gets replaced with the URL of the site collection.

If you’re curious why SharePoint adds the tag using a document.write instead of simply adding the <script> tag, it’s a mechanism for overcoming some quirks in how browsers download and parse JavaScript files. Without going into too much detail (which I’ll do in another post), it prevents one script from blocking the download of other page elements (scripts, images, CSS, etc) while the script is downloaded and parsed. More on that in a separate post.

 

To test this out, simply hit F5 to deploy and run your code.  After the browser opens to the homepage of your site, type the following into the address bar of the browser: javascript:sayHello(); and hit Enter.  The results should look something like this:

image

Our JavaScript code in the library (the sayHello function defined earlier) ran and popped the alert box up on the screen.  A very simple example, but sufficient to test out our process.  We’ve successfully deployed a JavaScript library to SharePoint and had it downloaded to the client.  Later in this series we’ll be developing more complex JavaScript libraries to begin offering real world functionality, but we’ll take advantage of the same mechanisms we’ve covered in this post for deployment and download.

Other Considerations

There are a number of tangential topics that need to be addressed in order to wrap up any discussion about deploying and downloading JavaScript libraries – improving download and caching, overall performance, etc.  These topics will be addressed in parts 5 (Download & Caching), 6 (Efficiency & Performance) and 10 (Advanced Topics). 

Wrap Up

This post has answered the question of “What is the best way to deploy my custom JavaScript to SharePoint and then have it get downloaded to the user’s browser?”  We’ve discussed a number of options and whittled down to the best approach – document libraries and Custom Action elements.  No matter what functionality we’re looking to introduce – form the simplest of examples (such as the project used here) to the most complex of scenarios, this approach will work equally well.

An Introduction to JavaScript

Series Contents

  • Part 1: Introduction and Basics (this post)
  • Part 2: Deploy & Download
  • Part 3: The Client Side Object Model *
  • Part 4: Functions, Objects and Classes
  • Part 5: Avoid the Global Namespace *
  • Part 5: Download & Caching *
  • Part 6: Efficiency & Performance*
  • Part 7: Testing *
  • Part 8: Professional JavaScript Development *
  • Part 9: Error Handling *
  • Part 10: Advanced Topics *
  • Part 11: Security *
  • Part 12: Implementing Business Logic *
  • Part 13: Tools and Resources *
  • Part 14: Wrap-Up *
  • Bonus: JavaScript in SharePoint 2013 *

*: Coming Soon…

Introduction

As the title of this post states, this is an introduction to JavaScript and using it in SharePoint.  It has some good information in it for any JavaScript developer, but it is very basic.  If you are already familiar with JavaScript, go ahead and skim this post or skip it entirely.  There likely won’t be a lot of new material here for you.  If, however, you are just getting started with JavaScript, read on.  You’ll probably learn a thing or two.

JavaScript is not a new technology, and yet it appears to be new to a lot of SharePoint developers.  I honestly don’t know why.  This series is going to take a look at JavaScript from a dev’s point of view and attempt to explain how it can be a very powerful tool in our toolbox.  I’m going to repeat one point there just to make sure you got it: this is a developer’s point of view.  That means no Content Editor Web Part (CEWP, the root of all evil).  It also means Visual Studio, deploying Solution Packages, and generally approaching JavaScript as a coding language (which, after all, is what it is).  If all you want to do is grab a script and toss it into a CEWP, this is not the right place for you.  Please move along.  We’re talking professional developer stuff here.  :-)

Starting right at the beginning – why would we use JavaScript in our SharePoint code when we have a rich server-side API available to us?  That’s an easy one – because not everything can or should be done on the server.  That’s not to say that the server side API is useless.  Quite the contrary – both are necessary to deliver an effective, modern application (whether on SharePoint or not.)  Despite what you may think, and what you may read elsewhere, neither JavaScript nor the server API can solve 100% of the business problems we face.  Too, SharePoint is just a great big ASP.Net application so using JavaScript is not going out on the limb of unsupportability.

In recent years, JavaScript has grown up considerably.  The addition of libraries such as JQuery, Dojo and MooTools have helped make JavaScript to become more popular.  In the SharePoint world, SharePoint’s JavaScript Object Model has brought JavaScript to the foreground.

One quick point here about JQuery.  Nobody anywhere has ever written a single line of JQuery.  There is no such thing.  JavaScript is a language.  JQuery is a library.  We use JQuery to make JavaScript easier to work with, but we don’t write JQuery.  This may seem like a pedantic nit, but it is an important distinction for one reason: there is a wealth of JavaScript material on the web that you ignore at your peril.  If you always look for a JQuery solution, you are almost certainly making your life harder.  That’s not to say that JQuery isn’t a great library; it is.  It’s just not always the answer.  Sometimes a few well-crafted lines of JavaScript are all that is necessary.  There’s not always a need to fall back on JQuery and it’s library of plug-ins.

What Can We DO With JavaScript in SharePoint?

Another easy one.  Just about any UI manipulation we care to write the code for.  This can range from pure eye-candy to something that provides actual business value.  The only times you can’t manipulate the UI are:

  • Content delivered via a plug-in of some type (Silverlight, Flash, ActiveX, etc) (Although, some of these do offer a limited ability to manipulate them via JavaScript )
  • If JavaScript is turned off in the user’s browser

Anything else is fair game, and that is both boon and bane.

DOM Scripting

When you are manipulating the user interface, you are doing what is called DOM scripting or DOM manipulation.  DOM stands for Document Object Model and it is the hierarchical representation of the HTML markup that the browser uses to render your page.  Every object shown on the page (and also those not visible) are represented by a node nested inside the DOM.  Changing the characteristics of those nodes, adding nodes and removing nodes all result in a changed interface being shown to the user – changed, that is, from what the server originally sent down to the browser.

What You Need to Know

At a very basic level, there are a few important things to know about using JavaScript:

  1. JavaScript is an interpreted language and so there are no DLLs that need to be deployed to the server
  2. JavaScript is downloaded to the user’s machine and parsed /executed there.
  3. JavaScript is downloaded in clear-text (though it may be somewhat obfuscated).  This is potentially a big deal as we’ll discuss in Part 12.
  4. Although there is a standard definition of JavaScript (ECMA-262, version 5.1), different browsers will interpret your JavaScript code slightly differently.  This has an impact on testing, as we’ll discuss in Part 8.
  5. Once downloaded, JavaScript files are cached on the user’s machine to improve performance.
  6. JavaScript is case-sensitiveHELLO is not the same as hello and not the same as Hello.
Another pedantic nit here: JavaScript is neither Java nor Java-lite.  Other than some semantic similarities, it has nothing to do with Java.

Your First JavaScript Program

Enough introductory drivel.  Let’s write some code.  Fire up your browser of choice and navigate to any website. Assuming that you’re using a relatively modern browser (IE 7 or later , Firefox or Chrome) open up the developer tools: in IE and Chrome, simply hit the F12 key.  In FF, hold down Ctrl and Shift and hit the K key.

In IE: Click the Script tag and then the Console button below it:

In Chrome, click the Console button:

In FF you don’t need to do anything, the Console is automatically shown:

In the browser/JavaScript console (where indicated in the above screenshots for your browser), type the following code:

alert("Hello World");

Now hit enter.  You should see a small dialog box pop up that shows your message.  Click OK to close the dialog box.

Congratulations, you’ve written your first JavaScript program.  (We’ll revisit each of those Console windows later on in this series).

It’s time to get a little more advanced (but just a little).

Variables

Like any programming language worth it’s salt, JavaScript has variables.  Declaring and using variables is easy:

var myVariable="Hello World";

alert(myVariable);

You can type that in the same Console and you should get the same results.  The variable declaration (“var myVariable=”HelloWorld”) defines a variable which is then referenced in the following alert statement.  At that point the value of the variable (in this case “Hello World”) is used by the alert.  Go ahead and give it a try.

There are a few things that can get tricky about variables, but we’ll cover those later.  For now, here are a couple of rules to remember:

  • JavaScript variables are not typed.  In other words, you don’t declare the data type that the variable will store when you declare the variable, and changing data types is perfectly OK.  The following is perfectly valid, although perhaps not a great practice:
var myVariable="Hello World";

alert(myVariable);  //outputs Hello World, myVariable holds a string

myVariable=345;

alert (myVariable);  //outputs 345, myVariable holds an integer

  • var is your friend.  99% of the time, you always want to preface your variable declarations with the var keyword.  This declares the variable as local to your current scope.  We’ll talk about this more later in part 5.  For now, and until you understand the implications of not doing so, always use var
  • Null – variables are null if it contains an unknown value, which is not the same thing as undefined.
  • Undefinedundefined is a special value in JavaScript.  It means the variable has not been declared (in the current scope – more on that in part 5), or has been declared but has not been given a value.

Functions

JavaScript is organized into functions.  A function is a group of statements organized together in what essentially amounts to a named container.  Here is an example of a function declaration and usage:

//declare the function:

function sayHello(){

    alert("Hello World");

}


//call the function:

sayHello();


 

Passing a parameter to the function is equally simple:

//declare the function with a parameter:

function saySomething(thingToSay){

    alert(thingToSay);

}


//call the function and pass in a parameter:

saySomething("Hello World");

We’ll touch on some advanced function declarations and usage in part 4.

Wrap Up

That’s a quick, high-level tour of the basic stuff you need to know to begin operating in a JavaScript world.  There is obviously a lot more that needs to be covered – or else I wouldn’t have 14 more sections planned :-).  We’ll get to all of that in later sections of this series.  Hopefully this has gotten everyone on the same page.  We’re pretty quickly going to move into the deep-end, so buckle up…

Questions from my CPT Webinar

I delivered my installment in the Critical Path Training 2012 Webinar Series last week covering JavaScript for SharePoint developers.  Overall I think the session went pretty well.  If you missed it, the recording is available here: Watch the recording.  The only real problem was that, as usual, I had WAY too much material to cover in the 45 or minutes allotted.  As a result, I didn’t get the chance to answer any of the questions that the attendees asked during the session, so here are the questions and answers:

Q: Do you recommend minimizing your js files?

A: Absolutely!  Minimizing and compressing your JavaScript files is an easy way to improve the performance of your site.  In addition, wherever possible, try to  minimize the number of individual script files that need to be downloaded.  Less HTTP requests means better performance.


Q: Is this a sandbox solution?

A: (I’m assuming the question is about the CKS:ScriptLibrary solution I demonstrated).  Yes.  The CKS:Script Library is fully sandbox-compatible.


Q: Is SOD (Script On-Demand) available in sandbox solution?

A: Yes.  The only related thing that is not is the ScriptLink control.


Q: Does the usage of javascript extend to jquery?

A: JQuery IS JavaScript, so yes.  As I said in the session – there is technically no such thing as “writing JQuery.”  You use the JQuery library to make it easier to write JavaScript.


Q: SP in the first line…SP.ExceptionHandlingScope that is in what library?

A: SP.Runtime.JS


Q: What other method of loading JS files is there besides Visual Studio solutions if you don’t want to use CEWP…?

A: A VS Solution is really the best method of getting the .js files placed on the server.  My (distant) second choice would be manually loading them into the script library manually via the browser.  The (evil) CEWP comes into play when you’re talking about referencing script files on a given page.  At that point, I would recommend a Custom Action, editing your Master Page, adding it via a web part, or just about any means except using the CEWP.


Q: Where would you recommend for us to learn & deep dive into these advanced javascript language & concepts you are talking about – learning resource? approach? so we can pickup these professional js skills easier?

A: There is a wealth of JavaScript information available on the Internet.  A simple search will turn up quite a lot of good resources.  My somewhat self-serving answer would also be to keep an eye on this blog.  I’ll be covering a lot more material over the next couple of weeks.


For those of you who caught the release of the SharePoint “15” Preview earlier today, this JavaScript stuff only gets more important in the next version of SharePoint, so it would behoove us all to come up to speed on it as quickly as we can.  I hope I can help with that…

Thanks,

Dave

PS: If you’re looking for SharePoint 2010 developer training, I’ll be teaching the CPT 2010 developer course as a webcast on September 10th.  More information is available here: WC-SPT2010 – Developing Solutions with SharePoint 2010 Webcast