SharePoint List Settings Issue: “Internet Explorer is required to use this feature.”

This one belongs firmly in the “things that make you go hmm…” department.

Let’s say you are a good do-be like me and you use all of the Microsoft products that you can get your hands on. You’ve got email and SharePoint running on Office 365, you use all the Office applications and tools, you’re up to date on your version of Internet Explorer… You get the picture.

Well, sometimes all that good behavior doesn’t pay. Today I wanted to edit an InfoPath form attached to a list in SharePoint 2013 on premises. (You won’t run into this problem on Office365, at least it doesn’t happen in my tenant. Office365 seems to know IE11.) I went to the List Settings and clicked on the Form Settings link. I’m using Internet Explorer 11, so I’m as up to date as I can be without getting into beta territory.

Lo and behold:

Internet Explorer is required to use this feature.

Internet Explorer is required to use this feature.

Yup. I’m using Internet Explorer and the message says “Internet Explorer is required to use this feature.” The issue is that the on premises install that I’m working with doesn’t understand Internet Explorer 11. It *should* see it as Internet Explorer, though, and give me a better message. I’m not exactly sure what patch level we’re on, but I think it’s pretty close to current.

Fortunately, there is an easy fix for this. Simply hit F12 to bring up the Developer Tools and scroll all the way down to the bottom of the left side icon list.The one you want to click on looks like this:

Emulation

That will give you access to the Emulation settings. Change the User agent string setting to Internet Explorer 10.

2014-06-18_10-21-10

Fixing the issue by changing the User agent string

The page will reload and now SharePoint will understand that you are the good do-be that you are, speaking IE10ish instead of IE11ish. After you do your work, it’s a good idea to switch back to default so that you are speaking IE11ish again.

The Emulation settings give you a bunch of other nice tools (want to act like an XBox360?), so if you have interest in testing things in different browsers types, etc., be sure to check out the rest of the settings as well.

SPServices: What About Deprecation of the SOAP Web Services?

SPServices user JSdream asked a question in the SPServices Discussions on Codeplex the other day that’s worthy of a more prominent response.

Should we, who use SPServices, be concerned at all with Microsoft recommending not to use either the ASMX web services in SharePoint 2013 (http://msdn.microsoft.com/en-us/library/office/jj164060.aspx#DeprecatedAPIs) or the owssvr.dll (I used this one a lot when doing InfoPath stuff) for development purposes?

The Choose the right API set in SharePoint 2013 article is an important one, for sure. In it, there’s pretty clear direction about which API to choose based on the specific requirements of the solution you are building. As with anything, though, there’s a strong dash of “it depends”. It depends on things like your available skills, the device the code will run on, etc.

Figure 1. Selected SharePoint extension types and SharePoint sets of APIs

Figure 1. Selected SharePoint extension types and SharePoint sets of APIs

I would say that we should all be “cautious” rather than “concerned”. The SOAP Web Services are used by many parts of SharePoint still, with the most prominent being SharePoint Designer. If you sniff around in the traffic between processes, you’ll spot other places as well.

That said, deprecated is deprecated. If you build your solutions with the data access layer separated out from the business logic layer, you should be able to replace the calls if and when it becomes necessary.

I am not aware of any official specific time frames for the SOAP services going away, and the Product Group would need to give us a good, long lead time because lots of code depends on it, SPServices or not. Many people have built managed code-based solutions which use the SOAP Web Services as well. GetListItems is a workhorse operation no matter how you build your solutions.

There are many things you simply cannot do with REST yet, though in many cases CSOM may provide better coverage. If you are using SPServices for the operations which aren’t available in REST or CSOM, obviously you’ll want to continue doing so until there is a viable replacement. The REST coverage is improving steadily. (See Overview of SharePoint Conference 2014 and new content for developers for some information.) Keep in mind, though, that the majority of improvements will end up in Office365 first and in the SharePoint Server product at some point later or perhaps not at all. So your time horizons and cloud plans are also critical decision factors.

[If I had to put my money on a horse, it'd be REST over CSOM over the long term.]

All that said, if you are starting a new project on SharePoint 2013 of any significant size, you should be considering using the App Model, CSOM, and REST. SPServices may still fit in there somewhere, so don’t toss it out with the bath water just yet. I’ll continue evolving it as long as it has people wanting to use it. I think I still have plenty of things to do.

Create a Subsite in SharePoint 2013 Using REST Calls

Today I was working on what seemed like a simple little task. I wanted to create a subsite using a REST call in SharePoint 2013. I’m not working in an “app” per se – this is for SharePoint 2013 on premises, and I want to do the subsite creation directly from a call in a plain old aspx page.

Unfortunately, there isn’t a clear example out there, at least not that I could find. It seems as though everyone has simply copied the example from this page on MSDN and quotes it verbatim. (Look for the “Creating a site with REST” example.) Unfortunately, I couldn’t get that example to work for me. Most of the examples are also focused on creating subsites in a workflow rather than directly.

I knew I’d need to have a fresh copy of the Form Digest for the request to work. There’s a great article from Wictor Wilén (@wictor) called SharePoint 2013: How to refresh the Request Digest value in JavaScript that explains several different ways to get this token. You must have the token in order for SharePoint to be willing to accept your requests to do a write to anything; it’s a part of the security features. In the page where I am working, we’re building a full application on top of SharePoint, but without using the out of the box SharePoint UI. Because of this, things like the hidden variable which usually holds the Form Digest token aren’t available in our pages. By making a quick call to the ContextInfo REST API, I can grab the Form Digest token pretty painlessly using the second method from Wictor’s post.

The breakthrough came due to some great suggestions from Matt Gibson (@Gibz) and Rob Windsor (@robwindsor) on Twitter. (You’ve got to love the #SPHelp hashtag!) Both Matt and Rob were sure this should work and gave me tips. The winning idea came from Rob. There’s a comment at the bottom of the MSDN page referenced above that shows slightly different JSON data in the REST call payload, and that did it. Bottom line, the documentation doesn’t seem to be adequate or correct in this case. At the very least, I couldn’t find it if it’s out there.

Here’s the code I ended up with. I’ve built it as a jQuery function for reusability.

// Create a new subsite
$.fn.Site.create = function(options) {

  var opt = $.extend({}, {
    siteUrl: null,
    siteName: null,
    siteDescription: "",
    siteTemplate: "sts",
    uniquePermissions: false
  }, $.fn.ProjectName.defaults, options);

  // Because we don't have the hidden __REQUESTDIGEST variable, we need to ask the server for the FormDigestValue
  var __REQUESTDIGEST;
  var rootUrl = location.protocol + "//" + location.host;

  var contextInfoPromise = $.ajax({
    url: rootUrl + "/_api/contextinfo",
    method: "POST",
    headers: {
      "Accept": "application/json; odata=verbose"
    },
    success: function(data) {
      __REQUESTDIGEST = data.d.GetContextWebInformation.FormDigestValue;
    },
    error: function(data, errorCode, errorMessage) {
      alert(errorMessage);
    }
  });

  // Once we have the form digest value, we can create the subsite
  $.when(contextInfoPromise).done(function() {
    $.ajax({
      url: rootUrl + "/_api/web/webinfos/add",
      type: "POST",
      headers: {
        "accept": "application/json;odata=verbose",
        "content-type": "application/json;odata=verbose",
        "X-RequestDigest": __REQUESTDIGEST
      },
      data: JSON.stringify({
        'parameters': {
          '__metadata': {
            'type': 'SP.WebInfoCreationInformation'
          },
          'Url': opt.siteUrl,
          'Title': opt.siteName,
          'Description': opt.siteDescription,
          'Language': 1033,
          'WebTemplate': opt.siteTemplate,
          'UseUniquePermissions': opt.uniquePermissions
        }
      })
    });
  });

}; // End $.fn.Site.create

With the function set up this way, I can call it something like this:

$().ProjectName.Site.create({
  siteUrl: "mysite",
  siteName: "My Site's Name",
  siteDescription: "This is the description that explains how to use this site.",
  siteTemplate: "sts",
  uniquePermissions: false
});

I like to publish stuff like this when I figure it out. We’re all in this together and we shouldn’t need to figure things out more than once.

Thanks Matt and Rob!

Getting Around SharePoint’s Threshold Limits for Large Reference Lists

In SharePoint 2007, we could build lists that contained as many items as we wanted and access them in any way we wanted. We may have done stupid things that were bad for server performance, but if we knew what we were doing there were few limits. We had the mythical “2000 item” rule of thumb (which had little basis in reality in many, many cases) but otherwise it was up to us. (See: Plan for software boundaries (Office SharePoint Server))

In SharePoint 2010, Microsoft introduced threshold limits to protect us from ourselves. This seemed counter intuitive to me, since with the upgrade to SharePoint 2010, one also had to go to 64 bit architecture and put a heck of a lot more iron behind the SharePoint farm. While we could potentially store 30,000,000 items in a list (30 million!), we had a list view threshold of 5000 items. (See: SharePoint Server 2010 capacity management: Software boundaries and limits)

SharePoint 2013 maintains similar limits to 2010, with 5000 items the limit for a list view. (See: Software boundaries and limits for SharePoint 2013)

List View ThrottlingSomehow, as technology has moved forward – significantly – we’ve got more limits.

5000 items is way too many to ever show in a list view, but it may not be if you want to do some client side processing. It doesn’t matter if you’re trying to build a truly bloated, Bad Idea list view or request data using REST, you’re stuck with that 5000 item limit.

But what if you know what you are doing and the 5000 item limit doesn’t work for you? I’ve written in the past about why we shouldn’t change some of the threshold limits (e.g.,  The SharePoint 2010 “List View Lookup Threshold” and Why We Don’t Change It).

If we’re working on Office365, we simply can’t change the limits – Microsoft gets to decide what they are. Sometimes those limits change without notice, too, so it’s truly out of our hands.

Well, what does all this add up to? Let’s take a specific example.

I needed to provide auto complete functionality in an InfoPath form. It was the classic scenario: we had a list of [in this case] 19,000+ cities and towns and we needed a good UX for entering selections into the form. We run into this sort of thing with data like cities and towns all the time. There are too many choices for a dropdown to make any sense, and SharePoint doesn’t offer up any better alternatives. jQueryUI’s autocomplete function is a perfect solution for this sort of thing.

The data was in a spreadsheet, and it’s easy to upload data from a spreadsheet to a SharePoint list. Bingo, bango, done, right? Well, no. It’s impossible to upload data from a spreadsheet *and* index the column. We need to index the column so that we can make type of requests requests that we need for autocomplete – basically, give me all of the items that begin with or contain this string – or else we run into the 5000 item threshold error on our requests.

No problem! We’ll just upload the data and *then* index the column. Not so fast, mister. When you try to index the column you run into – you guessed it – the 5000 item limit. No indexee, no laundry.

So seemingly we’re stuck. But wait – we can just create the list in the UI, add the index, and paste all 19,000 items into the Brave New World of SharePoint 2013′s “data sheet view” aka “Quick Edit”. Sadly, when I tried to paste in more than a few hundred items, the browser hung on me. This was on Office365, and I tried several different browsers. SharePoint Online seems to prefer nibbles to big bites of data. Unless I spent days just doing the pasting, this was never going to happen.

In this case, I decided to simply store the data in a text file containing JSON rather than trying to force it into a list. Thanks to @bpmccullough for the suggestion on Twitter.

The data I originally had received for the sities and towns was in a CSV file. I found a nice little site that would convert the CSV format to JSON (bookmark this one; you’ll need it in this JSON-oriented world).

Once I had the JSON file uploaded to a Document Library, the code below is what I used to set up the autocomplete. We wanted the autocomplete to allow multiple choices, so there’s a little monkeying around to enable that. It wasn’t tremendously peppy (19,000 cities, after all), but it worked. Remember, kids: this is an example. Don’t expect to drop it into your page and have it work.

var citiesAndStates = [];

// Get the City and State data from the file with JSON data
$.getJSON("/Shared%20Documents/CityState.txt", function(data) {
  var results = $(data);
  // Push the data into an array which is appropriate for jQueryUI autocomplete
  citiesAndStates = ($.map(results, function(item) {
    return {
      label: item.State + " - " + item.City, // Show "State - City" [e.g., MA - Boston] for selection
      value: item.City + ", " + item.State // Show "City, State" [e.g., Boston, MA] upon selection
    }
  }));
});

// When the field is available and gets focus, set up the autocomplete behavior
//ctl00_ctl42_g_6069846d_1b7f_4890_b767_2bdc15d2b133_FormControl0_V1_I1_S15_I4_T5
$(document).on("focus", "input[id$='FormControl0_V1_I1_S15_I4_T5']", function() {
  if ($(this).data("autocompleteSet") === undefined) {
    $(this).data("autocompleteSet", true);

    $(this)
    // Don't navigate away from the field on tab when selecting an item
    .bind("keydown", function(event) {
      if (event.keyCode === $.ui.keyCode.TAB && $(this).data("ui-autocomplete").menu.active) {
        event.preventDefault();
      }
    }).autocomplete({
      source: function(request, response) {
        // Delegate back to autocomplete, but extract the last term
        response($.ui.autocomplete.filter(citiesAndStates, extractLast(request.term)));
      },
      minLength: 3,
      focus: function() {
        // Prevent value inserted on focus
        return false;
      },
      select: function(event, ui) {
        var terms = split(this.value);
        // Remove the current input
        terms.pop();
        // Add the selected item
        terms.push(ui.item.value);
        // Add placeholder to get the semicolon-and-space at the end
        terms.push("");
        this.value = terms.join("; ");
        return false;
      }
    });
  }
});

function split(val) {
  return val.split(/;\s*/);
}

function extractLast(term) {
  return split(term).pop();
}

One note here: This approach basically violates my “put all data into a list so that end users can maintain it” rule. However, the approach I came up with was the best one for the situation. It’s still possible for a reasonably savvy (meaning “non-developer”) user to manage the data by downloading the file and using a JSON-aware editor.

The main thing was that we were able to set up something that worked, regardless what the Office365 limits may change to.

Office 365 Update Changes ‘Display Name’ on Required Fields

Observant SPServices user GregRT noticed something on Office365 today that I figured couldn’t be true. He posted the following in the discussions on the SPServices Codeplex site:

FYI – I had left my debug on.
Users were getting errors on there forms that a field could not be found by SPServices.
MSFT has changed the display name of required fields when it lands in the DOM. I had a cascade going from parentColumn ‘Division’ to childColumn ‘SalesCenter’ (both required fields) – working last week with the display names as ‘Divison’ and ‘SalesCenter’ … now when the form renders in the DOM the display names are ‘Division Required Field’ and ‘SalesCenter Required Field’ – no indication in the UI that this is modified.
Hope this helps someone!

My first reaction was to question whether this could be right.

For years, we’ve been able to reliably select a regular dropdown (select) easily by using the column’s Title. The markup has looked something like this (depending on SharePoint version):

<select id="Region_59566f6f-1c3b-4efb-9b7b-6dbc35fe3b0a_$LookupField" title="Region">

2014-01-23_14-39-44so we could use a jQuery selector like this:

var regionSelect = $("select[Title='Region']");

However, GregT is right. In one of my demo sites on Office365, when I set a the Region column to required I’m seeing this markup instead:

<select id="Region_59566f6f-1c3b-4efb-9b7b-6dbc35fe3b0a_$LookupField" title="Region Required Field">

2014-01-23_14-40-50I expect this will be a problem not just for everyone using SPServices, but for many custom scripts as well.

Not only does this become a breaking change, it’s just plain bad practice.

If you run into this issue, a quick fix solution would be:

var regionSelect = $("select[Title='Region'], select[Title='Region Required Field']");

It’s not enough for your selector to look for a Title which *starts* with ‘Region’; you might have a column called ‘Region2′ or ‘Regions’ as well, so you’d get false positives.

I’ll see if I can find out any more details on why this may have happened and whether it’s permanent. Ugh.

[notice]2014-01-24 8pm EST – Based on info from Christophe below and several others, the issue seems to arise somewhere between vti_buildversion:SR|16.0.2308.1208 and vti_buildversion:SR|16.0.2510.1204. You can check your version by going to  /_vti_pvt/buildversion.cnf in your Offic365 tenant. See: http://corypeters.net/2013/07/getting-the-product-version-for-sharepoint-online/[/notice]

[notice]2014-01-24 11pm EST – The PG reached out to me and they are investigating the issue. I’ll post more info as I get it.[/notice]

[notice]2014-01-31 9am EST – Based on the information I’ve gotten from the PG so far (not a lot), I’m going to assume this is a permanent change. The ostensible reason, as suggested by several people in the comments below, is to improve accessibility using screen readers. It’s hard to argue with that, but it’s still an unfortunate change.

I’ve also checked with a few people running non-English tenants, and the titles are localized, like so:

  • Swedish: “Namn Obligatoriskt fält” or “Name Required Field”.
  • Russion: “RegSelect Обязательное поле” or “RegSelect Required Field”
  • etc.

I’ve also received reports (several below in the comments) that this issue is popping up with SharePoint 2010 after applying the December CU. More on that as I get further details.

Based on this, I’m getting a fix ready in the 2014.01 release and will try to get it out there shortly. Methinks it’s going to become a game of catch up from now on.
[/notice]

[notice]2014-02-03 12:40m EST - SPServices 2014.01ALPHA2 posted with a fix for the issue on Office365. As soon as I can get an example of how the issues arises in SharePoint 2010, I hope to have that fix as well. [/notice]

[notice]2014-02-19 SPServices 2014.01 released with fixes for every implication of these changes of which I am aware. If you’ve run into this issue, please upgrade!
[/notice]