Skip Ribbon Commands
Skip to main content
Home
April 12
Loading JS files in a SharePoint Online Environment

For any of you that don't follow Wouter van Vugt, he had a great session at the Dutch SPC a while ago about loading JavaScript files in an On Premise SharePoint 2010 Environment. Very cool solutions were discussed however none of them are applicable when having a SharePoint Online environment. It's true the possibilities are very limited but still some cool techniques can be used to keep amount of scripts loading down to an acceptable level.

ScriptLink

The easiest way to add script to your page from a feature is to use the ScriptLink. By default this control is on every SharePoint Masterpage and by using a <CustomAction> a script can easily be added to the page without the need of changing the MasterPage or Page Layout. The Custom Action to do this can look like this:

<CustomActionLocation="ScriptLink" ScriptSrc="~SiteCollection/Scripts/jquery-1.6.min.js" Sequence="105" />

This example loads the jQuery library to the page. This approach is a nice one to load Shared Libraries (like jQuery) on every page. Even on the system pages based on the default v4.master the jQuery library is loaded because of this Custom Action. That is an important consideration whether to use this in your solution or not.

ScriptTag

Using the HTML tag <script/> is a good way to always load a script. Actually the SharePoint ScriptLink also renders a <script/> tag eventually. However for this approach the MasterPage needs to be updated and if you want your script to load on system pages (Forms, Views etc.) you also have to edit the default MasterPage which is not a best practice.

Script On Demand

A good way of loading scripts is only load them when you are actually gonna use them. The SharePoint Client OM accommodate you with the SP.SOD (Script On Demand) class. With a few steps we implement this:

1) Deploy your script using a Module (i.e. to the folder '/Scripts/MyFile.js')

2) In the MyFile.js file at the bottom add "SP.SOD.notifyScriptLoaded('MyFile.js');"

3) On the page where the call to this script is made add "SP.SOD.registerSod('MyFile.js', '/Scripts/MyFile.js');"

4) When the script is needed make a function call like this "SP.SOD.execute(MyFunc, 'MyFile.js');"

Now the SP.SOD.execute will make sure the Function is execute after the MyFile.js is loaded. At PageLoad this script is not loaded this way.

Script Storage

Because SharePoint Online is bound to SiteCollection level and because we are not able to write to the _layouts folder on the server, the storage of all Script files is important to think about. The logical place after _layouts would be in the Style Library, but there the possibility exist that user are going to mess up your code. In a SharePoint Online environment we can never cover this entirely but a more secure location to store your script would be just in a Folder of the RootWeb. Then people can only touch your code using SP Designer which is more difficult to most users.

Minify your scripts

In order to keep the JS files to a minimum, don't create too much different JS files and remember to Minify them. The nice VS add-on from Mavention is a very powerful tool to get this done. http://visualstudiogallery.msdn.microsoft.com/04ef7cbc-23dd-49f8-b4a2-ab87885ad065

March 28
Get User Information from Client OM (JS)

When I was exploring the possibilities to read from a User Profile in a SharePoint Online environment I realized there are lots of properties that are being synced back to the UserInfoList, but only when they are filled in the User Profile.

User Info List

We know by now it's impossible from a Sandboxed Solution (or Client Side OM Solution) to access a Users Profile directly as you would in a On-Premise environment. Our scope is the SiteCollection that runs our custom code. In that scope there is one important resource we can use to get information about a User, the UserInfoList. The list contains some Properties that are populated by the SharePoint Profile. So somehow this is synced.

Synced Properties

The synchronization process is done (On-Premise) by a TimerJob called: "User Profile Service Application - User Profile to SharePoint Full Synchronization". This TimerJob normally runs "Hourly". I didn't test this out but my guess is that this will be the case with SharePoint Online too. The important part being that there is a delay in this procedure. That being said, which properties of the User Profile are being synced by this TimerJob?

Property StaticName (Client OM) Returns
Account name Name domain\ierselca or claim
User name UserName ierselca
Name (DisplayName) Title Cas van Iersel
First name FirstName Cas
Last name LastName van Iersel
Title JobTitle SP Consultant
Email EMail cas@rapidcircle.com
Work phone WorkPhone 0123456789
Mobile phone MobilePhone 0123456789
Picture Picture http://linktoimage *
Department Department R&D
About me Notes Inner HTML of About field as a string
Web site WebSite http://mywebsite.com *
SIP SipAddress sip format string
Office Office Rapid Circle
Ask me about SPSResponsibility SharePoint, C#, ASP
If User Is Site Admin IsSiteAdmin true | false
* You’ll need to do .get_url() on the return object

This is an example on how to get the information based on the UserID in the Context of the current web (You can obtain this from the SPUser object or use javascript to get from a people link “person.aspx?ID={UserID}”:

    //Get the Context, Web and SiteUserInfoList for User Info
    var clientContext = SP.ClientContext.get_current();
    var web = clientContext.get_web();
    var collListItem = web.get_siteUserInfoList().getItemById(userID);

        //Load the objects async
    clientContext.load(collListItem);
    clientContext.executeQueryAsync(
    Function.createDelegate(this, function(){
          //Read all properties from the Item
                 var userName = collListItem.get_item('Name');
                 var website = collListItem.get_item('WebSite').get_url();
     }), Function.createDelegate(this, function(){
         //On Fail
    }));

Note: When the field is empty in your profile the get_item() Method will return null on the property.

Profile Picture

On property that can be slightly inconvenient is the Profile Picture. The URL is stored in the UserInfoList so that will be returned perfectly. But with SharePoint Online the Picture is most definitely stored in the MySite Host webapp. This means the user is challenged for credentials when this URL is used in an <img /> tag for instance.

Summary

There is a lot of User Information we can work with using the Client OM. It’s very easy to obtain the information using Javascript and to do cool stuff with it. Just keep in mind that the syncing process can take some time and no custom properties are being synced.

March 07
Inconvenient (Sandboxed) Custom ListDefinitions

Building custom SharePoint Online solution a List Definition is likely to be a SPI you would like to use. Sandboxed Solution look like a good way of deploying these definitions to your SharePoint Online environment, but are they?

Read the full post on http://www.casvaniersel.com/?p=39

December 19
Inconvenient Recurrence Data from a SharePoint Calendar using Client OM (JS)

The CAML to get SharePoint items from lists has a nice feature when it comes to Calendar data. Using the <DateRangesOverlap/> it is possible to check if a given date is within a range of dates and when passing the ExpandRecurrence property it even takes the Recurrence Data into account. Using Sandboxed Solutions to do so we can easily set this property SPQuery.ExpandRecurrence = true; However when it comes to the JavaScript Client OM we cannot use this property.

WebServices

The only way to query SharePoint for Recurrence Data using Client OM is by using the GetListItems Method from the List WebService (/_vti_bin/lists.asmx). The XML passed into the WebService can handle QueryOptions and we can use this to specify if ExpandRecurrence should be true. The Soap XML looks like this:

<soapenv:Envelopexmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'>
  <soapenv:Body>
    <GetListItemsxmlns='http://schemas.microsoft.com/sharepoint/soap/'>
      <listName>[MyListName]</listName>
      <query>
        <Query>
          <Where>
            <DateRangesOverlap>
              <FieldRefName='EventDate' />
              <FieldRefName='EndDate' />
              <FieldRefName='RecurrenceID' />
              <ValueType='DateTime'>
                <Today />
              </Value>
            </DateRangesOverlap>
          </Where>
        </Query>
      </query>
      <queryOptions>
        <QueryOptions>
          <ExpandRecurrence>TRUE</ExpandRecurrence>
          <CalendarDate>
            <Today />
          </CalendarDate>
          <ViewAttributesScope='RecursiveAll' />
        </QueryOptions>
      </queryOptions>
      <viewFields>
        <ViewFields>
          <FieldRefName='EventDate' />
          <FieldRefName='EndDate' />
          <FieldRefName='fAllDayEvent' />
          <FieldRefName='fRecurrence' />
          <FieldRefName='Title' />
        </ViewFields>
      </viewFields>
      <RowLimit>10</RowLimit>
    </GetListItems>
  </soapenv:Body>
</soapenv:Envelope>

This example checks if there are events overlapping with <Today />. I found that it's best to check with tags like <Today/>. <Week/>, <Month/> and <Year/> instead of using UTC Dates. Notice the <queryOptions/> wrapper passing the Options. Building regular CAML XML using the inner <QueryOptions/> tag didn't work unfortunately. Both <ExpandRecurrence/> as <CalendarDate/> are mandatory in order for this query to work.

Tip: When using Client OM to process SharePoint data requests it's best practice to specify as much properties as possible. Specifying <ViewFields/> will only return these fields instead of all possible fields that come with an Item. If you know the maximum amount of results specifying <RowLimit/> also helps to improve the performance on your Query.

December 16
Handling DateTime in Office 365 Sandboxed Solutions

When developing custom solutions on the SharePoint platform we don't really think about using DateTime objects anymore. We just build solutions using server-side DateTime.Now or DateTime.Today to check Date and Time and to check that with the values we get back from SharePoint. Because we have full control over our On-Premise environment we can be sure that the Server Date and Time is correct. However moving this principal to the Cloud we loose that bit of control. We have to make sure again we get the right Date and Time from the server to do accurate checks.

Timezone of a Office 365 Server

As soon as I was testing a solution using a DateTime.Now object to get Calendar Items I came across some strange behavior when testing before 09:00 (GMT +1). I came across this article http://onlinehelp.microsoft.com/en-us/office365-enterprises/hh531509.aspx to get all Applications in the right TimeZone. It seemed that the Office 365 servers were all set to the TimeZone GMT -8 (Which is the Redmond TimeZone). So there was a 9 hour difference (I'm in Amsterdam TimeZone GMT +1).

Regional settings

Because programming it like DateTime.Now.AddHours(9); didn't seem the right thing to do, I found a good solution to get the right DateTime.Now based on our local TimeZone. First step is to set the Regional Settings for your Office 365 SharePoint Site Collection (https://MySharePointSite/_layouts/regionalsetng.aspx) to the correct TimeZone. With this Regional Settings we can use the SPRegionalSettings object to calculated the local time at the moment of need using the following code.

        SPRegionalSettings reg = SPContext.Current.Site.RootWeb.RegionalSettings;
        SPTimeZone tz = reg.TimeZone;
        DateTime utc = DateTime.Now.ToUniversalTime();
        DateTime utcLocal = tz.UTCToLocalTime(utc);

The utc represents DateTime.Now at GMT. With the UTCToLocalTime() method we will get the current DateTime based on our TimeZone. Now we can use utcLocal instead of DateTime.Now to get the accurate Date and Time when doing Server Side (Sandboxed) calculation with DateTime. The picture illustrates the DateTime.Now, the TimeZone ID set for the Current Site, GMT time and our LocalTime.

BlogPost-DateTimeO365

September 26
Create a sub site based on a custom (Sandboxed) Web Template using Powershell

One quick tip when using Powershell to create a SharePoint sitestructure combined with custom Web Templates (In my case Sandboxed). The correct syntax for creating Webs based on your custom (sandboxed) Web Template is:

$site = Get-SPSite http://myserver/sites/mysite
$web = New-SPWeb http://myserver/sites/mysite/subsite 
$web.ApplyWebTemplate("{FeatureGUID}#MyTemplate")

In this case you can not use the –template parameter on the New-SPWeb method. Hopefully this post will save u the wondering why your PS script is failing.

If you are trying to figure out what the correct name is for the WebTemplate, you can also use this PS command to check which Templates are available in your current Site.

$site = Get-SPSite http://myserver/sites/mysite
$site.GetWebTemplates(lcid)

lcid off course being the language ID.

August 18
Deploying Sandboxed Solutions

Lately I’ve been working on some Sandboxed solution for Office 365. We all know that they differ on lots of points from Farm Solutions. On the coding end by now we know all the limitations and best practices but how about deployment of these solutions. Some experiences from my end in this post.

Dependencies

Maybe a no-brainer but dependencies between sandboxed solutions can be killing and may result in errors on Solution Activation level. For instance Content Type references in a List Definition with an instance attached to it. The Content Type should be in the same solution as the definition. If there are more Feature in one Solution, make sure to use Activation Dependencies. Again make sure that two different features in two different solutions don’t have any direct dependencies with each other.

Upgrading Shared Resources

When Branding is needed in a Sandboxed solution like MasterPage, PageLayouts, CSS, Images etc. we can use the SharePoint Module SPI for provisioning. However when 1 of these resources is checked out by someone else then the user who deploys and activates the Feature which holds that module, SharePoint will give a Runtime error on Activating the feature. In this case it doesn’t matter if the person deploying the Solution is a sitecollection admin. The settings on the the library for Mandatory Check Out don’t help much either. Even when this is turned off and the file is still checked out, the error occurs.

So it’s important to make SURE that all the files that need to be upgraded are Checked In! And off course this doesn’t apply only to branding files but ALL files that are being provisioned by a Module SPI.

August 15
Customize default links to List Forms

So we all know that for lots of reasons we want to modify OOB stuff in SharePoint. However when you’re developing for SharePoint Online not everything can simply be customized or extended. For instance lots of OOB links in SharePoint point to _layouts/ListForm.aspx (with some QueryString parameters). We can easily get control over these links using a little piece of jQuery and knowledge on how this magical page works. Also when creating WebParts it can be a pain to build relative links to certain List Forms. In this case we can use the ListForm.aspx page as well.

Redirect

When you come across a link to ListForm.aspx, the first thing that we notice is that it’s actually redirecting you to another page, based on the parameters in the QueryString. These are the parameters:

  • PageType
  • ListId
  • ID

The first one is the most interesting one. In my case I wanted to point to the Items Edit Form. A quick lookup to the PageType enumeration (http://msdn.microsoft.com/EN-US/library/ms454458) learns that I need to pass 6 into the QueryString to get the Items Edit Form.

ListId is the GUID of the list the item is in and ID is the ID for the ListItem.

jQuery interception

So now we know what all of this means we need to modify it. Best ways of loading JavaScript is using the SP.SOD methods from the SharePoint client OM (http://msdn.microsoft.com/en-us/library/ff410742.aspx).

I’ve created a custom js file called my.js and used a CustomAction to load it on the page.

<CustomAction Location="ScriptLink" ScriptSrc="~SiteCollection/Style Library/Scripts/my.js" Sequence="305" />

So my js File is stored in the Style Library in the Scripts folder. The contents of the file looks like this:

function changeEditLink() {
            var elemSize = $("a:contains('Eigenschappen weergeven')").size();
                if (elemSize > 0) {
                $("a:contains('Eigenschappen weergeven')").each(function () {
                    var linkHref = $(this).attr("href");
                    $(this).attr("href", linkHref.replace("PageType=4", "PageType=6"));
                    $(this).html("Bewerken");
                });
            }
}//Notify SharePoint that the custom file has loaded.
SP.SOD.notifyScriptLoadedAndExecuteWaitingJobs("my.js");

So in this function I’m using jQuery to get all the <a> elements that contain the text: “Eigenschappen weergeven” (dutch for “Display properties”). Al I need to do next is a simple string replace to change the PageType parameter.

Now the code on the page to call my method according to the SP.SOD class:

<script type="text/ecmascript" language="ecmascript">ExecuteOrDelayUntilScriptLoaded(changeEditLink, "my.js");</script>

That’s all

So now we use the links to ListForms.aspx and change them to our likings. Also it can be a great tool to build a custom relative URL to a listform from any SharePoint (Sub)Site. The only requirements are the ListId and ItemId.

May 11
Adding Scripts to all pages without writing code

Hello everyone. When I was developing for Office 365 I came across the following challenge. I needed to add some JavaScript functions to each SharePoint Page without writing code or even adjusting the MasterPage. When I start looking into this I found this Blog post from Andrew Connell: http://www.andrewconnell.com/blog/archive/2011/04/11/adding-jquery-to-every-page-in-a-sharepoint.aspx

The only thing you need is a Feature with a CustomAction Element.

<CustomAction
    ScriptSrc="~SiteCollection/Style Library/Scripts/jquery-ui-1.8.12.custom.min.js"
    Location="ScriptLink"
    Sequence="205"/>

ScriptSrc: This is the location of your script file.
Location: The control to render the reference to the script file. Works like a delegate control.
Sequence: When you need to add more scripts you can determine the sequence for loading.

When the Feature is activated the Script is automatically added to the ScriptLink control which is on de MasterPage by default.

April 29
Using SharePoint 2010 Taxonomy Picker out of context

Tagging in SharePoint is great. A while ago I wrote about using the TaxonomyField in Publishing pages but this time I needed the control in an application page with no Content Type attached (of any other form of context). The case is to build a configuration page for creating a new SiteCollection. On this page is a form where a user can put in a name, description and Tags from the Term Store Taxonomy.

WebTaggingControl

When I started digging into the SharePoint Taxonomy controls I found the TaxonomyWebTaggingControl. With this control the same field and tags button is rendered as with the TaxonomyField. Because there is no Site Column or Content Type to which this field is attached, you’ll need to set some properties in the Page Load or Init of the application page to attach the field to the right TermStore and TermSet.

On the aspx Page I used this control:

<Taxonomy:TaxonomyWebTaggingControl id="SiteMetaDataControl" runat="server" />

You also need a reference in the Page to the Taxonomy assembly:

<%@ Register Tagprefix="Taxonomy" Namespace="Microsoft.SharePoint.Taxonomy" Assembly="Microsoft.SharePoint.Taxonomy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

In the OnInit():     

//Create a new Taxonomy Session for binding 
TaxonomySession session = new TaxonomySession(SPContext.Current.Site); 
//Get the first Service TermStore 
TermStore termStore = session.TermStores[0]; 
//Get the TermGroup
Group group = termStore.Groups["YOURGROUP"];
//Get the TermSet for Communities
TermSet taxTerm = group.TermSets["YOURSET"];
SiteMetaDataControl.SspId.Add(termStore.Id);
SiteMetaDataControl.TermSetId.Add(taxTerm.Id);

Now you can use the default Taxonomy Picker in your application page without using publishing features, Content Types or Site Columns.

1 - 10Next
 

 About this blog

 

Welcome to my Zeven Seas Blog! I will be posting cool stuff about SharePoint and Office 365. Feel free to contact me in any way:

T: www.twitter.com/casvaniersel
E: cas.van.iersel@rapidcircle.com 
W: www.casvaniersel.com  

 

 Most Discussed

 
Using SharePoint 2010 Taxonomy Picker out of context 6163
Adding Scripts to all pages without writing code 30
Cross Site Content Aggregation in Office 365 27
Create a sub site based on a custom (Sandboxed) Web Template using Powershell 14
Deploying Sandboxed Solutions 14
Customize default links to List Forms 8
Loading JS files in a SharePoint Online Environment 7
Inconvenient (Sandboxed) Custom ListDefinitions 4
Handling DateTime in Office 365 Sandboxed Solutions 3
Get User Information from Client OM (JS) 1
Inconvenient Recurrence Data from a SharePoint Calendar using Client OM (JS) 1
 

 Most Recent

 
Loading JS files in a SharePoint Online Environment 36 Days Ago
Get User Information from Client OM (JS) 51 Days Ago
Inconvenient (Sandboxed) Custom ListDefinitions 72 Days Ago
Inconvenient Recurrence Data from a SharePoint Calendar using Client OM (JS) 150 Days Ago
Handling DateTime in Office 365 Sandboxed Solutions 154 Days Ago
Create a sub site based on a custom (Sandboxed) Web Template using Powershell 235 Days Ago
Deploying Sandboxed Solutions 274 Days Ago
Customize default links to List Forms 277 Days Ago
Adding Scripts to all pages without writing code 373 Days Ago
Using SharePoint 2010 Taxonomy Picker out of context 385 Days Ago
Cross Site Content Aggregation in Office 365 396 Days Ago
 

 Information

 
Owners
Cas van Iersel
Mark Overdijk
Sachin Zade
Tanmay Shahane
Vardhaman

Views: 88812
Posts: 12
Comments: 6272
 

 Tag Cloud

 
No Items Found