Custom Web Part properties using jQuery

(This blogpost is inspired by this blogpost by Rachid Bouzalmat)

Have you ever thought there should be a better way of doing custom web parts with JavaScript? I thought so.. All developers have their own way of doing it, and it can easily become a bit of a mess.

How can we simplify? This might be the solution.

This solution is built of the following parts:

  • WebPart object/class (in JavaScript of course)
  • A Manager object (in JavaScript of course)
  • Some HTML markup

The HTML markup will keep a render function, and some properties (that will be sent to this function). The Manager will buid WebPart objects from this HTML, and call the render function specified in the markup with the properties. Cool, yey?

Let’s get to it:

How can this be done just using some jQuery magic?

Custom web part properties using jQuery 1

That’s what I’ll show in this blog post.

I’m mostly writing in TypeScript using the SharePoint and jQuery d.ts files for full intellisense, but you don’t need any TypeScript knowledge to understand what’s going on here (and you’ll always have the source on GitHub).

The WebPart class

Look at the WebPart class implementation at line 20 @ CustomWebPart.js

Here you’ll find out how the webpartid(s) are fetched etc.

Let’s start of by creating a WebPart class. This is how it’s done in TypeScript:


class WebPart {
instance: any;
id: Array;
renderfunction: string;
properties: Array<object>
render() {Manager.Render(this);}}

If you’re just writing normal JavaScript, just write it as an array of Objects with the properties above (or take a look at the compiled JS linked to above). In TypeScript I would also add a constructor to the class taking the jQuery element as a parameter. It would then set it’s instance to this element, and it would get the web part IDs, renderfunction and properties from the instance.

The HTML

For the web part properties you see above, this would be the markup/HTML. A Script Editor web part would be used to keep this HTML.

<div class="custom-webpart" data-webpart-properties="[{ "List"="", "ItemsCount"="" }]" data-webpart-renderfunction="CustomWebPart.Test.ListItems"></div>

The properties in data-webpart-properties is the properties that’ll be rendered in the UI. In this case List and ItemsCount. The function in data-webpart-renderfunction will do the rendering of the webpart. It will retrieve the WebPart object as a parameter.

The Manager

Look at the function Init at line 140 @ CustomWebPart.js
Look at the function RenderAllWebParts at line 152 @ CustomWebPart.js
Look at the function Render at line 157 @ CustomWebPart.js

I’ve created a TypeScript module Manager under CustomWebPart. This replaces namespacing in JavaScript. In normal JavaScript the file would be built up like this:

var CustomWebPart = CustomWebPart || {};
CustomWebPart.Manager = CustomWebPart.Manager || {};

The Manager object will need two main functions. Init which initializes the whole thing, and RenderAllWebParts which is pretty self-explationary.The init function will go through your DOM, and look for DIVs with a given class (in my case .custom-webpart). It would then create WebPart objects from these DIVs (like I explained above, give the jQuery element as a parameter and the WebPart object will do the rest).
If you decide to go for a Model namespace.

CustomWebPart.Model = CustomWebPart.Model|| {};

.. add a an array to this object where you’ll keep your WebPart objects.
The RenderAllWebParts function goes through the array of WebParts and calls their render() function.

So how is the properties rendered and persisted?

Look at the function GetToolPaneForWebPart at line 18 @ CustomWebPart.js
Look at the function GetUpdatedWebPartHtml at line 30 @ CustomWebPart.js
Look at the function RenderWebPartProperties at line 77 @ CustomWebPart.js

How do you render the properties? You’l need to find the .ms-TPBody for your webpart. This element should have an ID that’s equal to the ID of your webpart, so it shouldn’t be a problem really. When you’ve found it, go through the properties of your webpart, and append them with jQuery. Simple!

How do you persist the properties? It’s pretty straight forward, but still pretty advanced. What you need to do first of all is to override the onclick for these two buttons (I do this at line 101):

Custom web part properties using jQuery 2

Now Microsoft has done something very interesting. The content of our script editor web part is kept in a hidden input field. If you have the ID of your webpart (which you should have in your WebPart object), you can find it.To do this I’ve created a simple function with the following content:

return jQuery(".aspNetHidden input[name*='" + webpartid + "']");

This function (GetHiddenInputFieldForWebPart) is found at line 18

What you want to update is the data-webpart-properties attribute of your webpart HTML. On OK and Apply, you’ll retrieve your WebPart HTML, replace the properties with the new values, and finally you’ll set the value of the hidden input field to the updated WebPart HTML.
Simple, right? You’re new properties should now be persisted.

In action

In View Mode

Custom web part properties using jQuery 4

In Edit Mode

Custom web part properties using jQuery 3

6 thoughts on “Custom Web Part properties using jQuery

  1. Great post. Very creative. I’ve gone down a somewhat similar path where I build in a standard way to register my web parts and use a list to store the JSON configuration for each web part. A similar solution here: http://almondlabs.com/blog/configurable-client-side-web-parts/.

    If you think this should be part of the platform (i.e. in the form of a JS api), please vote up this User Voice suggestion: https://sharepoint.uservoice.com/forums/282887-customer-feedback-for-sharepoint-server/suggestions/7087348-make-it-easier-to-develop-javascript-based-web-par

    Liked by 1 person

    1. Thanks Brian!

      I’ve added that to my solution aswell, but it’s not commited to the BitBucket repo as of now. The code was pretty easy to extend to use a list for config. When using a list for config, you can also edit the properties in view mode which can be cool!

      Not sure how Microsoft can make it easier though? They already support
      this cool way of persisting the properties using this hidden input field, but they can make a small framework for it perhaps? Some functions for updating the properties in edit mode, and for appending new input fields to the toolpane.

      Like

      1. Yes, storing the configuration in a central list makes it easy in scenarios where you may need to make quick or bulk edits as an admin to the site (as I do in my current role). Avoids the whole check out/checkin process, but at the cost of loosing the settings in page history and also not making the web part fully exportable – something we were OK with, but may not be suitable for all scenarios.

        I also considered storing the configuration as properties of the page “file” using the property bag but decided against this as we want to have quick/easy access to the settings without having to build a separate admin UI. We get that for free with a list.

        Perhaps “make it easier” is a bad choice of words.

        What I really mean to say is to “provide a standard API for this that will hold up over time”. Your solution is good, however, it relies heavily on undocumented implementations of UI elements that work “today”. If they decide to start changing how web parts are assigned IDs (for example prefix them with MSO or O365 or something) or change the mechanics of the hidden input field, the solution would break. Granted a pretty easy fix, but could break things. Similar things have happened before: http://sympmarc.com/2014/01/23/office-365-update-changes-display-name-on-required-fields/

        Liked by 2 people

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s