Wednesday, November 23, 2011

SharePoint 2010: ECMA Script Client OM & Examples

SharePoint 2010: ECMA Script Client OM

Before going to the post please read this post SharePoint 2010 : Client OM to get the more information related to SharePoint Client OM.


Few points to notice about ECMAScript Client OM:


  • ECMAScript Client OM can only be used in SharePoint sites. So you can’t use this OM in an asp.net site to access SharePoint resources deployed in another URL as this is cross-site scripting and not allowed.
  • You can’t use this OM in a SharePoint site to access resources in different SharePoint sites (i.e., different url’s). For example, from mysite.mysp.com you can access resources in yoursite.yoursp.com using ECMAScript client OM. This is also cross-site scripting.
  • You can use JQuery with ECMAScript Client OM and for this you don’t need to do some extra work. All you need to do to use JQuery is to add reference to JQuery.js file and start using JQuery.
  • You can use this ECMAScript Client OM in web part pages or application pages (aspx pages) by referencing a javascript file (SP.js). You don’t need to add reference to the file manually rather use <SharePoint: ScriptLink Name=”sp.js” ………. />. The file is located on the path “Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS”
  • To update with JavaScript, you need to add a FormDigest tag in your page for security purpose.

Use ECMAScript Library: A Sample program

At first use Visual Studio 2010 to create a SharePoint web part project. As a result, VS2010 will open a ascx control for you on the designer. 

1. Add reference to js file:


To use Client OM, add an entry like below in your web part ascx control. For your information, there’s an debug version of the sp.js called sp.debug.js which you can use for debugging but should not be used in production.

<SharePoint:ScriptLink Name="SP.js" runat="server" OnDemand="true" 
    Localizable="false" />

Here, OnDemand means whether the sp.js file need to be loaded on demand (not in page load) or not.

2. Add FormDigest tag:


If your code modifies SharePoint content add a FormDigest control inside your page. The FormDigest add a security token inside your page based on user, site and time. Once the page is posted back the security token is validated. Once the security token is generated it’s valid for a configurable amount of time. Add the FormDigest inside <form>…</form> tag, as shown below:

<SharePoint:FormDigest runat="server" />

For more information on FormDigest follow the links below:

3. Use Client OM to retrieve data:

Now you can use SharePoint ECMAScript library. Let’s dissect the code snippet below. The first thing in using this library is that you need to get the ClientContext (just like SPContext). Then the context.get_web returns the current web (just like SPContext.Current.Web). Then client context’s load method is invoked passing the web object. Then the executequery method is invoked asynchronously passing two functions: onSuccess and OnFailed which will be called on success and fail correspondingly.

<script type="text/javascript">
    function getWebProperties() {
        var ctx = new SP.ClientContext.get_current();
        this.web = ctx.get_web();
        ctx.load(this.web);
        ctx.executeQueryAsync(Function.createDelegate(this, this.onSuccess),
            Function.createDelegate(this, this.onFail));
    }
    function onSuccess(sender, args) {
        alert('web title:' + this.web.get_title() + '\n ID:' + this.web.get_id() + 
            '\n Created Date:' + this.web.get_created());
    }
    function onFail(sender, args) {
        alert('failed to get list. Error:'+args.get_message());
    }
</script>

By calling getWebProperties method from any web part, you can get the current web’s title, id and creation date.

4. Load minimal data you need:


In the above code snippet, the Ctx.load method is invoked with only one parameter (web). The load method will load all properties of the web object. But we are only using Id, Title and Created Date properties. If you know which properties you are interested in, you can pass the properties names in the load method and only those properties will be loaded. For example the following load method will return only ID, Title and Created Date.

ctx.load(this.web,'Title','Id','Created');

Remember, here the properties names are properties of SPWeb. You need to pass Title instead of title. The properties name uses CAML casing. You can get the full lists of ECMAScript namespaces, object, properties following the link on MSDN. The document is not final yet and may be changed.

You can also look into the sp.debug.js file in the folder “Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS”, to get an idea of objects, properties and methods of ECMAScript Client OM.

5. Execute your JavaScript function after sp.js is loaded:


Sometimes you may need to execute your JavaScript (that uses ECMAScript Client OM) on page load in the browser. But since your JavaScript is using sp.js file and if the sp.js file is not loaded yet (since to lazy loading nature of sp.js), when your custom JavaScript will be executing, you’ll get your JavaScript function not executed. In this case you need to make sure your JavaScript code runs after sp.js finishes loading. You can do so by putting your JavaScript method call inside a js function as shown below:

ExecuteOrDelayUntilScriptLoaded(myjsfucntion, "sp.js");

Putting your JavaScript function (i.e., myjsfunction) inside the ExecuteOrDelyUntilScriptLoaded method delays your method call until the sp.js file is loaded.

6. Update with ECMAScript Library:


You can use the Client OM to update SharePoint contents. The following code snippet shows how to update web title.

<script type="text/javascript">
    function updateTitle() {
        var ctx = new SP.ClientContext.get_current();
        this.web = ctx.get_web();
        web.set_title('UpdatedTitle');
        this.web.update();
        ctx.executeQueryAsync(Function.createDelegate(this, this.onUpdate),
            Function.createDelegate(this, this.onFail));
    }
    function onUpdate(sender, args) {
        alert('title updated');
    }
    function onFail(sender, args) {
        alert('failed to update title. Error:'+args.get_message());
    }
</script>

By calling the updateTitle method from any web part or SharePoint application pages, you can change the title of current web site (where the web part or application page is deployed). For your information, in ECMAScript Client OM, to get an property use get_propertyName and to set a property use set_propertyName. To update list with ECMAScript library you need to add FormDigest tag.

Use JQuery with ECMAScript


You can use JQuery with ECMAScript without any conflict. As usual, you need to add jquery.js file reference to your page/web part or in master page. Then you can use JQuery as like normal asp.net applications. But make sure that if you need to execute any JavaScript function on page load event, you put this inside ExecuteOrDelayUntilScriptLoaded function.

Deployment Consideration


SharePoint provides two sets of JavaScript file: minified and unminified/debug version.

For example sp.js file is minified and sp.debug is minified and debug version.

The default master page in SharePoint has a scriptmanager in the page and whose ScriptMode is set to auto, as a result the minified version of js file loaded.

If you want to use debug version you can add the <deployment retail="false" /> in the <system.web> section of the web.config. In the production you need to remove this entry to make sure minified version is used.

ECMA SharePoint 2010 Code Examples:


1.       To Create A List

<script type="text/javascript">
var clientContext = null;
var web = null;
ExecuteOrDelayUntilScriptLoaded(Initialize, "sp.js");
function Initialize()
{
clientContext = new SP.ClientContext.get_current();
web = clientContext.get_web();
var itemCreateInfo = new SP.ListItemCreationInformation();
var listCreationInfo = new SP.ListCreationInformation();
listCreationInfo.set_title('My Custom Generic List');
listCreationInfo.set_templateType(SP.ListTemplateType.genericList);
this.oList = web.get_lists().add(listCreationInfo);
clientContext.load(oList, 'Title', 'Id');
clientContext.executeQueryAsync(Function.createDelegate(this, this.onListCreateSuccess), 
Function.createDelegate(this, this.onQueryFailed));
}
function onListCreateSuccess(sender, args) {
         alert("List title : " + this.oList.get_title() + "; List ID : "+ this.oList.get_id());
}
         
function onQueryFailed(sender, args) {
         alert('request failed ' + args.get_message() + '\n' + args.get_stackTrace());
}</script>​

2.    To Create A Site

<script type="text/javascript">
var clientContext = null;
var web = null;
ExecuteOrDelayUntilScriptLoaded(Initialize, "sp.js");
function Initialize()
{
clientContext = new SP.ClientContext.get_current();
web = clientContext.get_web();
var webCreateInfo = new SP.WebCreationInformation();
    webCreateInfo.set_description("Description.");
    webCreateInfo.set_language(1033);
    webCreateInfo.set_title("SharePoint and .NET");
    webCreateInfo.set_url("SharePoint");
    webCreateInfo.set_useSamePermissionsAsParentSite(true);
    webCreateInfo.set_webTemplate("BLOG#0");
    this.oNewWebsite = this.web.get_webs().add(webCreateInfo);
    clientContext.load(this.oNewWebsite, 'ServerRelativeUrl', 'Created');
clientContext.executeQueryAsync(Function.createDelegate(this, this.onCreateWebSuccess), 
Function.createDelegate(this, this.onQueryFailed));
}
function onCreateWebSuccess(sender, args) {
         alert("Web site url : " + this.oNewWebsite.get_serverRelativeUrl());
}
         
function onQueryFailed(sender, args) {
         alert('request failed ' + args.get_message() + '\n' + args.get_stackTrace());
}</script>​

3.    To delete a Site

<script type="text/javascript">
var clientContext = null;
var web = null;
ExecuteOrDelayUntilScriptLoaded(Initialize, "sp.js");
function Initialize()
{
clientContext = new SP.ClientContext.get_current();
web = clientContext.get_web();
this.website = web.get_webs().getByTitle('jayakrishnaakkiraju.blogspot.com');
website.deleteObject();
clientContext.executeQueryAsync(Function.createDelegate(this, this.onSiteDeleteSuccess), 
Function.createDelegate(this, this.onQueryFailed));
}
function onSiteDeleteSuccess(sender, args) {
         alert("site deleted");
}
         
function onQueryFailed(sender, args) {
         alert('request failed ' + args.get_message() + '\n' + args.get_stackTrace());
}</script>​

4.    To delete a List

<script type="text/javascript">
var clientContext = null;
var web = null;
ExecuteOrDelayUntilScriptLoaded(Initialize, "sp.js");
function Initialize()
{
clientContext = new SP.ClientContext.get_current();
web = clientContext.get_web();
this.list = web.get_lists().getByTitle('My custom generic list');
list.deleteObject();
clientContext.executeQueryAsync(Function.createDelegate(this, this.onListDeleteSuccess), 
Function.createDelegate(this, this.onQueryFailed));
}
function onListDeleteSuccess(sender, args) {
         alert("list deleted");
}
         
function onQueryFailed(sender, args) {
         alert('request failed ' + args.get_message() + '\n' + args.get_stackTrace());
}</script>​

5.       To  delete a ListItem

<script type="text/javascript">
var clientContext = null;
var web = null;
ExecuteOrDelayUntilScriptLoaded(Initialize, "sp.js");
function Initialize()
{
clientContext = new SP.ClientContext.get_current();
web = clientContext.get_web();
this.list = web.get_lists().getByTitle('My custom generic list');
this.oListItem = list.getItemById(1);
oListItem.deleteObject();
clientContext.executeQueryAsync(Function.createDelegate(this, this.onListItemDeleteSuccess), 
Function.createDelegate(this, this.onQueryFailed));
}
function onListItemDeleteSuccess(sender, args) {
         alert("list item deleted");
}
         
function onQueryFailed(sender, args) {
         alert('request failed ' + args.get_message() + '\n' + args.get_stackTrace());
}</script>​

6.       To Load List Data

<script type="text/javascript">
var clientContext = null;
var web = null;
ExecuteOrDelayUntilScriptLoaded(Initialize, "sp.js");
function Initialize()
{
clientContext = new SP.ClientContext.get_current();
web = clientContext.get_web();
this.list = web.get_lists().getByTitle("Images");
clientContext.load(list, 'Title', 'Id');
clientContext.executeQueryAsync(Function.createDelegate(this, this.onListLoadSuccess), 
Function.createDelegate(this, this.onQueryFailed));
}
function onListLoadSuccess(sender, args) {
         alert("List title : " + this.list.get_title() + "; List ID : "+ this.list.get_id());
}
         
function onQueryFailed(sender, args) {
         alert('request failed ' + args.get_message() + '\n' + args.get_stackTrace());
}</script>​

7.       To load List Items Data

<script type="text/javascript">
var clientContext = null;
var web = null;
ExecuteOrDelayUntilScriptLoaded(Initialize, "sp.js");
function Initialize()
{
clientContext = new SP.ClientContext.get_current();
web = clientContext.get_web();
var list = web.get_lists().getByTitle("Pages");
var camlQuery = new SP.CamlQuery();
var q = '<View><RowLimit>5</RowLimit></View>';
camlQuery.set_viewXml(q);
this.listItems = list.getItems(camlQuery);
clientContext.load(listItems, 'Include(DisplayName,Id)');
clientContext.executeQueryAsync(Function.createDelegate(this, this.onListItemsLoadSuccess), 
Function.createDelegate(this, this.onQueryFailed));
}
function onListItemsLoadSuccess(sender, args) {
         var listEnumerator = this.listItems.getEnumerator();
         //iterate though all of the items
         while (listEnumerator.moveNext()) {
             var item = listEnumerator.get_current();                
             var title = item.get_displayName();
             var id = item.get_id();
            alert("List title : " + title + "; List ID : "+ id);
        }
}
         
function onQueryFailed(sender, args) {
         alert('request failed ' + args.get_message() + '\n' + args.get_stackTrace());
}</script>​

8.       To load Site data

<script type="text/javascript">
var clientContext = null;
var web = null;
ExecuteOrDelayUntilScriptLoaded(Initialize, "sp.js");
function Initialize()
{
clientContext = new SP.ClientContext.get_current();
web = clientContext.get_web();
clientContext.load(web, 'Title');
clientContext.executeQueryAsync(Function.createDelegate(this, this.onSiteLoadSuccess), Function.createDelegate(this, this.onQueryFailed));
}
function onSiteLoadSuccess(sender, args) {
         alert("site title : " + web.get_title());
}
         
function onQueryFailed(sender, args) {
         alert('request failed ' + args.get_message() + '\n' + args.get_stackTrace());
}</script>​

9.       To update List

<script type="text/javascript">
var clientContext = null;
var web = null;
ExecuteOrDelayUntilScriptLoaded(Initialize, "sp.js");
function Initialize()
{
clientContext = new SP.ClientContext.get_current();
web = clientContext.get_web();
this.list = web.get_lists().getByTitle('My custom generic list');
list.set_description('My custom generic list description');
list.update();
clientContext.load(list, 'Description');
clientContext.executeQueryAsync(Function.createDelegate(this, this.onSiteLoadSuccess), Function.createDelegate(this, this.onQueryFailed));
}
function onSiteLoadSuccess(sender, args) {
         alert("list description : " + this.list.get_description());
}
         
function onQueryFailed(sender, args) {
         alert('request failed ' + args.get_message() + '\n' + args.get_stackTrace());
}</script>​



10.   To update ListItem

<script type="text/javascript">
var clientContext = null;
var web = null;
ExecuteOrDelayUntilScriptLoaded(Initialize, "sp.js");
function Initialize()
{
clientContext = new SP.ClientContext.get_current();
web = clientContext.get_web();
this.list = web.get_lists().getByTitle('My custom generic list');
this.oListItem = list.getItemById(1);
oListItem.set_item('Title', 'JK Updated');
oListItem.update();
clientContext.executeQueryAsync(Function.createDelegate(this, this.onUpdateListItemSuccess), Function.createDelegate(this, this.onQueryFailed));
}
function onUpdateListItemSuccess(sender, args) {
         alert("list item updated");
}
         
function onQueryFailed(sender, args) {
         alert('request failed ' + args.get_message() + '\n' + args.get_stackTrace());
}</script>​

Tuesday, November 22, 2011

SharePoint 2010 : Client OM


SharePoint 2010: Client OM


Introduction



SharePoint 2007 allows using its Server OM to run against server running SharePoint and to communicate from the client side allows using the Web Services. SharePoint Client OM designed to run from the Client OS where SharePoint is not installed.
SharePoint 2010 introduces three new client APIs which can be used to interact with SharePoint sites. The three APIs are targeted for three different types of clients:

1. NET Managed Client OM (for the applications like console, window, web etc ) which are not running inside SharePoint Context.
2. Silverlight Client OM. (For the Rich UI applications using the Silverlight)

3. ECMA Script (Jscript, JavaScript). This API is only available for applications hosted inside SharePoint (for example, web part deployed in SharePoint site can use this JavaScript API for accessing SharePoint from browser using JavaScript). Cross Page Scripting is not possible with the ECMA Script.
The new ECMAScript (JavaScript, Jscript), .NET managed, and Silverlight client object models each provide a subset of the server object model that is defined in Microsoft.SharePoint.dll, including objects that correspond to major objects at the site-collection level or lower in the SharePoint Foundation hierarchy.

The client object models are provided through proxy .js and managed .dll files, respectively, which can be referenced in custom applications like other object models. The object models are implemented as a Windows Communication Foundation (WCF) service (.../_vti_bin/client.svc), but uses Web bindings to implement efficient request batching. All operations are inherently asynchronous, and commands are serialized into XML and sent to the server in a single HTTP request. For every command, a corresponding server object model call is made, and the server returns a response to the client in compacted JavaScript Object Notation (or JSON) format, which the proxy parses and associates with appropriate objects.

SharePoint 2007 had no Client Object model available.

 The main reason is that Microsoft has found lot of requests from SharePoint users to introduce more and more web services to get data out of SharePoint in the last couple of years. But introducing web services will not fix the issues, as Microsoft found, because then the request for more functionality in the web services will continue. Even if Microsoft provides a good numbers of web services with SharePoint, customization in web services will be required for different clients and this will make the out of the box web services unusable.

 The following table shows the equivalent objects in Client and SharePoint Object Model.

The Site class represents site collections, and the Web class represents sites.
Sample Code :
ClientContext clientContext = new ClientContext (siteUrl);
Site siteCollection = clientContext.Site;
Web site = clientContext.Web;

How Client OM is developed and work under the hood?

It’s interesting how SharePoint team has developed the same set of classes for three different sets of applications (Managed, Silverlight and ECMAScript). There is same class ListItem for three different set of applications

Client Type
Assembly/File
Managed Client
Microsoft.SharePoint.Client
Silverlight
Microsoft.SharePoint.Client.Silverlight
ECMAScript
SP.js

To ensure the same class object (say ListItem) behaves similarly in three different types of applications SharePoint team followed the steps described below:

a) SharePoint team first set attributes to the SharePoint classes and methods and properties that need to be exposed in Client OM.

b) Then a code generator is run against the SharePoint object model to generate client OM automatically.

This automated code generation has ensured maximum compatibility between these three sets of APIs.

How the Client-Side Object Model Works

An application that uses SharePoint content interacts with the API in several ways—call methods and get the return values, pass a Collaborative Application Markup Language (CAML) query and get the results, and set or get properties. After you use the API to perform a specific task the SharePoint Foundation 2010 managed client object model bundles up these uses of the API into XML and sends it to the server that runs SharePoint Foundation. The server receives this request, and makes appropriate calls into the object model on the server, collects the responses, forms them into JavaScript Object Notation (JSON), and sends that JSON back to the SharePoint Foundation 2010 managed client object model. The client object model parses the JSON and presents the results to the application as .NET Framework objects (or JavaScript objects for JavaScript). The following diagram shows these interactions.


SharePoint 2010 Namespaces:


Microsoft.SharePoint.Client is the core namespace used for the .NET managed and Silverlight object models, and SP is the core namespace for the JavaScript object model.

In addition to the core namespace, SharePoint 2010 provides the following namespaces.

.NET Managed and SilverlightJavaScript
Microsoft.SharePoint.Client.Application
N/A
N/A
N/A
N/A
N/A
N/A
N/A

The following table shows the equivalent objects that the new APIs provide for common SharePoint 2010 server objects.

Server.NET Managed and SilverlightJavaScript
Microsoft.SharePoint.SPContext
Microsoft.SharePoint.Client.ClientContext
SP.ClientContext
Microsoft.SharePoint.SPSite
Microsoft.SharePoint.Client.Site
SP.Site
Microsoft.SharePoint.SPWeb
Microsoft.SharePoint.Client.Web
SP.Web
Microsoft.SharePoint.SPList
Microsoft.SharePoint.Client.List
SP.List
Microsoft.SharePoint.SPListItem
Microsoft.SharePoint.Client.ListItem
SP.ListItem
Microsoft.SharePoint.SPField (including major derived classes)
Microsoft.SharePoint.Client.Field
SP.Field
Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager
Microsoft.SharePoint.Client.WebParts.LimitedWebPartManager
SP.WebParts.LimitedWebPartManager

The new client APIs do not provide administration objects or objects that are higher than site collection: SPSite class in the server object model.