New Release of Widget Wrangler

When you’re writing a widget in Angular 1.x, it’s possible to pass configuration information into the widget using the ng-init directive, as shown in this example. (Angular 2 isn’t ready for widgets yet since there’s no way to put multiple copies on the page; Microsoft is working with Google on a fix. Here’s a sample.)

That works fine in Angular, but what if you’re using some other framework? The Widget Wrangler has a feature, the ww-appBind attribute, that allows you to bootstrap your own widget; this allows pretty much any JavaScript framework. But then how can you pass in configuration information?

The answer came from colleague Brian McCullough, who contributed a new feature to the Widget Wrangler. I have to admit I’ve been kind of swamped at work lately; he submitted the pull request more than a month ago! Well today Brian’s new attribute, ww-appConfig, is released in version 1.02 of the Widget Wrangler.

Here’s an example:

<div>
<h1>Knockout Widget 1</h1>
<span data-bind="text: textboxLabel"></span>:
  <input data-bind="textInput: message, event: {keyup: messageChanged}" />
  <i>
    <span data-bind="text:messageLabel"></span>:
    <span class="secret" data-bind="text: message"></span>
  </i>

  <script type="text/javascript"
          src="pnp-ww.js"
          ww-appName="MyWidget"
          ww-appBind="myWidget.Load"
          ww-appConfig='{"textboxLabel":"Enter a secret message",
                         "messageLabel":"The secret message is"}'
          ww-appCss='[{"src": "style.css"}]'
          ww-appScripts='[{"src": "https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js", priority":0},
                          {"src": "script.js", "priority":1}  ]'>
  </script></div>

In this example, two labels are passed into ww-appConfig in JSON format.The Widget Wrangler passes the appConfig value to the appBind function, myWidget.Load(), which parses the JSON and makes it available to the Knockout application.

var myWidget = myWidget || {};

myWidget.Load = function (element, config) {
  myWidget.Config = JSON.parse(config);
  ko.applyBindings(new myWidget.vm(), element);
}

You can see the whole thing in action in this Plunk.

Thanks Brian, this is a great addition and your contribution was clean and ready-to-go!

HTML Templates and CSS in SharePoint Framework Apps

“The time has come,” the Walrus said,
“To talk of many things:
Of template files, cascading styles,
And bundles made of strings,
And why SharePoint is boiling hot,
And whether pigs have wings.”

Like many SharePoint developers of late, I’ve been exploring the SharePoint Framework (SPFx), doing experiments, and porting code over to the new web part model. Something that perplexed me at first is how to handle HTML templates.

On the client side, I mostly work in AngularJS 1.x (Angular 2 isn’t ready for web parts yet since it only allows one instance of an app to run on a page at a time). And we Angular developers just love our templates! So how to manage them in the SPFx development environment? This article will show you how, and it will also clarify the mystery of CSS modules, which end up being related to HTML templates.

Continue reading

ALM for Widget Solutions

Colleague and fellow SharePoint developer Brian McCullough asked a great question on Twitter:

tweetfrombrianc

This is such an important topic I thought it was worth more than a 140-character reply; hence this article. Whole books have been written on Application Lifecycle Management,and there are many facets beyond simple software deployment, but this article will focus on the baseline needs of a typical “widget” project:

  • Allow reliable and repeatable movement from a development environment to test and ultimately into production potentially across dozens or thousands of SharePoint sites
  • Support this not just once, but repeatedly as project versions are developed and released. If the project includes persistent data, this should be preserved (and perhaps enhanced) as part of the upgrade process

In a widget project, each “environment” may just be a couple of site collections; for example you could have site collections for dev, staging, and production all in the same tenant on farm. Since widgets run on the client side, there’s no need for them to interfere. If you’re on Office 365, you might want a First Release tenant to test your code with forthcoming updates to the platform while keeping your main staging and production environments on the standard release schedule.

Continue reading

Vantage Point Puzzler: Drive Synchronicity

Here’s a little puzzler based on a personal experience I had a recently. I had finally outgrown my backup drives, so I purchased two identical new ones online. When they arrived, I set about backing up my home server to both drives. I use Beyond Compare to make backups; while this is a wonderful file synchronization tool, in this case both drives were blank, so it was really just copying the files.

I unwrapped the first drive and began the backup. Then I unwrapped the second drive, but before I finished my cat came by with an urgent request, so it was maybe ten minutes later when I finished petting her and began the second backup. Also, on the second backup I forgot to exclude the recycle bin, so the second backup had several additional files compared with the first.

So of course I expected the first backup, with its significant head start, to finish first. Yet when I checked back in an hour or so, I was surprised to see the two backups were perfectly in sync! That is to say, they were copying the exact same files at the exact same rate, and ultimately they finished within a second of one another. Here’s a screen shot to show you what I mean:

Puzzler-01.01As you can see, both backups are exactly in sync.

THE QUESTION: Why did this happen?

HINT: It’s not a coincidence; I can reproduce it at will. It’s also related indirectly to the theme of my previous post!

New Performance Best Practices for SharePoint Online Portals

or, Avoiding the BLOB (and other) caches in SharePoint Online

SharePoint was designed to work best in relatively small farms on premises. A typical configuration has 2-4 web front-ends, so caching information on the web servers is a good strategy. In SharePoint Online, however, a typical farm has hundreds of web front-ends, and is shared by many tenants. As a result, the chance of finding cached content for any given tenant on any given server is greatly reduced, and server side caching is ineffective. That changes some key best practices for building SharePoint portals; in Office 365, it’s best to avoid SharePoint features that rely heavily on server-side caching.

An excellent session at Microsoft Ignite, Learn how to build a fast, responsive SharePoint portal in SharePoint Online, focused on this and other performance considerations in SharePoint Online. This article will call out key best practices to optimize portal solutions hosted in Office 365.

Continue reading

Roadmap to the Future of SharePoint

(cross-posted to the BlueMetal Blog)

This week Microsoft mapped out a bold new plan for SharePoint. Microsoft is investing heavily to modernize the product to make it work as well in the Device and Cloud era as it once did in when the Web was still shiny and new. This article will explain how these changes could affect your organization’s SharePoint plans and how you can start preparing.

FOSP-4Pillars

If you missed the announcement, this is a good place to start. Here are some of the highlights:

Continue Reading

Learning TypeScript: A Code Camp Adventure

Last weekend I had the pleasure of presenting a couple sessions on TypeScript at Boston Code Camp 25, one on my own and one with my good friend and colleague, Bob Goodearl. We’ve just posted the materials, which may be useful beyond the presentation.

TypeScript 101

This session covers the basics of the language. I tried to distill the whole thing into a set of code samples, inspired by the old “Got Dot Net” site from days of yore. You can find the Github repo here, including project folders for both Visual Studio Code and Visual Studio 2013.

TypeScript 102

This session delves into creating AngularJS 1.x applications in TypeScript. I started off with the simple example of a weather “widget”. A widget is a small application that runs independently on a page; in this case I used the Widget Wrangler library to place the widget on the page. Because it’s small and simple, you can easily see how to set up an Angular controller and service in TypeScript, and how to handle Angular promises.

After that, Bob Goodearl picked it up with a more advanced example that shows a hybrid Angular/ASP.NET MVC application with a WebAPI back-end service. Pointers to his code and the other session materials are here on his web site.

Please check it out and send feedback in the comments; thanks!

Widget Wrangler Webcast and New Release

(Cross-posted to Julie Turner’s blog, SharePoint Customization Veni, Vidi, Vici)

Here’s a quick update on the Widget Wrangler – the light-weight JavaScript framework that helps you build flexible widgets that can be used in SharePoint content editor web parts, add-in parts, or really pretty much everywhere.

WW-PnP-WebcastThe Widget Wrangler was featured in a webcast on Channel 9 today. The Office team’s Vesa Juvonen interviewed WW creators Julie Turner and Bob German, who explained the framework and demonstrated how to use it with AngularJS, jQuery, and plain old JavaScript. Please check it out!

Also today we’re pleased to announce the release of Widget Wrangler version 1.0.1. This new version is backward compatible with the old one; the new release includes:

  • CSS Support – Allows packaging CSS references from within your widget; the Widget Wrangler will efficiently load each CSS file once on each page, even if it’s referenced by multiple widgets
  • Multi-module support – Allows bootstrapping multiple AngularJS modules within a widget (thanks to Peter Wasonga for the feature suggestion; Peter writes widgets in Kenya)
  • A new TypeScript sample; the Widget Wrangler works the same with TypeScript or JavaScript; this is mainly useful to show how to develop an AnuglarJS widget in TypeScript
  • Improved/reorganized documentation

You can get the new release on our Github repo at https://github.com/Widget-Wrangler/ww. The Widget Wrangler is also a part of the Microsoft OfficeDev Patterns and Practices library, and will be updated there in the next PnP release.

Thanks to everyone for your interest and support, and happy widget writing!

Flexible SharePoint Development with Widget Wrangler

(Cross posted at Julie Turner’s blog, SharePoint Customization: Vedi, Vini, Vici)

What’s a widget, and why should I care?

In economics, a widget is a name for a generic gadget or manufactured good; on the web, a widget is a generic piece of web functionality running on a page. What makes widgets special is that, unlike controls in ASP.NET or directives in AngularJS, widgets are generally released separately from the web page that hosts them, and are often deployed by end users.

If you’re reading this blog, you probably know something about Microsoft SharePoint, and this might sound familiar. A widget is a lot like a web part, only much lighter weight. In fact, widgets can easily be hosted in content editor web parts, on a list form, in a SharePoint add-in, or outside of SharePoint. If you’re careful, you can reuse the same widget in all those contexts!

Continue Reading

How to read information in a SharePoint Person field via the REST API

A colleague of mine recently had a challenge reading data out of a SharePoint person field via REST and then rendering it in AngularJS. As it turns out, I had the same challenge recently and found the solution … so here it is!

If you simply read the person field, you’ll end up with the user ID, which isn’t too helpful. The key is to use the OData $expand option to join the user ID to the user information (stored in a hidden list in every site collection). Here’s a sample.

$http.get("https://<servername>/sites/doccenter/" +
            "_api/web/lists/GetByTitle('Documents')/items?" +
           "$select=Title,Customer,FileLeafRef,FileRef,UniqueId,Modified," +
                "Author/Name,Author/Title" +
            "&$expand=Author/Id" +
           "&$filter=Customer eq '" + item.CustomerName + "'" +
           "&$orderby=Title")
.then(function (response) {
    // Add the response data to the ViewModel
    vm.items = response.data.value;
})
.catch(function (response) {
   vm.message = "The list of documents could not be retrieved";
    console.log("error");
});

Now here’s the view that renders the author’s name. Notice that the person’s attributes are properties within the person object (Author in this case…)

<div class="row site-grid-row" 
         ng-repeat="item in vm.items">
    <div class="col-xs-12 col-sm-7 col-md-6 col-lg-6">
        {{item.Title}}
    </div>
    <div class="hidden-xs hidden-sm col-md-3 col-lg-3">
       {{item.Author.Title}}
    </div>
    <div class="hidden-xs col-sm-5 col-md-3 col-lg-3">
       {{item.Modified | date : 'medium' : '-0500'}}
   </div>
</div>

I hope someone else finds this helpful!