Friday, February 26, 2010

SharePoint 2010 - Client Object Model - ECMAScript - Introduction on how to use

In SharePoint 2010, the great feature is introducing the client object model [Read this article before proceed]. The great advantage with this is, we can do plenty of things without server side coding using the ECMAScript. There are plenty of default supported files to use and do whatever you want with the SP Package files. All javascript files will be found in the layouts folder. All of them starts with "SP" name.

ECMAScript works only for the current context. It means from outside of the site, you can't access the SharePoint data. This won't support the cross-site scripting.

How to add the reference to SP.js and access the data?
  1. Refer it from the client side: Create a js file somewhere in the SharePoint site which can be accessible and write the below line as the first line.
    ExecuteOrDelayUntilScriptLoaded(initialize, "sp.js");
  2. Refer it from the server side: Add the below line to the ASPX page.
Note: It's not really needed to use refer from server side code added to page to execute the code.

What this method is doing?
In javascript when you request files, all will load asynchronously. I mean, they will load randomly and what if your javascript is using sp.js file and it's not loaded yet? This will be a problem. So, this method helps to tell the browser to wait and execute the "initialize" function if and only if sp.js file is loaded.

Note: If you are using the separate js file then paste the below code by removing the script tags. If you are using the script on ASPX page or in Content editor web part then copy all the code and paste.

A small example:
<script type="text/javascript">
ExecuteOrDelayUntilScriptLoaded(getWebSiteData, "sp.js");
var context = null;
var web = null;
    function getWebSiteData() {
        context = new SP.ClientContext.get_current();
        web = context.get_web();
        context.load(web);
        context.executeQueryAsync(Function.createDelegate(this, this.onSuccessMethod), Function.createDelegate(this, this.onFailureMethod));
    }
    function onSuccessMethod(sender, args) {
        alert('web title:' + web.get_title() + '\n ID:' + web.get_id());
    }
    function onFaiureMethodl(sender, args) {
        alert('request failed ' + args.get_message() + '\n' + args.get_stackTrace());
    }
</script>
Explanation:
I think you understood well by seeing the above without any difficulties. Simply I will explain the steps.
  1. I am getting the current context by calling the get_current() method.
  2. Get the current web site [Where we have write the javascript code, will get that web object.]
  3. context.load() - I know it's not straight forward to understand. But, it's simple. When you send the request to server, what we need to get back from the server as response? That is what we need to place in the load method. In this case, load is invoked with web parameter. It means it will load the complete web object with all properties.
  4. When you write load, it means it won't load the object immediately. We need explicitly call it by using executeQueryAsync() method. As the name says, this method is asynchronous call. And the syntax shows that it is a callback call. It has the success method and the failure method. So, when the query is succeeded then it goes to the success method, otherwise it goes to the failure method.
Load only the data you want, not the whole web object:
This is a performance and efficient related thing. Everyone knows in SQL, why we don't use select * always, and use only select and then only columns you needed to process something in the selected list? The same reason here too. Don't query all the properties in an object and only query the properties you actually needed. This is looking fine, but how to do that? In  my above example, I am actually using only Title and Id, I want to load only them. For that I need to use the below line.
context.load(web, 'Title','Id');  
If you added comma separated properties then it will query those properties and load data. There is another option also available named loadQuery(). I will tell you about this in later posts.

NOTE: Remember, all the properties are case-sensitive. I have wasted 1 hour to find out a small problem. I have used the 'ID' instead of 'Id' in properties and running into trouble. So, make sure you are aware of that.

You can debug and there is a file which helps you to debug upto inner imeplementations. The file is sp.debug.js and you can find it in layouts folder. This is good practice to use it on dev environment, but don't forget to remove this reference on the production environment.

11 comments:

  1. Excellent Post. My requirement is to get a list of all subsites in a site collection using ECMAScript. The code I have iterates over only one level under Site Collection. However, Site Collection has Subsites across multiple levels. What changes need to be done to the code to accomplish this ?

    function retrieveAllSites() {

    var clientContext = new SP.ClientContext(siteUrl);
    this.sitesGroup = clientContext.get_web().get_webs();
    clientContext.load(this.sitesGroup );

    clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded),

    Function.createDelegate(this, this.onQueryFailed));
    }

    function onQuerySucceeded() {

    var sitesInfo = '';

    var groupEnumerator = this.sitesGroup.getEnumerator();
    while (groupEnumerator.moveNext()) {
    var oSite = groupEnumerator.get_current();
    sitesInfo += '\nSite ID: ' + oSite.get_id() +
    '\nSite Name: ' + oSite.get_title();
    }

    alert(sitesInfo);
    }

    ReplyDelete
  2. Hi, you have a little error in a code:

    Error:
    function onFaiureMethodl(sender, args) {

    This should be:
    function onFailureMethod(sender, args) {

    ReplyDelete
  3. Thank you - this post has actually explained why this JavaScript works rather than me just repeating it without understanding. Much appreciated

    ReplyDelete
  4. I put this script in html or aspx page in sharepoint designer 2010, but I could not get the logged in username. I understand that it has to be in sharepoint site, but I am putting it in sharepoint site, it lives in sp site. Also, I tried to put it in masterpage, but still no result. How can I do it? Thanks

    ReplyDelete
  5. Hi there, we should not use designer for running the code.
    Follow steps below:
    1. Go to a SharePoint Web part page from the browser.
    2. Edit page, and then add Content Editor Web Part
    3. Copy the code which is in this post and paste it here.
    4. Save the page and see the code working fine.

    Let me know if you have any issues.

    thanks
    -Praveen.

    ReplyDelete
  6. Thanks. This not only resolved a problem, the solution provides additional useful insight!!!

    ReplyDelete
  7. Thanks a lot, it helped.

    ReplyDelete
  8. Thanks Praveen for sharing the article

    ReplyDelete