SPTechCon Austin 2015 Wrap-Up

A splendid time was had by all at the inaugural Austin, TX version of the venerable SharePoint Technology Conference, usually known as SPTechCon. There was a tangibly different energy in the air at this SPTechCon. I’m sure some of that had to do with the new venue, but there seemed to be a bit more to it than that.

My friends at BZ Media did a wonderful job – as always – with the conference. David Rubinstein, Stacy Burris, Katie Serignese (soon to be Katie Flash!), and the whole team really know what they are doing and it shows.

In addition to the two session I presented, I was honored to be a part of an “expert panel”, discussing ‘SharePoint at the Crossroads’. I think SharePoint always seems to be at some sort of crossroads, so there’s always a lot to talk about.

20150209_202805000_iOS

Photo courtesy Heather Newman (@heddanewman)

After hours, we had a meeting of the SharePoint beards and thought deep thoughts.20150210_223631000_iOS

Here are many of the speakers at the speaker party.

20150210_052836000_iOS

Photo courtesy Christina Wheeler (@cwheeler76)

And what would a trip to Austin be without a stop at Salt Lick? BTW, that dude sitting behind Joel is Chris Tomich. He was there all the way from Perth, Australia (via San Francisco, where he’s spending a few months). Chris is one of my SharePoint heroes (not to slight anyone else), and it was awesome to have the chance to spend a bunch of time with him in Austin.

20150211_140517000_iOS

Photo courtesy Joel Oleson (@joeloleson)

The ‘Q:

20150211_025706464_iOS

Oh, and I presented two sessions. Thanks to everyone who joined me for them. The slides are up on Slideshare if you’d like to take a look.

The session I did on Content Types was a new one for me, and I had an unbelievably large and engaged crowd. Clearly this is a topic area where there need to be more resources available.

SPTechCon SFO 2014 Wrap Up

SPTechConLogoAnother splendid time was had by all at the latest rendition of SPTechCon, this time in sunny (mostly) San Francisco at the Hilton Union Square. The BZMedia folks who put on SPTechCon are great people and both the San Francisco and Boston versions are on my list of favorite SharePoint events.

Announcing SPTechCon BostonIf you weren’t able to attend this one, you may still be interested in my slides. Face it, though: it’s much more fun to go to these events to watch me make a fool of myself in person. Consider, nay decide that you will be, attending the Boston SPTechCon coming up September 16-19, 2014.

I’ve posted them to SlideShare for your fun and enjoyment. Even though several of the sessions I did were repeats of previous performances, they continually evolve, so every deck always has some new goodies in it.

 

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!

InfoPath Forms with Master Page Applied or Script Enabled

InfoPath 2013Say what you will about InfoPath. It’s a dead technology, it’s not getting any Microsoft love, it’s only for the wealthy (Forms Services is only available only in Enterprise -level CALs of SharePoint), it has no future. I’ve heard all of these and more. That said, it’s a pretty solid technology and works. We can bemoan it’s future, but we can also use it today to Get Good Stuff Done.

All that said, InfoPath browser-based forms don’t do everything one might need. I’ve written in the past about the way my friend Marcel Meth (@marcelmeth) and I worked together to use jQueryUI’s autocomplete function to augment InfoPath’s functionality in my post Using SPServices with jQueryUI’s Autocomplete Function on InfoPath Forms in SharePoint.

I was trying to do this again in an Office365 tenant recently and ran into a roadblock. A similar method worked just fine when filling out a new form, but we also needed it to work with existing form data when we edited it.

By default, InfoPath browser-based forms open up in a “chrome-less” state. By that, I mean that they don’t use the master page so one doesn’t see any of the site branding or tools around the form on the screen. From a branding perspective, that can be annoying but tolerable. However, when one needs to add some additional script to the page, one needs that chrome. This should be something simple to implement, but lo, it is not.

I had an InfoPath form that worked great. One of the things I needed to work in it is a little bit of script which is similar to the one in my blog post above. In this case, the basic idea was to add some autocomplete functionality to a field on the form, choosing (in this case) from a list containing 19000 cities and towns. (Cities seems to be a pretty common use case; there are a lot of them and autocomplete works well.)

To implement the script in the form, I created a new aspx page and dropped an InfoPath Form Web Part on it to display the form. The InfoPath Form Web Part pointed to my InfoPath form and the appropriate Content Type and worked perfectly. I embedded a reference to the script I needed in a Content Editor Web Part (CEWP) and everything worked a charm. By adding a few well-placed links to that page on the site, it was easy to get there to create a new InfoPath item.

The problem came in when we wanted to edit an existing form. Because links to the form go to

_layouts/15/FormServer.aspx?XmlLocation=...

, I couldn’t get my script to run in the page. As I mentioned, the FormServer.aspx page doesn’t pick up the chrome or anything else from the master page, which was where I wanted to put the script references.

I found a great suggestion on StackOverflow to simply run some script in the master page which changes the destination of links to the FormServer.aspx page. The posts didn’t give all of the details on how to do it, but I whipped something up pretty quickly.

//Rewrite Form Links to Open in Custom Page
$("a.ms-listlink[href*='/sites/Projects/Sales Orders']").each(function() {
  var formFileName = $(this).attr("href");
  var formServerUrl = "/sites/Projects/SitePages/Manage%20Sales%20Orders.aspx";
  $(this).bind("click", function(e) {
    e.preventDefault();
    var destination = formServerUrl + "?XmlLocation=" + formFileName + "&Source=" + location.href;
    location.href = destination;
  });
});

The script worked, in that it rewired all of the existing links to the FormsServer.aspx page correctly, sending me to a link that looked something like this, which was basically what I wanted:

https://domain/sites/Projects/SitePages/Edit%20Sales%20Order.aspx?XmlLocation=/sites/Projects/Sales%20Orders/SO1.xml&Source=https://domain/sites/Projects/

Unfortunately, the InfoPath Web Part then showed the error below.

Error Loading InfoPath Form

Error
There has been an error while loading the form.
Click Try again to attempt to load the form again. If this error persists, contact the support team for the Web site.

Click Close to exit this message.
Hide error details
XmlLocation and XsnLocation have both been set to non-empty values. It is an error to set both to non-empty values. Set XsnLocation to open a new copy of the form template. Set XmlLocation to open the xml file corresponding to an existing InfoPath document.

There had to be some way to pass the XmlLocation to the InfoPath Web Part successfully.

The trick turned out to be pretty simple, but I don’t know if I ever would have gotten to it. Luckily I have friends in far away places. John Liu (@johnnliu) in Sydney, Australia saw my #SPHelp on Twitter which pointed to my query on the MSDN Forums. (John’s a newly awarded MVP, so congratulations to him! Well deserved.)

1-13-2014 10-39-33 AMJohn’s suggestion seemed cryptic at first. (Hey, he was limited to 140 characters on Twitter.) I was passing in the XmlLocation, so why wasn’t it working?

After some thought (OK, a lot of thought), I decided to try something which seemed crazy. I created a new page and dropped an InfoPath Form Web Part on it, but I didn’t configure it at all. It looked like this on the page:

Unconfigured InfoPath Form Web PartThis seemed to be asking for trouble, right? Without configuring the Web Part, how would it work?

But I tried my URL with this page, and voila, it worked!

The issue with the first page was that it was configured to point to the XSN file for the InfoPath form. By omitting that configuration, the InfoPath Form Web Part was open to discussion about what to load.

As far as I know, this isn’t documented *anywhere* on the InterWebz. At least I couldn’t find it with my Bingling skillz.

Now I have two pages: New Sales Order.aspx which has the InfoPath Form Web Part configured as usual, and Edit Sales Order.aspx with the InfoPath Form Web Part not configured. Going to New Sales Order.aspx with no XsnLocation or XmlLocation on the query string loads the form to create a new item. Going to Edit Sales Order.aspx with the XmlLocation on the Query string opens an existing form for editing.

SharePoint Saturday New Hampshire (SPSNH) and SharePointFest Chicago 2012 Follow Up

Last week was a busy one for me, not so much with client work (though I managed to get a lot of that in, too), but with speaking at SharePoint events.

On Saturday, September 22, I was honored to deliver one sixth of the sessions in the keynote slot which kicked off the day. My session was called Getting Started with SharePoint 2013 Development. My goal with the session (it was the Standard development session to Bob German’s Advanced session) was to give an overview of what I see as some of the big changes that developers can expect when they start working with 2013. Rather than try to cover every nook and cranny (or even a large portion of them), I tried to give some links to articles out in the blogosphere that I thought gave good overviews of some of the topics. Thanks to people like Eric Shupps, Randy Drisgill, and others – I pointed to their content for later reading.

SharePointFest Chicago 2012On 25 September at SharePointFest Chicago, I was lucky to be able to present a full day workshop called SharePoint Design Essentials with the great Kyle Schaeffer (@kyleschaeffer). Watching Kyle do the design stuff he does live is a sight to see. Make time for it someday if you have any interest in SharePoint design at all. Kyle’s posted the main slide deck we used over on his blog. For the jQuery section, I did an abbreviated version of my A jQuery Primer for SharePoint slides from SharePointFest Denver.

My first regular session in Chicago was one that I’ve been doing different versions of over the last year or so-called Flying in the Cloud: New Ways to Develop for SharePoint. It’s different every time because I am always adding new examples based on the client work I’ve been doing. It’s gotten a bit long in the tooth, and it’s probably time to retire it. To me it’s not a new way of working, but with SharePoint 2013 coming along with its new app model, it’s becoming almost fashionable to use things like jQuery, Web Services, DVWPs, XSL, and CSS. You know, that “no code” stuff.

If you’re interested in the demos I showed, I’ve packaged them into a couple of WSPs which you can download and instantiate in your own environment if you’d like. Additionally, for each of the examples, I’ve done other blog posts which describe what I did and how they work, along with the code. If you can’t find the posts, feel free to ping me via the contact for or on Twitter (@sympmarc) and I can shoot you a link for what you’re looking for.

Finally, I did a session at SharePointFest Chicago called SharePoint Solutions with SPServices. It’s a live tour of the SPServices site, along with some demos from my inner sanctum: the WSS site where I do all of the development for SPServices. No slides, no net. I couldn’t find my HDMI-VGA adapter, but thanks to the very nice gentleman in the second row who loaned me his laptop, we managed to cover just about what I would have from my local VM. If you attended that session or you just have questions about SPServices, please post them in the SPServices Discussions on Codeplex.