Problem with the People Picker of Sharepoint

For one of my list I’ve had a very weird issue: one people picker didn’t work properly. If I entered a name and clicked to check it, then it didn’t work. If I saved it and then got back to the form, the value didn’t appear.

This strange behavior is due to a missing SPAN element with _errorLabel as an ID. I have no clue why Sharepoint failed to create this SPAN element… And the error is related to the EntityEditorCallback function that tries to use the SPAN element, but as it doesn’t exist, it returns NULL and fails the function.

To fix it, I’m checking if the SPAN element exists, and if not I create it.
The below code must be called AFTER the line in your document that says :

document.write('<script type="text/javascript" src="/_layouts/entityeditor.js?rev=vXD0hrzDeHYHbfW8aRSMjA%3D%3D"></' + 'script>');

The code to fix this issue is:

// some People Picker are broken for an unknown reason...
// the behavior : we cannot check the name, and the "default" value is not set when editing
// the fix : the span with _errorLabel is not created, so we need to create it
if (typeof EntityEditorCallback === "function") {
  var _EntityEditorCallback = EntityEditorCallback;
  window.EntityEditorCallback = function(result,ctx,preventAutoPostBack) {
    var errorControl=document.getElementById(getSubControlID(ctx, 'errorLabel'));
    // if errorControl doesn't exist then we create it
    if (!errorControl) {
      var e=document.getElementById(ctx);
      var spans=e.getElementsByTagName("td");
      for (var i=0; i<spans.length; i++) {
        if (spans[i].getAttribute("colspan") == 3) {
          spans[i].innerHTML = '';
          break;
        }
      }
    }
    // call the original function
    _EntityEditorCallback(result,ctx,preventAutoPostBack);
  }
}

Communication between iframe and parent window [JavaScript]

In the iframe you’ll use the below code:

window.parent.postMessage("Hello World !", "http://your.site.web");

And in the parent window:

// function that will be called when the message is received
function receiveMessage(event) {
  alert(event.data); // it'll show "Hello World !"
}
// we listen to a message
if (window.addEventListener) {
  window.addEventListener('message', receiveMessage, false);
} else if (window.attachEvent) { // IE8
  window.attachEvent('onmessage', receiveMessage);
}

It’s working from IE8+, and all modern browsers, but make sure you have a HTML5 doctype (<!DOCTYPE html>)

Use hash word in the Sharepoint navigation

Let’s say you have the url http://my.site.com/myfolder/mypage.aspx#hash and you want to use it as a link into your left navigation bar in Sharepoint…. If you try putting that name, Sharepoint will not keep your link.

The trick here is to add a questionmark juste before the #. The URL to use will be http://my.site.com/myfolder/mypage.aspx?#hash and Sharepoint will accept the link 🙂

How to edit the default action for an icon in a Sharepoint Ribbon

I wanted to change the behavior of the “Edit Item” button from the Sharepoint 2010 ribbon of the Display Form (DispForm.aspx). It wasn’t really easy, so I finally found a solution that I’m going to share here.

You’ll need to use JavaScript for that. In the below example, the click on the “Edit Item” will open the EditForm in a new window:

function ribbonIsLoaded() {
  // find the button we want to change
  var a = document.getElementById('Ribbon.ListForm.Display.Manage.EditItem-Large');
  // remove the default action for this button
  Sys.UI.DomEvent.clearHandlers(a)
  // define your own action
  a.setAttribute("onclick","");
  a.setAttribute("target", "_blank");
  a.setAttribute("href", window.location.href.replace(/DispForm.aspx/,"EditForm.aspx").replace(/&IsDlg=1/,""))
}
// Note: 'SOD' is an abbreviation for "Script on Demand"

SP.SOD.executeOrDelayUntilScriptLoaded(function () {
  var pm = SP.Ribbon.PageManager.get_instance();
  pm.add_ribbonInited(function () {
    ribbonIsLoaded();
  });
  var ribbon = null;
  try
  {
    ribbon = pm.get_ribbon();
  } 
  catch (e) {
  }
  if (!ribbon) {
    if (typeof (_ribbonStartInit) == 'function')
    _ribbonStartInit(_ribbon.initialTabId, false, null);
  } 
  else {
    ribbonIsLoaded();
  }
}, 'sp.ribbon.js');

Show/Hide a Sharepoint fields in the NewForm, EditForm and DispForm

With the Sharepoint WebServices it’s possible to hide a field into the NewForm, the Editform and/or the DispForm.
You’ll need to use JavaScript with jQuery and SPServices. It’s the UpdateList service that will do the trick.

Once you have loaded the both librairies you can use the below code:

var fieldsToUpdate = '<Fields>';
fieldsToUpdate += '<Method ID="1"><Field Type="Text" Name="My_x0020_Field" DisplayName="My Field" ShowInDisplayForm="FALSE" ShowInEditForm="FALSE" ShowInNewForm="FALSE"></Field></Method>';
fieldsToUpdate += '</Fields>';

$().SPServices({
  operation: "UpdateList",
  listName: "Name of the list",
  listProperties:"",
  updateFields: fieldsToUpdate,
  newFields: "",
  deleteFields: "",
  listVersion: "",
  completefunc: function (xData, Status){}
});

As explained into this Stackoverflow’s question you must provide a minimum of three mandatory properties, and in this order:

  1. Type
  2. Name
  3. DisplayName

The Type must reflect the type of your field. This information is available into the MSDN documentation. The most common values should be Boolean | Calculated | Choice | Currency | DateTime | Integer | Lookup | LookupMulti | MultiChoice | Number | Text | User | UserMulti.

The Name is the internal name (usually the spaces are replaced with “_x0020_”).

And for each form (ShowInDisplayForm | ShowInEditForm | ShowInNewForm) you can set them to TRUE or FALSE (it seems to be case sensitive ?!). More properties are available into the MSDN documentation.

Delete a User Custom Action from Sharepoint [JavaScript]

The MSDN documentation is a nightmare…. For example Microsoft provides an example to create a User Custom Action for Sharepoint, however there is no code about how to delete it.

So here is the code to use to delete the usercustomaction just created with the above example:

var siteUrl = '/site collection/site/';

function deleteUserCustomAction() {
    this.clientContext = new SP.ClientContext(siteUrl);
    var oWebsite = clientContext.get_web();
    this.collUserCustomAction = oWebsite.get_userCustomActions();
    clientContext.load(oWebsite,'UserCustomActions','Title');
    clientContext.executeQueryAsync(Function.createDelegate(this, this.deleteCustomAction), Function.createDelegate(this, this.onQueryFailed));
}
function deleteCustomAction() {
    var customActionEnumerator = collUserCustomAction.getEnumerator();
    while (customActionEnumerator.moveNext())  {
      var oUserCustomAction = customActionEnumerator.get_current();
      if (oUserCustomAction.get_title() == 'New Menu Item') {
           oUserCustomAction.deleteObject();        
           clientContext.load(oUserCustomAction);
           clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));
        }
    }
}
function onQuerySucceeded() {
    alert('Custom action removed');
}
function onQueryFailed(sender, args) {
    alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
deleteUserCustomAction()

Dynamically inject a CSS code into the page [JavaScript]

Mozilla created a function that permits to inject some CSS into the document: addStylesheetRules()

But if you use jQuery you may want to use this function:

function injectCSS(rule) {
  $("head").append('<style>' + rule + '</style>')
}

// example
injectCSS("div { padding:5px }")

Tiny AJAX

This is a very tiny javascript code to do an AJAX Request:

/*
 m: method ("get", "post")
 u: url
 a: async (true) or sync (false)
 c: callback (with 'xhr' as a parameter)
 d: post_data (the data to post)
*/
function tiny_ajax(m,u,a,c,d){with(new(this.XMLHttpRequest||ActiveXObject)("Microsoft.XMLHTTP"))onreadystatechange=function(){readyState^4||c(this)},open(m,u,a),send(d)}

And an example:

tiny_ajax('get', 'http://www.google.com', true, function(xhr) {
    alert(xhr.responseText)
})