The other day I was working on a solution with a mate, and realized that as much as I take full advantage of reusable components I've written, there was one type of development I have written time and again.  Sure, I have done the old copy and paste from earlier projects, but definitely an area that takes more time than others.   Probably you can guess this by now by the title of the post, my current nemesis is the Client Side Object Model, and more specifically, for JavaScript.  I say nemesis, but really I mean "time consuming".  Even things I've written many times are easily forgotten.

TL:DR;

spJsom is a fluent API that you can use in JavaScript or TypeScript projects. It hides the complexity of the JavaScript Client Side Object Model (JSOM) and allows you to chain commands together. To start using it take a look at spJsomFluent GitHub Project

Affectionately called JSOM in SharePoint world, building solutions that take advantage of SharePoint's extensive set of API's can be challenging, time consuming and confusing.  I've also found it common that people prefer the REST API vs CSOM/JSOM.  It's a very understandable point of view,  REST and OData are generally easy to get a grasp of, and to get something happening.  The problem is that SharePoint's REST API is limited, and if you build SharePoint solutions long enough you'll eventually hit a wall and say to yourself.  "Darn, I'll just have to use CSOM for this".  

Personally, I'd rather pick an API for power than for ease.  But wouldn't it be cool if we could have both?  So I guess, I want the power of CSOM, thats simple to use, quick to develop and with minimal code.  That's not asking too much is it?  

I figured it was time to put something together to achieve this.  Here's what I wanted:
1. Use CSOM for maximum features with SharePoint online
2. Reduced code (working with CSOM can be verbose)
3. Reduced nesting (chaining async actions can become a nasty nested mess at times)
4. Use TypeScript to give us strong typing and intelli-sense
5. Include code documentation with examples to make it quick and easy to use

I settled on using a Fluent API.  I've already done this for LightVx in the CSharp world, and I was excited to try this out in JavaScript.  The reason for this choice is I find that with a fluent API the code starts to read like a story, rather than a math formula, and anything that makes code simpler and easier to read is a plus in my book.  In fact making code easier to read, simpler and consistent is always a goal in anything I work on.  But, let's talk about code conventions another time, instead let's take a look at spJsom.  

What is spJsom?

spJsom is a Fluent API wrapper over the SharePoint Client Side Object Model (JavaScript/JSOM). With a simple to use syntax, code documentation, and all sorts of CSOM complexity encapsulated, spJsom makes it easy to get the power of CSOM without the pain.

For all the details check out github repo here.

I find an example, much like a picture speaks 1000 words. So here goes:

var listName = "My List";
var context = SP.ClientContext.get_current();
new spJsom.Fluent()
    .withContext(context)
    .permission.hasWebPermission(SP.PermissionKind.manageLists, context.get_web())
    .whenTrue() 
    .list.exists(context.get_web(), listName)
    .whenFalse() 
    .list.create(context.get_web(), listName, 100)
    .listItem.create(context.get_web(), listName, { Title: "Created by spJsom" })
    .execute()
    .fail((sender, args) => {
        console.error(args.get_message());
    })
    .done((results) => {
        console.log(results);
    });

Follow it through and I bet even the non-developers out there can easily figure out what we are trying to do here. Does it read like story? Well maybe a story by a crazy drunk, but I've definetely sobered up since.

For a heap more examples, both simple and full on, check out: spJsomExamples-typescript.ts

That small dozen or so lines does the following:

  1. Checks the user has permission to create a list
  2. Checks the list doesn't exist already
  3. Creates a list
  4. Adds an item to the list and sets its title

If you've used JSOM before, you'll be familar with chaining your commands off all the call backs. Think about all the executeQueryAsync calls in that lot? Phew, it's ok, you're back in our safe space.

When working in CSOM, one of the problems we face is designing how all the async operations are called/chained, in what order, and what do we do when something isn't right, like the user doesn't have permissions. Do we try the action anyway, call it first, this tell them something went wrong? Oh wait, no that's what SharePoint does almost anytime there is an error. At least it gives us that really helpful corrleation ID when we click Technical Details.

But coming back to reality, we do figure out how to call JSOM, we probably check permissions early, or we chain promises together, refactor into seperate methods, put logic checks in to make sure things are going right and load SharePoint dependencies like sp.publishing.js and userprofiles (which uses an inconsistent naming convention). But it's all a hassle, time consuming, verbose and error prone. I really wanted a way to take all that away, simplify and allow it to be done in a single call by chaining commands through a Fluent API.

Chaining Commands

By chaining commands, and using the when conditional commands, you can put together a host of work in a single block. The when commands are used to stop execution of the chain if their criteria isn't met. The when commands consist of:

Command Description
when Pass in your own function to evaluate the last result.
whenAll Pass in your own function to evaluate all previous results.
whenTrue When the previous command resolves True execution will continue
whenFalse When the previous command resolves False execution will continue

A whole buckload of commands

There are many ways you can interact with CSOM, and more will be added over time.
I've segmented each area to make it easier to work with. Here take a look:

Fluent API Description
spJsom.file File based methods live here. Use this in doc libraries and such.
spJsom.list Work with lists and libraries.
spJsom.listItem Query lists, create, delete, update, get and more...
spJsom.navigation Update and work with SP Navigation settings
spJsom.permission Check permissions of the current user against various objects
spJsom.publishingPage Work with publishing pages.
spJsom.user From user to manager to profile properties, its whats here.
spJsom.web Need to set the welcome page? or create a web? Do that here.

Want more techie detail? Visit the github repo here.

What about progress?

Yes, some of these commands like creating a new web take time. You can't just leave your users hanging, give them a progress indication.

onExecuting
To show progress, this method will give you the details you need.

.onActionExecuting((actionName:string, current:number, total:number) => {
    let progress = Math.ceil(100 * current / total);
    console.log(`Executing: ${actionName}, we are ${progress}% through.`);
})
            

onExecuted

.onActionExecuted((actionName:string, success:boolean, results: Array<any>) => {
    console.log(`Executed: ${actionName}:${success}`);
    if (!success) {
        console.error(actionName, results);
    }
})

NPM

Want to use this in your own project, either check out the sampleApp or run this node command:
npm i spjsomfluent --save

Getting started using the sample app for TypeScript and WebPack

  1. Clone the repository and copy the sampleApp folder to your own location. git clone https://github.com/TjWheeler/spJsomFluent
  2. run npm install from the sampleApp folder you copied using a Node shell
  3. run npm run debug to build the sample app. (The development commands listed above are valid for this app too.)
  4. Upload the resulting .js and .js.map to SharePoint or use Fiddlers autoresponder to a location of your chosing. eg; /style library/myApp
  5. Add a script reference in a Script Editor web part: <script src="https://yoursharepoint.sharepoint.com/sites/yoursite/style library/myApp/myApp.js"></script>
  6. Modify the app as needed (use npm run dev to watch the file updates you make and immediately rebuild)

Note: The default sample app is designed to create a List called MyList1 and a single list item.
Once the script is loaded, it will execute as soon as SP.js is loaded.

Adding your own commands?

Want to extend this? Sure, feel free, one way you can do this is you you can add your own custom Action Commands using the chainAction method.
To follow the convention you need to return a jQuery promise. Have a look at this custom command that sets the title of the web using the chainAction method.

var context = SP.ClientContext.get_current();
new spJsom.Fluent()
    .withContext(context)
    .chainAction("myCustomCommand", () => {
        var deferred = $.Deferred();
        context.get_web().set_title("My new title");
        context.get_web().update();
        spJsom.Fluent.executeQuery(context)
            .fail((sender, args) => {
                deferred.reject(sender, args);
            })
            .done(() => {
                deferred.resolve();
            });
        return deferred.promise();
    })
    .execute()
    .fail((sender, args) => {
        console.error(args.get_message());
    })
    .done((results) => {
        console.log(results);
    });

If you want to move your commands else where, and call them, try it this way using the chain method:

var context = SP.ClientContext.get_current();
var customAction = new spJsom.ActionCommand();
customAction.name = "myCustomCommand";
customAction.action = () => {
    var deferred = $.Deferred();
    context.get_web().set_title("My alternate title");
    context.get_web().update();
    spJsom.Fluent.executeQuery(context)
        .fail((sender, args) => {
            deferred.reject(sender, args);
        })
        .done(() => {
            deferred.resolve();
        });
    return deferred.promise();
};

new spJsom.Fluent()
    .withContext(context)
    .chain(customAction)
    .execute()
    .fail((sender, args) => {
        console.error(args.get_message());
    })
    .done((results) => {
        console.log(results);
    });

            

 

Conclusion

I built spJsom to make this quicker and easier for me as I'm building SharePoint apps all the time.  Hopefully it will be useful for you too, if you build SharePoint apps.  If you don't, then thanks for reading anyway.

I'll be adding new features in future, so if you are interested watch spJsomFluent on GitHub.