CHUVASH.eu

CHunky Universe of Vigourous Astonishing SHarepoint :)

Tag Archives: jsom

Trigger SP2010 Workflows using JSOM

Today I found out how to start workflows in JSOM (JavaScript Object Model in SharePoint). Nothing special, but since it is not documented, it took me a while to find a solution. Here is the code which I want to keep as simple as possible.

What you need to start a SP2010 Workflow for a list item or a document in JSOM, you need to load SP.WorkflowServices.js and you need to create the manager and get the service, then you can trigger a workflow using the workflow name, the list guid and the guid of the list item:

var ctx = SP.ClientContext.get_current();
var workflowServicesManager =
	SP.WorkflowServices.WorkflowServicesManager.newObject(ctx,
		ctx.get_web());
var service = workflowServicesManager.getWorkflowInteropService();
service.startWorkflow(workflowName, null,
	listGuid, plainItem.guid, initiationParams);

Here is the code to trigger a workflow for multiple items:

//fire the workflows
function fire2010WorkflowForListItems(ctx, listGuid, plainItems) {
	var workflowServicesManager =
		SP.WorkflowServices.WorkflowServicesManager.newObject(ctx,
			ctx.get_web());
	var service = workflowServicesManager.getWorkflowInteropService();
	for(var i = 0; i < plainItems.length; i++) {
		var plainItem = plainItems[i];
		console.log('scheduling workflow for id: ', plainItem.id);
		service.startWorkflow(options.workflowName, null,
			listGuid, plainItem.guid, options.initiationParams);
	}
	console.log('now executing...');
	ctx.executeQueryAsync(function() {
		console.info('yes, workflows completed for '
			+ items.length + ' items');
	}, function() {
		console.error('it didnt go well');
	});
}

 

The code above is inspired from this gist and sharepoint stackexchange. It is a simplified version that only works for list item workflows and SharePoint 2010 workflows.
Here is an example how you can get multiple items and batch start a workflow:

//just a couple of variables
var options = {
	workflowName: 'Behörigheter',
	listName: 'Documents',
	initiationParams: {}
};
//load list items
function startWorfklows() {
	//Start 2010 Workflow for a List Item
	var ctx = SP.ClientContext.get_current();
	var web = ctx.get_web();
	var lists = web.get_lists();
	var list = lists.getByTitle(options.listName);
	ctx.load(list);
	var items = list.getItems(new SP.CamlQuery());
	ctx.load(items);
	ctx.executeQueryAsync(function() {
		var listGuid = list.get_id() + '';
		var en = items.getEnumerator();
		var plainItems = [];
		while (en.moveNext()) {
			var it = en.get_current();
			//do not take checked out files, it won't work
			if (!it.get_item('CheckoutUser')) {
				plainItems.push({id: it.get_id(), guid: it.get_item('GUID') + '' });
			}
		}
		fire2010WorkflowForListItems(ctx, listGuid, plainItems);
	}, function() {
		alert('boom');
	});
}

//Load Worfklow Js dependency
var wfScript = 'SP.WorkflowServices.js'
SP.SOD.registerSod(wfScript,
	_spPageContextInfo.webAbsoluteUrl + '/_layouts/15/SP.WorkflowServices.js');
SP.SOD.executeFunc(wfScript, '', startWorfklows);

Why I needed it

I created a simple workflow that is triggered on Item Added and Item Updated. Unfortunately there are already thousands of items in the document library. To trigger them manually is nothing good. But a simple javascript solution did exactly what I wanted.

Advertisements

JSOM: Alter a column’s DisplayName

Here is another article in my JSOM series. For one month ago I showed how to alter a column’s ShowInDisplayForm property with JSOM. This time I’ll show a code sample for changing a column’s (field’s) display name. If you want to alter the displayname with Server Object Model, grab the code in the sharepoint.stackexchange.com: Change Field’s DisplayName in a List.

var ctx = SP.ClientContext.get_current(),              //SP.ClientContext
    field = ctx.get_web()                              //SP.Web
               .get_lists()                            //SP.ListCollection
               .getByTitle('MyList')                   //SP.List
	       .get_fields()                           //SP.FieldCollection
	       .getByInternalNameOrTitle("Body");      //SP.Field
ctx.load(field, "Title");                              //load only Title
ctx.executeQueryAsync(function() {
	field.set_title("Beskrivning");
	field.update();
	ctx.executeQueryAsync();
});

Delete all list items with jsom

Today I needed to “clean” a list, meaning to remove all list items. For some time ago I wrote a post about different ways of removing list items in bulk: Server Object Model, SPLinq and RPC.  This time I had only the web browser. So I tried the jsom way. By the way, the javascript documentation for jsom on msdn is getting really good. Don’t miss that: How to: Complete basic operations using JavaScript library code in SharePoint 2013.

Now here comes theworking code I used to remove all items in my list:

var ctx = SP.ClientContext.get_current(),
   list = ctx.get_web().get_lists().getByTitle('MyList'),
   query = new SP.CamlQuery(),
   items = list.getItems(query);
ctx.load(items, "Include(Id)");
ctx.executeQueryAsync(function () {
    var enumerator = items.getEnumerator(),
        simpleArray = [];
    while (enumerator.moveNext()) {
        simpleArray.push(enumerator.get_current());
    }
    for (var s in simpleArray) {
        simpleArray[s].deleteObject();
    }
    ctx.executeQueryAsync();
});

Enjoy

GeoLocation Field in SharePoint 2013

In SharePoint 2013 Preview there is a new type of field: GeoLocation which is, like the old SPUrlField, a pair of values. The geolocation is described as longitude and latitude.

Unfortunately you can’t add this field in list settings. You have to create this in code. In the provided link you can find the code C# code which uses the Client Object Model. In another link  you can find an example how to create the geolocation file using Server Object Model (in FeatureActivated EventReceiver).

If you know me, you might already know that I will propose a JavaScript solution. Here is the code to create a geolocation field in an existing list using JSOM:

var ctx = SP.ClientContext.get_current(),
	list = ctx.get_web()
		.get_lists()
		.getByTitle("CheckIns"),
	fields = list.get_fields();

fields.addFieldAsXml("<Field Type='Geolocation' DisplayName='Location'/>", true); 
list.update(); 
ctx.load(list); 
ctx.executeQueryAsync();

Add the location in the UI. There you can define long and lat, or use your current location:

To add a list item with a geolocation we can use jsom as well. This code adds a new list item with Cheboksary geolocation:

var ctx = SP.ClientContext.get_current(),
	list = ctx.get_web()
		.get_lists()
		.getByTitle("CheckIns"),
	itemCreateInfo = new SP.ListItemCreationInformation(),
	item = list.addItem(itemCreateInfo),
	point = "POINT (47.23 56.13)";
item.set_item('Title', 'Cheboksary');
item.set_item('Location', point);
item.update();
ctx.load(item);
ctx.executeQueryAsync();

When you open the list again, you will see this:

Happy coding!

Paging with JSOM

If there are many list items you try retrieve with javascript object model,paging could be very useful. Today I came across a wonderful blog post series about javascript object model in SharePoint: The SharePoint javascript object model – Resources and Real World Examples posted by David Mann and published on Aptilon Blog.

There is an example how to achieve paging with JSOM. The key is items.get_listItemCollectionPosition() and query.set_listItemCollectionPosition()

I have refactored David’s example to avoid global variables and to put into a module. Here is it. If you have a Tasks list in your site with many items, just hit F12 to open the console and paste this and see the result:

(function(SP) {
   var 
      ctx = SP.ClientContext.get_current(),
      list = ctx.get_web().get_lists().getByTitle('Tasks'),
      position,
      enumerator,
      view = '<View><ViewFields><FieldRef Name="Title"/></ViewFields><RowLimit>10</RowLimit></View>',
      query = new SP.CamlQuery(),
      items,
      init = function() {
         query.set_viewXml(view);			
      },
      loadChunks = function() {
         query.set_listItemCollectionPosition(position);
         items = list.getItems(query);
         ctx.load(items);
         ctx.executeQueryAsync(success, error);
      },
      success = function() {
         console.log("\nFound Matching Items! ");
         enumerator = items.getEnumerator();
         while(enumerator.moveNext()) {
            console.log("Title: " + enumerator.get_current().get_item("Title") );
         }
         position = items.get_listItemCollectionPosition();
         //when there are no items position is null
         position && loadChunks();
      },
      error = function(sender, args) {
         console.log('Request failed. Error: ' + args.get_message() + '. StackTrace: ' + args.get_stackTrace());
      };

   init();
   loadChunks();
})(SP);

JSOM: Alter a column’s ShowInDisplayForm property

When you create a content type, you can define if your fields will be shown in DisplayForm, EditForm, NewForm. You can hide or show them, just as Yaroslav Pentsarsky says. If your list is already provisioned, you can change them with Server Object Model, why not in PowerShell: Technet: Setting ShowInDisplayForm, ShowInEditForm, ShowInNewForm properties with powershell.

If you don’t have access to the server, then the same can be done with JSOM. Here is the code:

var ctx = SP.ClientContext.get_current(),              //SP.ClientContext
    field = ctx.get_web()                              //SP.Web
               .get_lists()                            //SP.ListCollection
               .getByTitle('MyList')                   //SP.List
	       .get_fields()                           //SP.FieldCollection
	       .getByInternalNameOrTitle("Site");      //SP.Field
ctx.load(field, "SchemaXml");                          //load only SchemaXml
ctx.executeQueryAsync(function() {
	var s = field.get_schemaXml(),
	    s1 = s.replace('ShowInDisplayForm="FALSE"', 
                           'ShowInDisplayForm="TRUE"');
	field.set_schemaXml(s1);
	field.update();
	ctx.executeQueryAsync();
});

Next: JSOM: Alter a column’s DisplayName.

JSOM: Last Modified Date of a List

The data transfer between server and client can heavily affect the performance. One of the measures to reduce the amount data transferred from the server to the client is storing data on the client. In many modern browsers we can use html5 localStorage. Even in older browsers there are ways to store data.

I would recommend a nice js lib called amplify.js. The interface is much easier, then:

amplify.store("key", { title: "value" });

It comes in nicely, if we have much data which we get with JSOM. But we have to care about eventual changes to list items done after we got them the last time.

So we have to store the last modified date. This property is also available in JSOM:

var ctx = SP.ClientContext.get_current();
var web = ctx.get_web();
var lists = web.get_lists();
var list = lists.getByTitle("Tasks");
ctx.load(list, "LastItemModifiedDate");
ctx.executeQueryAsync(
	function() {
		var lastmodified = list.get_lastItemModifiedDate();
	},
	function() {}
);

Be sure you load only the properties you need:

ctx.load(list, "LastItemModifiedDate");

I took a screenshot to show the difference:

Next time we want to load our items, we can check if we have them saved locally and get the last modified date of the list. If this hasn’t changed, just load from the localStorage.

Another property to keep an eye for is “LastItemDeletedDate”…

$().SPServices is best for SOAP

SPServices is a great tool, really nice work, Marc Anderson (@sympmarc). It has been there all the time I have developed for SharePoint. But the fact that you work with XML and you must parse the attributes (!) was the reason why I prefered listdata.svc and Client Object Model, where you get objects in JSON or you have a nice API to get objects and their properties. But there is an area where SPServices are really the best tool: SharePoint Web Services which only understand SOAP like SocialDataService.asmx.

Three ways to get list items

Just a little comparison. We’ll retrieve Titles from Tasks list (Oppgaver in nb-no).
listdata.svc

$.getJSON("/_vti_bin/ListData.svc/Oppgaver()?$select=Tittel")
	.done(function(data){
	  var tasks = data.d.results;
		for(var t in tasks) {
			var title = tasks[t].Tittel;
			console.log(title);
		}
	})
	.fail(function() {
		console.log("error");
	});

Pay attention to the field name: Tittel. I think it is the biggest shortcoming of listdata.svc: the fact that we can’t use the internal (static) field names.
Client Object Model

var ctx = SP.ClientContext.get_current();
var web = ctx.get_web();
var taskList = web.get_lists().getByTitle("Oppgaver");
var query = new SP.CamlQuery("<ViewFields><FieldRef Name='Title' /></ViewFields>");
var tasks = taskList.getItems(query);
ctx.load(tasks);
ctx.executeQueryAsync(function() {
	var listEnumerator = tasks.getEnumerator();
	while(listEnumerator.moveNext()) {
		var task = listEnumerator.get_current();
		var title = task.get_item("Title");
		console.log(title);
	}
}, function() {
	console.log("error");
});

SPServices

$().SPServices({
    operation: "GetListItems",
    async: true,
    listName: "Oppgaver",
    CAMLViewFields: "<ViewFields><FieldRef Name='Title' /></ViewFields>",
    completefunc: function (xData, Status) {
        $(xData.responseXML).SPFilterNode("z:row").each(function() {
            console.log( $(this).attr("ows_Title") );        
        });
    }
});
SPServices and SocialDataService

Let’s try to find the count of comments for an url. To do so we must create a SOAP envelope in javascript, send it and handle the response result:

var strUrl = "http://dev/Sider/Help.aspx";
var request = "<soap:Envelope \
    xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' \
    xmlns:xsd='http://www.w3.org/2001/XMLSchema' \
    xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'> \
    <soap:Body>    \
      <CountCommentsOnUrl \
          xmlns='http://microsoft.com/webservices/SharePointPortalServer/SocialDataService'> \
        <url>" + strUrl + "</url> \
      </CountCommentsOnUrl> \
     </soap:Body> \
  </soap:Envelope>";

jQuery.ajax({
  type: "POST",
  async: true,
  url: '/_vti_bin/SocialDataService.asmx?op=CountCommentsOnUrl',
  data: request,
  contentType: "text/xml; charset=utf-8",
  dataType: "xml",
  success: function (content, txtFunc, xhr) {
    var count = jQuery(content).find('CountCommentsOnUrlResult').text();
    console.log(count);
  }
});

It works but, we have to handle the creating of SOAP envelope in our javascript code which can be error prone. SPServices provides a nice abstraction layer and handles many scenarios. The same operation in SPServices:

$().SPServices({
  operation: "CountCommentsOnUrl",
  async: true,
  url:"http://dev/Sider/Help.aspx",
  completefunc: function (xData, Status) {
    var result = $(xData.responseXML).find("CountCommentsOnUrlResult")[0];
    console.log($(result).text());
  }
});

In both cases we have to iterate through responseXML. This is a sample responseXML for CountCommentsOnUrl from SocialDataService.asmx:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope
  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
      <CountCommentsOnUrlResponse
          xmlns="http://microsoft.com/webservices/SharePointPortalServer/SocialDataService">
      <CountCommentsOnUrlResult>1</CountCommentsOnUrlResult>
    </CountCommentsOnUrlResponse>
  </soap:Body>
</soap:Envelope>
Вула Чăвашла

VulaCV - Чăвашла вулаттаракан сайт

Discovering SharePoint

And going crazy doing it

Bram de Jager talking Office 365, SharePoint and Azure

My view and thoughts on Productivity and more.

My programming life

and everything in between

SharePoint Development Lab by @avishnyakov

It is a good place to share some SharePoint stories and development practices.

SharePoint Dragons

Nikander & Margriet on SharePoint

Paul J. Swider - RealActivity

RealActivity is a specialized healthcare services and solution advisory firm.

Mai Omar Desouki - Avid SharePointer

Egyptian & Vodafoner - Senior SharePoint Consultant

Cameron Dwyer | Office 365, SharePoint, Outlook, OnePlace Solutions

Office 365, SharePoint, OnePlace Solutions & Life's Other Little Wonders

paul.tavares

Me and My doings!

Share SharePoint Points!!

By Mohit Vashishtha

Jimmy Janlén "Den Scrummande Konsulten"

Erfarenheter, synpunkter och raljerande om Scrum från Jimmy Janlén

SPJoel

SharePoint for everyone

SharePointRyan

Ryan Dennis is a SharePoint Solution Architect with a passion for SharePoint and PowerShell

SharePoint 2020

The Vision for a Future of Clarity

Aharoni in Unicode

Treacle tarts for great justice

... And All That JS

JavaScript, Web Apps and SharePoint