Second Life of a Hungarian SharePoint Geek

July 6, 2015

Accessing and Manipulating Property Bags via the ECMAScript Client Object Model

Recently I work a lot with web applications implemented on the client side with JavaScript, mostly using the AngularJS library. Rather often should I build the application logic on the values stored in the property bags of the web objects, so I decided to sum up the experience I made in this field.

Note: A similar blog entry discussing the same topic can be found here. It might be useful to read that one as well, but I include additional info in my entry as well.

Note 2: The code samples in my post are borrowed from our custom AngularJS service, but the bulk of them should be reusable for any kind of JavaScript solution.

The first example shows how to retrieve the property values:

  1. this.readSettings = function ($scope) {
  2.     var deferred = $q.defer();
  3.  
  4.     var ctx = SP.ClientContext.get_current();
  5.  
  6.     var web = ctx.get_web();
  7.     var props = web.get_allProperties();
  8.     ctx.load(props);
  9.  
  10.     ctx.executeQueryAsync(
  11.         function () {
  12.             // you receive an error if the property is not defined for the web:
  13.             // 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.
  14.             var yourProperty = props.get_item("YourProperty");
  15.             // or alternativelyyou can use
  16.             //var allProps = props.get_fieldValues();
  17.             //var yourProperty = allProps.YourProperty;
  18.             // in this second case you can  check, if the property is defined …
  19.             //if (typeof (yourProperty) == "undefined") {
  20.             //    console.log("The property is undefined");
  21.             //}
  22.             //…or iterate through all the properties
  23.             //for (var property in allProps) {
  24.             //    if (allProps.hasOwnProperty(property)) {
  25.             //        console.log(String.format("{0}: {1}", property, allProps[property]));
  26.             //    }
  27.             //}
  28.  
  29.             deferred.resolve(
  30.                 {
  31.                     projectId: projectId
  32.                 });
  33.         },
  34.         function (sender, args) {
  35.             deferred.reject('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
  36.         }
  37.     );
  38.  
  39.     return deferred.promise;
  40. };

If you trace the network traffic with Fiddler, you will capture the following (or similar) request-response:

image

As you can see, all of the properties from the bag are returned by the server, they are in the form of simple property name – property value pairs (see response for Query with Id=6).

When you already have the response from the server, there are two different methods to get the value of a specific property. There is a very important difference between the two versions (get_item method vs. get_fieldValues method). If the property is undefined in the property bag, you receive an error, if you would like to read the value via props.get_item("YourProperty"):

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.

However, if you access the property via the get_fieldValues method, you don’t get the exception, even if there is no such property in the property bag. In this case the property remain simply undefined, so you can check its existence via

var allProps = props.get_fieldValues();
if (typeof (allProps.YourProperty) == "undefined") {
  console.log("The property is undefined");
}

In this case the properties from the bag are available as simple JavaScript properties from code:

image

You can dump (or process) all properties defined in the bag via this code (taken from this thread):

var allProps = props.get_fieldValues();
for (var property in allProps) {
  if (allProps.hasOwnProperty(property)) {
    console.log(String.format("{0}: {1}", property, allProps[property]));
  }
}

A sample output of the script in the debugging console:

image

Unfortunately, I have not found any way to limit the scope of properties returned by the query to specific properties. All of the properties in the property bag are returned by the request. The GetProperty method of the SPWeb class, that on the server side makes it possible to access the value of a single property, is not implemented in the client object model.

If you try this one:

var props = web.get_allProperties();
ctx.load(props, "Include(YourProperty)");

you will receive an exception complaining about the invalid request, as you call the executeQueryAsync method.

Saving the value back to the web properties is a straightforward operation:

  1. this.saveSettings = function ($scope) {
  2.     var deferred = $q.defer();
  3.  
  4.     var ctx = new SP.ClientContext();
  5.  
  6.     var web = ctx.get_web();
  7.     var props = web.get_allProperties();        
  8.     props.set_item("YourProperty", $scope.propValue);
  9.     web.update();
  10.  
  11.     ctx.executeQueryAsync(
  12.         function () {
  13.             deferred.resolve();
  14.         },
  15.         function (sender, args) {
  16.             deferred.reject('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
  17.         }
  18.     );
  19.  
  20.     return deferred.promise;
  21. }

1 Comment »

  1. Hey Peter, thanks for linking my blog post, but nowadays I would use a REST call to /_api/web/allproperties. It’s much simpler and more flexible in my opinion. I’m not sure if it supports writing back values however.

    Comment by derek gusoff — July 7, 2015 @ 14:32


RSS feed for comments on this post. TrackBack URI

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

Blog at WordPress.com.

%d bloggers like this: