Skip Ribbon Commands
Skip to main content

Tanmay Shahane | zevenseas | SharePoint Blog

:

Tanmay Shahane | zevenseas | SharePoint Blog > Posts > Overcoming the sandbox limitation…Client object model (ECMA script) volunteers adding web parts on page
August 13
Overcoming the sandbox limitation…Client object model (ECMA script) volunteers adding web parts on page

Hello kind readers…

A good friend of mine, Vardhaman wrote a post about adding web part through COM some time back, here. I would like to take it a step further on how it be a wonderful thing in making your sandboxed solutions more fun and limit free :). To understand what I am talking about, let's look at a scenario,
 
Scenario:
You have a sandbox solution and have a hierarchy of sites created. Every site has a landing page, mainly default.aspx and you have a particular web part as part of each site landing page. Now you want to automate this task.
 
Approach:
Normally a direct approach would be to write a feature .. Some server code to loop through all webs and add the web part on the page using the SPLimitedWebPartManager class.. BUT.. This class in not available to the Sandboxed solution. That’s a bummer .. Enters Client Object Model we dearly call COM. Now using the COM you can add a web part to a page even in a sandbox solution and is pretty cool!! Lets see how we can use the magical COM to get what we want…  step by step ...
 
$(document).ready(function () {
        ExecuteOrDelayUntilScriptLoaded(addWebpartForMe, "sp.js"); //Self explanatory
});
 
function addWebpartForMe() {
 
  // you can get the client context using the server relative URL of the current site, you can use the
//SharePoint js variable to read from the current page or can pass it dynamically to your function
//it works with get_current() as well, no need to pass absolute URL to get the context
    var clientContext = new SP.ClientContext(_spPageContextInfo.siteServerRelativeUrl );
    var web = clientContext.get_web();
   //to get the page give the server relative URL of the page which again you can hard code or get using get listems
   // via the COM only
    var oFile = web.getFileByServerRelativeUrl(_spPageContextInfo.siteServerRelativeUrl +'/Pages/default.aspx');
   
   //Once you have the file, using the file you get the limited web part manage class giving the scope of webpart,  //shared brings all data that’s shared across users. (you can use scope user to get personalization related stuff)
    var limitedWebPartManager = oFile.getLimitedWebPartManager(SP.WebParts.PersonalizationScope.shared);
 
//The complete webpart XML, now this can be done in number of ways, you can either hard code it or if you want //a dynamic approach for this, just use the COM to get the Catalogs gallery and read from the webpart file you
//want to and use in the code for adding it to page
    var webPartXml = '<webParts>' +
  ' <webPart xmlns=\"http://schemas.microsoft.com/WebPart/v3\">' +
     ….
    '</webPart>' +
  '</webParts>';
 
   //Using the web part manager you import the web part XML on the page
    var oWebPartDefinition = limitedWebPartManager.importWebPart(webPartXml);
  //Once the xml is loaded on the page you get reference to the web part based on the imported definition
    var oWebPart = oWebPartDefinition.get_webPart();
 //Get all the child webs of the current web
    this.allWebs = web.get_webs();
 //store the xml in reference variable for this call
    this.webpartXml = webPartXml;
//Now when you have the reference to the web part loaded, add it to the page with specified zone id and index of web part.
    limitedWebPartManager.addWebPart(oWebPart, 'LeftColumn', 1);
//load the web webpart instance for the context, also for all child webs
    clientContext.load(oWebPart);
    clientContext.load(allWebs);
 
    clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceededWebPart), Function.createDelegate(this, this.onQueryFailedWebPart)); 
}
//when you webpart is added the success method is called
function onQuerySucceededWebPart() {
 
    var Enumerator = this.allWebs.getEnumerator(); // to loop in all child webs
 
 //get the webpart xml coming from parent function call
    var xmlWp = this.webPartXml;
//Loop webs
    while (Enumerator.moveNext()) {
        var subWeb = Enumerator.get_current(); //get the reference to specific web item
        //Now again you need to create a client context which is using the server relative URL of the child web, you
       //need to create a fresh context of the site to which you are doing the web part operation on else it wont work
        var ctx = new SP.ClientContext(subWeb.get_serverRelativeUrl());
      //so though you have reference to the child web in subWeb variable you still need to open the context and get
      //the web again, so baiscally you need the client context object created from the URL of the site that you want
     //to do operation to, to make things work
        var childWeb = ctx.get_web();
     //Now you have the child web object using which you get the aspx page
        var oFile = childWeb.getFileByServerRelativeUrl(subWeb.get_serverRelativeUrl() + '/Pages/default.aspx');
      //same as before you get the webpart manager, import web part and add it
        var limitedWebPartManager = oFile.getLimitedWebPartManager(SP.WebParts.PersonalizationScope.shared);
        var oWebPartDefinition = limitedWebPartManager.importWebPart(xmlWp);
        var nWebPart = oWebPartDefinition.get_webPart();
        limitedWebPartManager.addWebPart(nWebPart, 'LeftColumn', 1);
     // load and execute the query for this web part
        ctx.load(nWebPart);
      
        ctx.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceededSubWebPart), Function.createDelegate(this, this.onQueryFailedWebPart)); 
    }
 
//This will happen for all the sub webs calling client context specific to that web and would add web parts to all the sub webs for you. 
alert('Web parts added to all');
}
 
function onQueryFailedWebPart(sender, args) {
    alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
function onQuerySucceededSubWebPart(sender, args) {
    alert('Added successfully to all sub sites'); //will be called recursively, this is just for demo don't have alert statement here 
}
 
This a veryyyyy basic example on how you can use the ECMA script to over come limitations in the sandboxed solution, of course you can modify the above to make it more complex and powerful or simple or whatever you like… there are SO MANY ways this could help in a sandbox solution…. its all up to you, possibilities are countless.
 
Point to Note: 
A point to note here is that with the COM the looping through webs is not possible beyond one level, so you get only the immediate children of any web, I did talk about this limitation in my last post as well, so then could there be a way around it.. YES there can be… there can be many ways but I will just quickly talk about one that I can think of… 
 
What you can do is on the parent site add a content query webpart and set it to bring all items from page content type, this will bring all the default.aspx from you site collection, now with the item you get the link url of the page and also site relative url can be deduced from it.. There you go you have the whole site collection webs url which you can use to open the context and do add remove to web parts.. A little combination of Jquery CQWP and COM.. Recipe to great solutions.
 
Now this makes a very flexible and NO-CODE solution which means you don’t even have to touch the server code and deploy it you can directly upload it to the doc library and add a reference to master page and you are done, that means everything can be done client side only and you can do modifications or anything any day without having to boot up your heavy VM :)
 
Hope this helps.
                    

                   -"T"

Comments

Does not work for Custom web parts

IS not working for custom web parts and sandbox webparts
 on 5/4/2012 3:08 AM

Christian Louboutin Boots On Sale


My partner and i take a nap, please take a straw head wear, along with buckles face,desire grass inside Hong Kong. I came to be to depart you, Once you enter in the path involving crimson dirt,   Christian Louboutin Boots On Sale   the actual wind chime because i tend not to invest the particular wedding ring.While this individual came up, This individual shook his / her head in a very vast natrual enviroment road, and smiled. I will be myself, you did not maintain myself in a aspiration.
http://www.zamshoes.com/ Christian Louboutin Boots On Sale
http://www.zamshoes.com/categories-pumps.html black christian louboutin pumps sale
http://www.zamshoes.com/categories-boots.html christian louboutin boots on sale
http://www.zamshoes.com/categories-for-men.html  christian louboutin men
http://www.zamshoes.com/categories-sneakers.html christian louboutin sneakers sale
http://www.zamshoes.com/categories-flats.html christian louboutin flats cheap
http://www.zamshoes.com/miu-miu-shoes.html miu miu shoes outlet
http://www.zamshoes.com/jimmy-choo.html jimmy choo shoes on sale
http://www.zamshoes.com/manolo-blahnik.html manolo blahnik something blue
 on 10/24/2012 5:59 PM

Add Comment

Title


Body *


Attachments

 

 Related Posts

 
 

 Statistics

 
Views: 3216
Comments: 2
Tags:Client Object Model
Published:676 Days Ago