magnify
formats

SharePoint JavaScript: removeByLoginName

Published on May 28, 2013 by in JavaScript

The SharePoint 2013 JavaScript object model includes a few new methods on the UserCollection object that on the surface seems like nice shortcuts, but I’m not convinced of their usefulness (yet – I could change my mind). These methods are:

  • getByLoginName
  • removeByLoginName

I’ve only tested the remove operation, but I’m assuming the get operation operates the same way.

In my testing, the loginName parameter must be the full claim name, for example (i:0#.w|wingtip\mdebakey) instead of the friendlier Wingtip\MDebakey. This severely limits the usefulness of these functions because, unless you are going to hard code the claim token and provider information (the i:0#.w| part) and then tack the user-friendly login name on the end, which is probably a bad idea as it restricts your code from working across different claim types or providers, you’re going to have to get the user object first and get the login name from there (via user.get_loginName), at which point, you might as well just use the remove method on the UserCollection object.

In other words, instead of this:

var user = web.ensureUser(“Wingtip\\MDebakey”);

userCollection.removeByLoginName(user.get_loginName());

 

Just do this:

var user = web.ensureUser("Wingtip\\MDebakey");

userCollection.remove(user);

 
 Share on Facebook Share on Twitter Share on Reddit Share on LinkedIn
No Comments  comments 
formats

SharePoint JavaScript: Use the right reference material!

This is quite obvious when you think about it, but it’s easy to miss nonetheless when you’re searching for something in a hurry and could lead to some problems:

When looking up a method or property for the SharePoint 2013 JavaScript Object Model, make sure you’re looking at the correct version on MSDN!

It’s easy to tell which version you’re in, it’s right at the top:

 

With the server-side OM, a lot of times it didn’t matter which version you referenced because, unless you were looking for something about a new capability, the server-side OM was pretty well established and the core bits didn’t change very much.

This is not so with the JS OM. It is very much still evolving and even core bits are seeing massive changes. One case in point, the Web class had 14 methods in SharePoint 2010 but that count more than doubles in 2013 to 30 methods.

If you’re looking at the wrong page in MSDN, you’re going to miss a lot of interesting capabilities.

For reference: here’s the starting point of the 2013 JavaScript documentation: http://go.dmann.me/SP2013JS

 
 Share on Facebook Share on Twitter Share on Reddit Share on LinkedIn
No Comments  comments 
formats

“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.

 
Tags:
 Share on Facebook Share on Twitter Share on Reddit Share on LinkedIn
No Comments  comments 
formats

SharePoint 2013 Licensing Guide

Just a quick note for myself…Licensing Microsoft SharePoint Server 2013.  Spells out common licensing scenarios.  Also: http://technet.microsoft.com/en-us/library/jj219627.aspx for managing license assignments by user/group.

 
Tags:
 Share on Facebook Share on Twitter Share on Reddit Share on LinkedIn
No Comments  comments 
formats

Anatomy of SPSPhilly 2013

Published on February 25, 2013 by in Conferences

This post is as much for me a year from now when we begin planning the next SPSPhilly event as it is for anyone else.  It is my attempt at capturing what we learned this time around and helping it to make future events better.

We were shooting for 300 attendees and that’s what we got, so it worked pretty well to have folks inform us if they were unable to attend and then we could release a ticket to a person on the waiting list.  Our “no-show” rate dropped to about 15% because of this, though we should still stick with a 20% no-show rate for future events.

Drinks

Here’s what we had:

  • Pepsi: 8 cases
  • Diet Pepsi: 4 cases
  • Sprite: 3 cases
  • Diet Sprite: 1 case
  • Iced Tea: 3 cases
  • Water bottles: ~300
  • Assorted Juice bottles: ~200

We had an extra case of Pepsi left over at the end and not enough water, juice or iced tea.  I would drop the extra case of Pepsi and increase others as follows:

  • Water bottles: an additional 300-400
  • Assorted Juice bottles: an additional 200
  • Iced Tea – an additional 100-150

We had WAY too much coffee as well.  We got all the coffee from Wegmans in the great big “Cambro” containers which kept it hot for 4-6 hours.  We had 150 cups for breakfast and an additional 150 for lunch.  Next time we’d probably be OK with 100 each for lunch and breakfast.  Wegmans provided all of the cups/lids, creamer, sugar, stirrers, etc.

Food

Here’s what we had for breakfast:

  • 250 assorted bagels – was probably 100 too many
  • ~200 assorted breakfast pastries, individually wrapped – was a little too much but not too bad.  Consider reducing if the budget is tight next time

The bagels were from Wegmans and they provided cream cheese as well.  Were well received.

Here’s what we had for lunch:

  • 32 Hoagie trays from Wegmans:
    • 6 each of ham, roast beef, Italian and turkey
    • 4 vegetarian
    • 2 tuna salad
    • 2 chicken salad
  • 300 assorted cookies from BJs
  • 300 assorted chip bags from BJs

The hoagies turned out to be about right, but we might want to drop form 6 to 5 for the first set and increase to 5 vegetarian and 3 each for chicken/tuna salad.  If the budget allows it, maybe just increase the latter 3 and leave the first 4 at 6 trays each.  We asked Wegmans to keep each tray with just one type of hoagie on it to make it easier to restock as types got eaten.

 

All Wegmans orders were called in about 2 weeks ahead of time and picked up in the morning – 7 AM for breakfast, 10 AM for lunch.  Those times worked pretty well though getting to Wegmans at 6:35 was a waste as the order was ready right at 7.

Sundries

There were a handful of other things purchased from BJs as well:

  • 600 large plates – could probably reduce to 400
  • 200 small plates – about right
  • 1000 napkins – could probably reduce to 500 or 600
  • 500 each forks, knives, spoons – way too much.  Needed less than 100 each
  • 30 table covers – about right – make sure to get the type with plastic backing and paper on top to absorb spills and protect the tabletops
  • 75 large trash bags – too many as the cleaning service provided their own.  Should probably reduce to 24 just to make sure we had some on hand
  • 6 rolls of paper towels – probably too many but need some, maybe 4 rolls would suffice.  Was nice to have the extra during the “great cooler flood”
  • Trash receptacles – ordered 10 medium (18 x 18) trash boxes with lids online about 3 weeks before the event from http://www.keeptidy.com/.  Was a little pricy but well worth it.  Ended up throwing them out at the end of the day which was not the original plan.  Next time make sure to keep the shipping box so we can breakdown the trash boxes and save them for future events.

We ordered 21 tables and 90 chairs from Taylor Rental in Malvern which worked out well.  They dropped everything off on Friday afternoon and picked it up at 5:30 on Saturday, though we had to pay a little extra for the Saturday pickup.

 

Logistics

For future reference, Sam’s Club allows you to order online for everything we need (BJ’s doesn’t do groceries online?) and pickup your order which would be a HUGE timesaver.  You can also save your order to start from next time.

The layout of the MTC and Malvern office can be a little confusing when there is a large crowd of people who have never been there before.  A map would be helpful to attendees.

 

Speaker Dinner

Having the speaker dinner in the back room of the Twenty9 Restaurant worked out great.

 

SharePint

The SharePint was in a cordoned off area of the Fox & Hound in King of Prussia which seemed to work out pretty well.  We should include directions on the attendee information/agenda.  We had pushed back to a 6:30 start which was a mistake.  6 PM start would have been fine.

At-Event Registration

This seems to be the hardest thing to get right.  We moved the tables up to the front of the building lobby for the morning to try to catch people as they came in but it was a little crowded.  I think part of that was because there were already a bunch of people in the lobby before registration opened so we started with a line as soon as registration opened.  Other things to consider:

  • Don’t have sponsors register – send someone around to their tables with their nametags and such
  • Make sure the signs are visible above the tables so people in line can see that there are really 3 distinct lines – A-L, M-Z and Speakers.  We ended up with one slow moving line because people couldn’t see that there were 3 distinct stations at which to register.
  • Don’t put speaker gifts and SharePint drink tickets in an envelope to be picked up at registration.  Once again, lots of speakers missed that there was a separate line for speaker registration and so ended up with hand-written nametags and not getting their goodies.  We ended up throwing out about $200 in speaker gifts by mistake because they were never picked up and got mixed in with regular attendee nametags which were thrown out.
  • We moved registration back inside the MTC at about 10 AM and I don’t think a lot of folks found it after that.  We should find a good central location for it and leave it there all day.

Online Registration/Sign Up

Wow.  This was not expected.  We filled all 300 spots in less than 5 hours and kicked over into the waiting list, which we closed at 130.  Next year:

  • Have a distinct Event Brite event for sponsor people who will NOT be attending sessions to keep them from inflating the number of attendees we can have in-session (which seems to be the limiting factor).  If the sponsor folks are going to be coming and going throughout the day or mostly hanging out at their table, then they only need to be counted for food – not as regular attendees
  • Have a distinct Event Brite event for speakers as well.  They count for sessions, food AND general attendee space but they are guaranteed to show so there won’t be any no-shows from this crowd
  • Publicize the information about registration opening up well in advance.  We had some complaints about not knowing the event had opened up registration until after it was sold out.
  • Drop the “Booster” ticket.  We don’t need the money and it seemed to confuse some people into thinking this was a paid event
  • If we stay at the MTC, we can probably go up to 300 regular attendees and 50 speakers plus 3-4 people per sponsor.  We were at about 250 regular attendees and 50 speakers this year
  • Having people notify us ahead of time if they could not attend so we could release tickets from the waiting list worked well.

Sponsors

We had 13 sponsors who got tables (2 Platinum, 3 Gold, 8 Silver) which was OK.  It got us plenty of money to run the event but I think each sponsor still felt like they were getting a good value for their money.  I thought having the sponsor tables set up in the lobby of the building worked out pretty well but it might have been a little crowded.  We need to make sure that the table layout is conducive to getting traffic to each sponsor.

We had 2 swag-only sponsors and one social sponsor.  Giveaways seemed light this year.

Sponsors need to be told ahead of time that they will not have power at their tables.

Non of the sponsors used their “Showcase” rooms, so probably drop those.

 

Food Service

Next year, don’t use the counter at the MTC for the lunch service.  Instead, place 2 rows of tables each perpendicular to it and about 5-7 feet away to allow for faster service.  Place the coolers at the counter so they’re accessible to all lines.

Using the regular MTC counter for breakfast and afternoon snack was fine, augmenting with tables as necessary.

 

 

Miscellaneous

  • We need to stop using the SharePointSaturday.org site for anything other than a pointer to the SPSPhilly.org site.  It is hard to use and confusing to attendees to have some information posted on one site and the rest elsewhere.  We also did a lousy job of keeping it updated.
  • Agenda should be posted a week ahead of time
  • Running the slides on the TVs didn’t work out at all.  Next year look into a projector somewhere in the MTC lobby.
  • Having 5 helpers worked out great – they could swing both registration and food service as needed.  They also picked up the food and more ice & water when we ran out.  They were available from 7:15 until 2:30, though 2 stuck around until about 4, which helped.
  • Pretzels were delivered at about 2 PM which worked out pretty well.  We ordered 300 soft pretzels from the Philly Pretzel Factory which was a little much.  We could have gotten by with 200-250

That’s all I can think of for now, though I’ll likely tack on more as I think of things.  If you were an attendee, speaker or sponsor and have any feedback that would help us make next year’s event better, I’d love to hear it so please add your comments below.

 
 Share on Facebook Share on Twitter Share on Reddit Share on LinkedIn
1 Comment  comments 
formats

Typescript Webinar–Part 1

I just wrapped up my latest webinar on the Critical Path Training free webinar series – this time on Typescript.   It was pretty well attended – about 60 people if I saw the attendee counter properly.  Smile  I think the session went OK – it started out a little slow but then picked up and as usual, I had way too much content to fit into a 45 minute session (allowing time for Q&A).

If you missed the live session, the recording is available here: http://t.co/bSZvjTYE.

Anyway, as promised, this post is a summary of the material I covered and the first of what I hope to be several posts on the subject of Typescript and SharePoint.  I do need to revisit my JavaScript series, which has been sorely neglected over the past few months, and see how it needs to be refocused to fit into the brave new world of Typescript.

What Is Typescript?

So, first of all…what is Typescript?  From the www.typescriptlang.org website, we learn that:

Typescript is a language for application-scale JavaScript development.
Typescript is a typed superset of JavaScript that compiles to plain JavaScript.
Any browser. Any host. Any OS. Open Source.

Great.  That and $5 will buy me a cup of coffee.  Honestly, that description barely scratches the surface of Typescript.  Personally, I prefer this as a definition:

Typescript is a language and accompanying tools that support robust, professional development using JavaScript for cross-browser, cross-host applications of any size.  It facilitates the creation of standards-compliant JavaScript (ECMAScript) in a type-safe, easy-to-use manner which can be quickly grokked by most managed code or other professional programmers.

I think that is a far more encompassing definition. 

Now on to the good stuff.

Getting Started with Typescript

To get started with Typescript, you first need to install a couple of tools.  First, you’ll need the Visual Studio plug-in and I highly recommend Web Essentials (for more than just Typescript):

Web Essentials: http://visualstudiogallery.msdn.microsoft.com/07d54d12-7133-4e15-becb-6f451ea3bea6

VS Plugin: http://go.microsoft.com/fwlink/?LinkID=266563 (If you don’t use Visual Studio, Typescript is also available for Sublime Text, Emacs and Vim.  My guess is that if you’re doing SharePoint development you use VS…)

With those installed, you’re ready to go.  You can now create a SharePoint project (Farm, Sandbox or App – doesn’t matter) and add a Typescript file to it:

image

 

After you first add the Typescript file to your project, you’ll see it in Solution Explorer:

image

(Notice that there is no accompanying .js file yet)

Once you compile (which could be as simple as just saving the .ts file, depending on how you’re environment is configured), the appropriate .js files are created and nested under the .ts file in Solution Explorer:

image

The configuration settings to pay attention to are in Tools|Options|Web Essentials|Typescript:

image

Most are pretty straightforward and can be left at their defaults for now.  I’ll explore these options in more detail in a later article.  The only ones I like to make sure are set a certain way are “Keep Comments,” “Compile on Save”,” and “Minify generated JavaScript” – I make sure they’re all set to TRUE.  Believe it or not, we want to leave “Compile all Typescript files on build” set to FALSE.  We’ll address that next.

To make sure that our Typescript code is compiled into JavaScript at the proper time, we need to go through a little hack for any SharePoint projects.  Rob Bogue spells it out here: http://www.thorprojects.com/blog/archive/2012/10/13/including-typescript-in-a-sharepoint-project.aspx and the end result looks like this in your .csproj file:

image

The highlighted part is what we added.  Note that you’ll need to perform that little hack for every project in your SharePoint VS Solution that needs to compile Typescript.

The last thing you’re going to want to do is remove the .ts file from your deployment package – there’s no sense including it in the package – neither SharePoint nor the web server would have any idea what to do with it.  Doing this is simply a matter of deleting it from, or commenting it out of, the Elements.xml file:

image

Now we’re finally ready to begin… 

The Typescript Editor

The Typescript editor is a two-paned affair.  You type your Typescript on the left, the right is a preview of your generated JavaScript:

image

Each and every Typescript file you add will have some sample code included with it.  This is great while you’re learning but just an annoyance when you’re actually trying to be productive.  I hope this changes in the RTM of the tooling.  If, for some reason the tooling doesn’t change at RTM, or if deleting the sample code every time gets on your nerves, you could just create a Text file and change the extension to .ts.

After pondering over the sample code for a few minutes, go ahead and delete everything in the left hand pane – Ctrl-A | Delete will do the trick.  Now save your .ts file and, assuming you set your options as specified above, the JavaScript code in the preview on the right hand side will disappear as well.

This is probably a good place to end part 1 of this article.  We’ll pick up with Part 2 shortly covering our first baby-steps into writing Typescript code.  I’ll leave you with some resources to help you learn basic Typescript.  Part 2 will review some of that quickly and then move on to SharePoint-specific Typescript code.

Resources

Typescript Language Specification: http://go.microsoft.com/fwlink/?LinkId=267238

Pluralsight Typescript course: http://pluralsight.com/training/courses/TableOfContents?courseName=typescript

My webinar slides: blog.mannsoftware.com/wp-content/uploads/2013/02/typescriptandsharepoint.pdf

 

That’s it for part 1. 

 

Dave

 
 Share on Facebook Share on Twitter Share on Reddit Share on LinkedIn
1 Comment  comments 
formats

Starting Over…

Published on January 2, 2013 by in Business, Technology

It’s a new year, and as good a time as any to turn over a new leaf.  In reality, this has been more of an end-of-year effort resulting from a hellacious 2012 and the realization that I can’t continue on at that pace. 

I took the last 2 weeks of 2012 off from “regular” work and focused instead on cleaning up my systems, processes and the way I did things to *try* to be more efficient.  It’s an ongoing effort and I’ve only just gotten started.  This blog post and a few that follow it will document what I’ve done in the hope that it can help someone else out.

The Problem

Before getting started on the solution, a quick review of the problem.  How much of this sounds familiar?

1. Laptop desperately needed a rebuild.  Win7 was working OK, but I wasn’t happy with how it was performing

2. Organization on the laptop was a mess – files scattered from email to file system (across multiple drives, internal and external) and back again.

3. Backup was (practically) non-existent.  I had made a few half-hearted efforts as time allowed but it was patchy and haphazard.  The only thing definitely backed up was my source code

4. Offline organization was worse than laptop organization.  I’m old, so I’m a fan of paper.  My natural inclination is to jot a list of things down on a piece of paper rather than type it into my laptop or phone.  Right now, I just counted, I have 11 “to-do” lists sitting on my desk.

5. Email.  Forget “Inbox Zero” I was struggling to keep “Inbox 1000”

You get the idea.  There were a few other things that needed attention, but those were the “biggies”

The Solution

Step 1: Rebuild Laptop

I ditched Win7 and (finally) committed to Win8.  Fortunately I had purchased a touch-screen on my W510 when I purchased it a few years back, so it was a little more Win8-ready than some other laptops.  Here are the specs on my laptop/setup:

  • W510 4318 CTO
  • 32 GB RAM
  • 256 GB SSD System Drive
  • 512 GB data drive in the optical drive bay (I’m waiting for Crucial to RMA my 512 GB SSD, so stuck on spinning rust for now).  (Who uses their CD/DVD drive any more?)
  • 3 monitors: laptop and 2x21” external monitors.  Resolution set to 1680×1050 on all three monitors gives me a total resolution of 5040×1050.  I like it…

I partitioned my two drives as follows:

Disk 0 (SSD)

  • 350 MB System Reserved
  • 163 GB System Drive (C:\)
  • 60 GB Backup partition (H:\).  More on this in a minute

Disk 1 (Spinning rust, soon to be SSD)

  • 60 GB Data (D:\)
  • 406 GB VHDs (V:\)

All partitions except the VHD one are BitLockered.  I didn’t BitLocker that one to avoid the (admittedly small, but there nonetheless) performance hit.  There’s really nothing on that drive I care if anyone sees, so not worried.  I use the TPM chip in my laptop to automatically unlock all of the BitLockered drives upon boot up.

Step 2: Configure Data and Backups

I took a look at all of the data on my laptop before rebuilding it and realized that it generally fell into one of two buckets:

1. Current

2. Not-Current

The former is things I’m actively working with – active clients, projects, blog posts, presentations, user group stuff,  etc.  The latter was things that I still needed to keep but didn’t necessarily need to have with me all the time.

I decided that all of the “Not-Current” stuff should really be called “Archived” and so that’s exactly what I did – archived it.  I chose a multi-location Archive strategy to account for my own unique paranoia:

  • Anything I didn’t need to have direct, immediate access to was added to a collection of password protected (there’s that paranoia) 7Zip archives and stored on my SkyDrive.  Each client, project, writing artifact, etc. has its own 7Zip file so it’s easy to keep them straight. 
  • I also took the uncompressed files and copied them to a server here in my office.  That server is not available off of my local network, but it is backed up to an off-site location every day using CrashPlan.  Everything on there (business stuff, plus 12 years of family photos and videos, software, my wife and kid’s backups, etc.) gets dumped over to a server at my brother’s house every day (He backs up to me the same way).  All together, this is about 300 GB of content, but we use the free version of CrashPlan so it doesn’t cost us a dime.

For the “current” stuff, I wanted that to be backed up as well so I took a multi-pronged approach:

  • Utilizing Win8’s “File History” functionality, I keep every version of every file in my Data Library until I start to run out of disk space, at which point it starts automatically pruning the oldest versions.  I have File History set to check every 10 minutes and it stores the versions on the H: drive mentioned above, which, by the way, is on a separate physical drive from my main data drive so there’s a little fault tolerance there.
  • I use SyncToy (set to “Contribute” so it does not synchronize deletes) to copy any changed files from my DataLibrary (what I called the top-level folder for all of my data) every 30 minutes to a directory on my local server, which, as mentioned above, gets backed up off-site once/day).  I use the regular Windows Task Scheduler to manage the SyncToy schedule.

All of this is automatic – it’s now set up and running.  I don’t have to think about it anymore.  There are, however, two manual things I will do periodically (2x/year?):

  1. Manually archive data I no longer need to have immediately available.  This is just manually copying it (uncompressed) to my local server and then compressing it and copying it to SkyDrive
  2. Manually clean up the “Sync” folder on my server.  Since I have SyncToy set to Contribute mode, it will never delete anything from the server.  Left unchecked, this means the files on my server will continue to grow until I fill all of my brother’s drives (mirrored 1TB, IIRC).  To avoid this, I take a few minutes and just delete stuff I no longer need.

That’s it for backups.  It gets me:

  • Versioned files via File History, stored on a different spindle
  • 30-minute backups to another machine
  • Daily backups off-site

I think that’s pretty good.  Certainly not perfect, but good enough for me.  Barring a humongous natural disaster (my off-site backup location is 45 minutes away from my home office) I think I can recover from most things.  True, since SyncToy copies to a local server it will only work when I’m in my office/on my local network, I could have a problem if I’m offsite.  I spent less than 5 days last year doing work where I was producing content/material away from my office (at a client location) so I’m not too worried about that.  If I take a gig that requires more time at a client site, I’ll adjust my strategy.

Source Code

For the most part, I’m a developer, so I produce source code as my main content item.  Losing this would suck raw eggs, so I’m extra careful about that.  This is also my main intellectual property so I’m extra paranoid about it as well.  I use TFS on Azure as my main source code repository, but I also do “extra” backups as well.  These are built upon the mechanisms I covered above – all of my source code is stored inside my Data Library so it is automatically backed up to my server every 30 minutes, and a file version is picked up by Win8 File History every 10 minutes and stored as well, as detailed above.

Virtual Machines

As a SharePoint guy, I live in virtual machines.  Prior to Win8, I used VMWare workstation, but I’m transitioning everything over to HyperV now.  I store all of my VHD/VHDX files on the 400+ GB V: drive mentioned above.  All “data” on the virtual machine (source code, etc.) is stored on the host machine in my Data Library, as mentioned above, so theirs is really nothing on the VHD itself that I need.  Sure, it would suck if I lost  VHD, but it would be a matter of simply spinning up a new virtual machine, running the scripts which build that particular environment (stored along with the source code) and I’m back in business.

EMail

My email used to be a mess.  I have three “primary” email addresses (two business, one personal) that I use and like I said above, had a ridiculous amount of crap in my Inboxes.  A friend recommended an approach that I’m going to give a try: anything that arrives in an email that I want to have for later reference goes into OneNote.  I have a notebook in OneNote called “EMail Keepers” that stores things not directly related to a client or project, so it gets things like purchase receipts, software keys, etc.  Anything related to a client or project goes into the appropriate client/project notebook.  Anything else I need to keep generally is “knowledgebase” type stuff where someone has explained a piece of technology and I want to be able to find it later so it goes into my Knowledgebase notebook in OneNote.  (See the next section for more details on my use of OneNote).

Most of the rest of my email is extremely temporal – I need it for a few months and then will likely never need it after that.  This is things like threads in which a decision about my business is made, a client discussion, etc.  For the most part, I leave them sitting in my Inbox, but I have a policy that will delete them after 6 months.  If I need to keep something – say the final decision for a project – I can either save it to OneNote or move it to a folder inside Outlook.  I’m still figuring out which will work best.

I’ve gone from >4500 items in my three inboxes, with ~1500 unread) to about 1000 items in my inboxes and less than 500 unread.  I’m still working on this, and would like to get down to just a few dozen unread at any one time – #InboxZero is unreasonable for me.

OneNote

I’ve used OneNote for years, but it has always been somewhat haphazard.  No more.  I now have the following notebooks set up:

  • Projects – each project gets a Section Group.  When the project documents and such get archived (see above), the information in OneNote is saved to a PDF, added to the archive and then removed from OneNote.
  • EMail Keepers – see above
  • Knowledgebase – section groups for each major technology area I try to pay attention to: SharePoint (General), SharePoint Workflow, JavaScript.  Anything I find anywhere (web, email, forums, etc.) that I want to be able to reference later gets saved here.  I use the OneNote plugin for IE or the Print to OneNote capability and the awesome thing is that the original source URL is saved so I always know where it came from
  • Aptillon – information about my main business effort
  • CPT – stuff I use for the classes I teach for Critical Path Training
  • My Notebook – other stuff that doesn’t fit anywhere else – ideas for blog posts, business ideas, etc.
  • Product Notes – ideas and information about various products I am or would like to build
  • To Be Filed – This notebook is synched to SkyDrive.  If I’m away from my computer, I can get to it from my Surface or my Phone, so I can add something here and then move it to the “correct” notebook when I get back to my laptop

Odds & Sods

A few other things…

  • I have a drive mapped to my 28 GB of SkyDrive storage that makes it dirt-simple to access my content there.  I don’t use the SkyDrive app to access those files as it’s just too slow when saving from Office, and SkyDrive is mostly just my “archive” location anyway.  If I need to dump something else up there to have accessible from my Surface or to share with someone, the mapped drive makes that easy enough.
  • I’m *trying* to make use of Outlook tasks for things instead of paper to-do lists, but that’s a hard trick for an old dog to learn.  Stay tuned
  • I’m 90% done switching from OnTime for project management to TFS.  This will be another blog post once I get it done and moving.

That’s about it for now.  I hope this has helped you out some in your own quest to become more efficient.  It has helped me to just get it all down on paper (so to speak).  There will be other blog posts about this stuff as I get things wrapped up and actually start using it all the way I intend.  Stay tuned…

 

-Dave

 
 Share on Facebook Share on Twitter Share on Reddit Share on LinkedIn
No Comments  comments 
formats

TypeMock Isolator Cheat sheet

This one is for my own reference so I can find it later…a really useful one-page list of common tasks when writing mocks for unit testing and an accompanying line of sample code to do it with TypeMock Isolator: http://www.typemock.com/files/CSharp_API_for_Isolator.pdf.  It’s not SharePoint-specific, but quite useful nonetheless.

 
Tags:
 Share on Facebook Share on Twitter Share on Reddit Share on LinkedIn
No Comments  comments 
formats

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

 
 Share on Facebook Share on Twitter Share on Reddit Share on LinkedIn
4 Comments  comments 
formats

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)

 
 Share on Facebook Share on Twitter Share on Reddit Share on LinkedIn
1 Comment  comments