ASP.NET, ES2015, React, SystemJS and JSPM

I’ve started investigating a relative newcomer to the JavaScript library, but one that is making a lot of noise. That library is React. But when I combined this with ASP.NET, I found the build processes confusing. There just isn’t a good recipe out there that allows you to write React/JSX components in ECMAScript 6 and get anything like the debugging you want. You lose the source map and any association with the actual source – not too good for the debugging environment. So how do you handle this?

Let’s rewind a bit.

What is React again? It’s a component technology. It occupies the same space as Polymer in that respect, although with vastly differing implementation details. It handles web-based components. It’s got various advantages and disadvantages over other component technologies, but it does the same thing at the end of the day.

I’m not going to go over yet another React tutorial. Really, there are plenty of them even if you don’t know much web dev, including tutorials on React and ES6.

Why am I learning them? Isn’t Polymer enough? Well, no. Firstly, React and Flux are a framework combination that I wanted to learn. I want to learn it mostly because it isn’t MVC and I wanted to see what a non-MVC framework looked like. Flux is the framework piece and React provides the views. Then there are things like React Native – a method of making mobile applications (only iOS at the moment) out of React elements. It turns out to be extremely useful.

As a module system, I like to use jspm. It’s optimized for ES6. So that was my first stop. Can I use jspm + ES6 + JSX + React all in the same application. Let’s make a basic Hello World React app using an ASP.NET based server in Visual Studio.

Step 1: Set up the Server

There really isn’t anything complicated about the server this time. I’m just adding Microsoft.AspNet.StaticFiles to the project.json:

{
  "webroot": "wwwroot",
  "version": "1.0.0-beta5",

  "dependencies": {
    "Microsoft.AspNet.Server.IIS": "1.0.0-beta5",
    "Microsoft.AspNet.Server.WebListener": "1.0.0-beta5",
    "Microsoft.AspNet.StaticFiles": "1.0.0-beta5"
  },

This isn’t the whole file, but I only changed one line. The Startup.cs file is similarly easy:

using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;

namespace WebApplication1
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseStaticFiles();
        }
    }
}

This gets us a web server that serves up the stuff inside wwwroot.

Step 2: Install Libraries

Next is jspm. Run jspm init like I have shown before. Then run:

jspm install react npm:react-dom jsx

This will install the ReactJS library and the JSX transformer for us. I’m using v0.14.0-beta1 of the ReactJS library. They’ve just made a change where some of the rendering code is separated out into a react-dom library. That library hasn’t made it into the JSPM registry yet, so I have to specify where it is.

Step 3: Write Code

First off, here is my wwwroot/index.html file:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World with React</title>
</head>
<body>
    <div id="root"></div>

    <script src="jspm_packages/system.js"></script>
    <script src="config.js"></script>
    <script>System.import("app.js!jsx");</script>
</body>
</html>

Note the !jsx at the end of the System.import statement. That tells SystemJS to run the file through the JSX transformer first. Now, let’s write wwwroot/app.js:

import React from "react";
import ReactDOM from "react-dom";

class HelloWorld extends React.Component {
    render() {
        return (<h1>Hello World</h1>);
    }
}

ReactDOM.render(<HelloWorld/>, document.getElementById("root"));

Don’t try this on any version of React prior to v0.14.0-beta1. As I mentioned, there are two libraries now – react for creating react components and react-dom for rendering them. You need both.

Step 4: Debug Code

This is a debuggers dream. I can see the code and the DOM side-by-side in the browser:

blog-08132015-1

Yep – that’s the original code. The JSX code has been transformed into JavaScript, but the ES6 code is right there. That means I can alter it “in-situ”, set break points, and generally work with it. If an exception occurs, it points at the original source code.

I wouldn’t want to ship this code. When you look at it, this small HelloWorld project loads 2.8MB and over 230 requests with a delay of 4.4 seconds (on localhost!) – just to get one React component rendered. I’d definitely be using Webpack or Browserify on a production site. But this is great for debugging.

Step 5: Code Control – Separate Components

Let’s say I wanted to give HelloWorld its own file. Code organization is important. It’s realatively simple with SystemJS. Just place the following code in wwwroot/components/HelloWorld.js:

import React from "react";

export default class HelloWorld extends React.Component {
    render() {
        return (<h1>Hello World</h1>);
    }
}

This is a copy of the original code, made into an ES6 module. Now I can alter the app.js file accordingly:

import React from "react";
import ReactDOM from "react-dom";

import HelloWorld from "./components/HelloWorld.js!jsx";

ReactDOM.render(<HelloWorld/>, document.getElementById("root"));

Final Notes

The Visual Studio editor is not doing me any favors here. I get errors all over the place. However, I can use this same technique in Visual Studio Code (which handles this syntax better), Atom and other places. This, however, is a great step towards debugging React code in a browser.

Moving from Bower to NPM

The “definitely not the” node package manager (npm) has recently moved up a major version to v3.0 and in the process has signalled its intent to start handling client-side packages. It supports any old git repository so the benefit of bower is basically gone now. It’s time to stop using two package managers and standardize on one.

There are three things I need to do. Firstly, I need to figure out how to get packages that aren’t in the npm package repository yet. Secondly, I need to handle my standard gulp recipe for building the library area. Finally, since I need to do extra stuff to the polymer package before using it, I need to adjust the build process for Polymer.

1. Handling Non-Repository Packages

npm has a bunch of ways you can handle non-repository packages. You could run your own repository – which is probably overkill for most projects. You can also install a .tgz or .zip file either locally or from a URI. You can also install from GitHub.

A quick warning – the first time you install from github, it will ask you for verification. On Windows, this was painful. Answering the questions and continuing then returning and re-running the command worked for me.

Polymer is not in the npm registry. There is a package called polymer – but it’s something different. There are also lots of things dealing with Polymer, but not polymer itself. Let’s install Polymer with this command:

npm install --save github:Polymer/polymer

As of this writing, it will install v1.0.5 of Polymer – exactly the latest version. In the package.json, it looks a little different. Here is the top of my package.json file:

{
  "version": "1.0.0",
  "name": "AspNetPolymer",
  "private": true,
  "dependencies": {
    "Polymer": "polymer/polymer",
    "font-awesome": "^4.3.0",
    "webcomponents.js": "^0.7.2"
  },

Note that I’ve moved the packages from bower.json to the package.json in the dependencies section. In the process, I had to rename the webcomponentsjs to webcomponents.js – you may encounter other naming differences. You can edit the package.json in Visual Studio and it will run a restore packages process when complete. Polymer is a little bit different though – it specifies the library name (Polymer) and the path on github.com. You can use private git repositories as well if you like (an alternative to NPM Enterprise, perhaps?).

2. Building the Libraries

Now that I’ve got the libraries on my machine in my source area, I want to move them into the right place on wwwroot. I use gulp for my build process, so here is the recipe:

gulp.task("libraries", function () {
    return gulp.src(plugins.npmFiles(), { base: "./node_modules" })
        .pipe(gulp.dest(config.dest + "/lib"));
});

The plugins.npmFiles() call is provided by gulp-npm-files – a module for this exact purpose. I’m using gulp-load-plugins to create the plugins object that loads this plugin.

3. Post-processing the libraries

Back to Polymer. Polymer is distributed as three files – polymer.html, polymer-mini.html and polymer-micro.html. I want to vulcanize these into one file. I use this to create a elements/polymer area:

/*
 * Build the vulcanized Polymer library that we need
 */
gulp.task("polymer", ["libraries"], function () {
    var polymerPath = "./node_modules/Polymer/polymer.html";

    return gulp.src(polymerPath)
        .pipe(plugins.vulcanize())
        .pipe(gulp.dest(config.dest + "/elements/polymer"));
});

The only real thing I had to do here was change the path to the Polymer library – it’s in node_modules instead of bower_components. I could build this into the libraries pipeline using gulp-filter (and look for **/polymer.html). The reduction in one task doesn’t seem worth it. Most libraries are distributed already built.

That’s pretty much all there was to it. If I’m developing using Aurelia, I will still use two package managers (jspm and npm), but most things can be developed with just one package manager now. The support for npm in Visual Studio is just a bonus to me.

A Polymer Image Carousel

I’m still working on my home page. What I want to do is create a Web Component (in Polymer – my preferred mechanism) to rotate images. I see this a lot on home pages and I think it would look cool. I’ve downloaded 4 fantasy wall papers in HD and resized them to be 1920×600 pixel resolution so that I have something to test this on. In an ideal world, these will change on a regular basis and have a nice transition between the different images.

On to the web component. I’ve adjusted my home page Areas/Main/Views/Home/Index.cshtml file to be the following:

@{ ViewBag.Title = "Home Page"; }

<div id="#Homepage">
    <div class="container-fluid">
        <div class="row">
            <dnd-carousel>
                <div class="s1"></div>
                <div class="s2"></div>
                <div class="s3"></div>
                <div class="s4"></div>
            </dnd-carousel>
        </div>
    </div>
</div>

@section htmlelements {
    <link rel="import" href="/jspm_packages/github/Polymer/polymer@0.8.0/dist/polymer.html">
    <link rel="import" href="~/elements/dnd-carousel.html">

    <style>
        html /deep/ .s1 {
            background-image: url("/images/backgrounds/homepage-s1.jpg");
        }
        html /deep/ .s2 {
            background-image: url("/images/backgrounds/homepage-s2.jpg");
        }
        html /deep/ .s3 {
            background-image: url("/images/backgrounds/homepage-s3.jpg");
        }
        html /deep/ .s4 {
            background-image: url("/images/backgrounds/homepage-s4.jpg");
        }
    </style>
}

The home page itself is relatively straight forward. The dnd-carousel will be my web component. Inside are four DIVs that I will rotate between.

Note that html /deep/ notation in the style sheet section. The child DIVs of the dnd-carousel element end up inside the shadow (or shady) DOM. This means that I have to cross that boundary between Shadow and Shady DOM to style those elements. I could have been explicit – adding a style property to the elements instead – especially considering that these are just images. The style sheet won’t be applied properly if I don’t include the html /deep/ syntax.

On to the web component. As normal, I’m putting my component under src/elements in a directory called dnd-carousel. There is a HTML file, a JS file and a LESS file. The basics are always the same. My HTML file is dnd-carousel.html:

<dom-module id="dnd-carousel">
    <link rel="stylesheet" href="dnd-carousel.css">
    <template>
        <div id="contentwrapper">
            <div id="carousel">
                <content></content>
            </div>
            <div id="carouselmarkers">
            </div>
        </div>
    </template>
</dom-module>

<script src="dnd-carousel.js"></script>

All I’ve changed here is the markup in the shadow DOM. I need a less file – dnd-carousel.less – to style this:

:host {
    display: block;
    width: 100%;
    height: 600px;
}

#contentwrapper {
    position: relative;
    width: 100%;
    height: 600px;
    left: 0;
    top: 0;

    #carousel {
        > ::content {
            display: block;
            width: 100%;
            height: 100%;

            div {
                display: none;
                width: 100%;
                height: 100%;
                background-repeat: no-repeat;
                background-size: cover;

                &.active {
                    display: block;
                    transition: all 1s ease-in-out;
            }
        }
    }
}

Note the active class. I’m going to add and remove this class from the elements as they come to the front and move to the back of my element. If the element is “active”, then it’s shown. If not, it isn’t.

Finally, I need a small Javascript file – dnd-carousel.js:

Polymer({
    is: "dnd-carousel",

    ready: function() {
        console.log("dnd-carousel: In ready()");
    }
});

With this markup, nothing is being shown. I can, however, check with the F12 Developer Tools that the right size and position is happening. Let’s start filling in the functionality:

Markers

In most of the carousels I see, there are numbers or blocks at the bottom – click on a number or block and you get taken to that image in the carousel. I’d like to emulate that. I added a carouselmarkers empty DIV into the HTML shadow DOM for this purpose. I now need to fill it in, which I do programatically:

    ready: function () {
        this.DIVSET = Polymer.dom(this).querySelectorAll("#carousel > div");
        if (this.DIVSET.length === 0) {
            console.log("No members - turning off");
            return;
        }

        for (var i = 1 ; i <= this.DIVSET.length ; i++) {
            var marker = document.createElement("span");
            marker.className = "marker";
            marker.innerHTML = i.toString();
            Polymer.dom(this.$.carouselmarkers).appendChild(marker);
        }
        Polymer.dom.flush();
    }

The first block gets all the DIVs that we passed in as children of the dnd-carousel and stored them for later. The next block constructs the elements I will need. Each digit will be added as a span with a class of marker.

Note the use of the Polymer.dom() API here. When you use this.$.id.appendChild(), it doesn’t add the style-scope necessary for using Shady DOM (which is the type of DOM used in webcomponents-lite.js that Polymer now uses). By utilizing the Polymer.dom() API for DOM interactions within the web component, that functionality gets implemented for us.

Of course, I’ll need some styling for this:

    #carouselmarkers {
        position: relative;
        top: -50px;
        width: 100%;
        text-align: center;
        z-index: 5;

        span.marker {
            border: 1px solid white;
            border-radius: 50%;
            color: white;
            padding: 0 4px;
            margin: 0 4px;
            cursor: pointer;

            &:hover {
                border: 1px solid #ff6a00;
                color: #ff6a00;
            }
        }
    }

This block is inside of the #contentwrapper at the same level as #carousel in the less file. I’ll also want to display the first carousel member to test this. Since I’ll be activating carousel elements, I may as well add a function to the Polymer object for that purpose:

Polymer({
    is: "dnd-carousel",

    ready: function () {
        this.DIVSET = Polymer.dom(this).querySelectorAll("#carousel > div");
        if (this.DIVSET.length === 0) {
            console.log("No members - turning off");
            return;
        }

        for (var i = 1 ; i <= this.DIVSET.length ; i++) {
            var marker = document.createElement("span");
            marker.className = "marker";
            marker.innerHTML = i.toString();
            Polymer.dom(this.$.carouselmarkers).appendChild(marker);
        }
        Polymer.dom.flush();

        // Reset the carousel active element
        this.activeElement = -1;

        // Display the first carousel
        this.displayCarousel(0);
    },

    // Private methods
    displayCarousel: function (idx) {
        if (idx === this.activeElement) {
            console.log("displayCarousel: Skipping as requested EL is the same as Active EL");
            return;
        }

        console.log("displayCarousel: displaying carousel element %d", idx);
        for (var i = 0 ; i < this.DIVSET.length ; i++) {
            var el = this.DIVSET[i];
            if (i === idx) {
                this.addClass(el, "active");
            } else {
                this.removeClass(el, "active");
            }
        }

        this.activeElement = idx;
    }
});

With this code and the styling applied, I can see the first element (the one labelled class="s1") and there will be the numbers 1 through 4 on top of the picture in white circles. If I roll over the numbers, they should turn orange. I’ve added some code from youmightnotneedjquery for addition and removal of classes as well:

    //#region CSS Class Handling Functions
    hasClass: function(el, className) {
        if (el.classList) {
            return el.classList.contains(className);
        } else {
            return new RegExp("(^| )" + className + "( |$)", "gi").test(el.className);
        }
    },

    addClass: function(el, className) {
        if (this.hasClass(el, className)) {
            return;
        }
        if (el.classList) {
            el.classList.add(className);
        } else {
            el.className += " " + className;
        }
    },

    removeClass: function(el, className) {
        if (!this.hasClass(el, className)) {
            return;
        }
        if (el.classList) {
            el.classList.remove(className);
        } else {
            el.className = el.className.replace(new RegExp("(^|\\b)" + className.split(" ").join("|") + "(\\b|$)", "gi"), " ");
        }
    },
    //#endregion

This is library code for me, but it’s so small that I include it where I need it.

Making the Markers Clickable

My next step is to make the markers clickable. The best way to do this is to add an event handler that calls my displayCarousel() method when the user clicks on the number elements. I can do this during the marker creation process in the ready() method. Here is the complete marker production loop:

        for (var that = this, i = 1 ; i <= this.DIVSET.length ; i++) {
            var marker = document.createElement("span");
            marker.className = "marker";
            marker.innerHTML = i.toString();
            Polymer.dom(this.$.carouselmarkers).appendChild(marker);

            marker.addEventListener("click", function (evt) {
                var newIndex = parseInt(evt.currentTarget.innerText);
                that.displayCarousel(newIndex - 1);
            });
        }
        Polymer.dom.flush();

The transition is a little harsh right now – I don’t think my transition CSS property is taking effect at the moment, but I can deal with that later.

Cycling the images

The other thing I want my carousel to do is to cycle through the images on a regular basis. For this, I want to add a property “interval” to my dnd-carousel, with a default timing of 30 seconds. Then I will use that in the ready() method to set up my event listener for transitioning the carousel. I’ll use the same displayCarousel() method to change the image. To handle the property, I have a new element within the Polymer object:

    properties: {
        interval: {
            type: Number,
            value: 30
        }
    },

You can check out the documentation on Polymer properties for more information. To set up the timer and call the displayCarousel() method, I added the following code to the ready() method:

        this.intervalTimer = setInterval(function () {
             var newIndex = (that.activeElement + 1) % that.DIVSET.length;
            that.displayCarousel(newIndex);
        }, this.interval * 1000);

I’ve already started tracking the active element (in this.activeElement), so all I need to do is increment the active element, adjust for the number of elements, then call displayCarousel().

Finishing off the Carousel

I did some more work before checking it in, but the basic functionality is there now. The things I did before checking in included:

  1. Highlighting the color marker when the image is shown
  2. Improving transitions between images by using opacity instead of display
  3. Some general code clean-up

You can get this code at tag cs-0.0.9. However, all the code is isolated to the src/elements/dnd-carousel directory, except for the view change on the home page.

Designing a Simple Polymer Web Component: Part 2 – Styling

In my previous post I created the foundation of my web component but it didn’t look how I wanted it to. Today I am going to finish off the web component visuals. Most of my work was with playing with the CSS. However, I bumped into some roadblocks that are worth highlighting.

Styling the content blocks

My initial CSS just had an embedded img and h1 selector. This is the wrong way to be selecting the stuff inside content and the Polymer documentation is quite explicit about it. Surroung the <content> block with a div that has a selector, then use a recipe. My characterName section became this:

.characterName {
    position: absolute;
    top: 70%;
    left: 0;
    width: 100%;
    height: 30%;
    text-align: center;
    vertical-align: middle;
    background-color: beige;

    &gt; ::content h1 {
        font-family: 'Segoe Script', cursive;
        margin: 2% 0 !important;
    }
}

Note the ::content – this is the selector nomenclature for the content block. I did something similar to the img tag as well so that it always fit within the characterImage content block.

Bootstrap, DOMReady and Scripts

One of the things I wanted to do was to make the element square. The work is a simple one-liner in Javascript:

elem.style.height = elem.offsetWidth + "px";

Placing it at the right point in the code is critical. My first attempt did it in the scripts section of Index.cshtml with jQuery, like this:

$(document).ready(function () {
    $("dnd-gridcharacter").each(function (idx, elem) {
        $(elem).css({ height: $(elem).outerWidth() + "px" });
    });
});

This does not hit the encapsulation requirement I had set for myself. My component should not have to rely on external scripts in order for it to work properly. I also had a problem with resizing. If the external app resized my element, then the element should resize accordingly to keep the square shape. Setting the height once was not enough.

After some trial and error, I ended up with the following code in my dnd-gridcharacter.js file:

    //#region Global Event Listeners
    domReady: function() {
        this.windowResize();
    },

    windowResize: function() {
        this.style.height = this.offsetWidth + "px";
    },
    //#endregion

    //#region Lifecycle event handlers
    ready: function() {
        console.log("dnd-gridcharacter::ready: %s %s", this.localName, this.id);

        var that = this;
        // Add event handler for DOMContentLoaded
        if (document.readyState != 'loading') {
            this.domReady();
        } else {
            window.addEventListener('DOMContentLoaded', function () { that.domReady(); });
        }

        // Add event handler for window resize
        window.addEventListener("resize", function() { that.windowResize(); });
    },
    //#endregion

This code does not work by itself. Let me go through it first. I have two methods in the object that will be called when the page DOM is ready and when the window gets resized. To implement those, I add an event listener on the DOMContentLoaded event in the ready() method. ready() is a Polymer event that fires once the element has been created and had the shadow DOM fully populated.

So why didn’t it work? When I ran my page the size of the element was not set. I added a console.debug to print the this.offsetWidth to verify this. It was as if styling had not been rendered yet. Was I capturing the right event?

I tend to wander the Internet when this happens. In this case I went to the Mozilla Developer Network and started researching events. I started reading the description for the DOMContentLoaded event to ensure that I was indeed using the right event. At the top of the page is this warning:

blog-code-0417-2

The implication is less than clear here. If you don’t have a script at the bottom of your page, then the DOMContentLoaded event is fired early – before the page is fully rendered out. The DOM is there but not the styling. I wanted details of the styling.

The way to fix this is to include a script at the bottom of the main page. I wanted to bring in Bootstrap and their grid component anyway. Bootstrap has a dependency on jQuery. Use jspm install bootstrap to bring in the library and include it in the Layout.cshtml file:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="~/jspm_packages/npm/font-awesome@4.3.0/css/font-awesome.min.css" rel="stylesheet">
    <link href="~/jspm_packages/github/twbs/bootstrap@3.3.4/css/bootstrap.min.css" rel="stylesheet">

    <!-- Required Polyfills -->
    <script src="~/jspm_packages/npm/webcomponents.js@0.6.0/webcomponents-lite.min.js"></script>

    <!-- Components used -->
    @RenderSection("htmlelements", required: false)

    <title>@ViewBag.Title</title>
</head>
<body>
    <div class="flex-container">
        @RenderBody()
    </div>

    <!-- Requirement for BootStrap -->
    <script src="~/jspm_packages/github/components/jquery@2.1.3/jquery.min.js"></script>
    <script src="~/jspm_packages/github/twbs/bootstrap@3.3.4/js/bootstrap.min.js"></script>

    <!-- Page Scripts -->
    @RenderSection("scripts", required: false)
</body>
</html>

Relative Font Size

Another task that took me a while to figure out was the sizing of the character name. The dnd-gridcharacter element can be any height, so I had to account for the size differences. A quick search on Stack Overflow brought up eight questions that fit my criteria, each – of course – with a slightly different variation. I went for the simplest, which is to calculate the font size. To do this, I used the following code in the resizeWindow() method of my dnd-gridcharacter.js file:

    windowResize: function() {
        // Make the object square by setting height == width
        this.style.height = this.offsetWidth + "px";

        // Make the character name font fit inside the containing DIV
        var textHeight = Math.floor(this.offsetHeight * 0.12);
        Polymer.dom(this).querySelector("h1").style.fontSize = textHeight + "px";
    },

You may be wondering why 0.12 as the multiplier? The character name section is 30% of the overall component height. I want to allow for some padding around the text (around 2% of the room), which brought it to 26% of the overall component height. I wanted to allow for two lines, like in my example, which brough it to 13%. When I looked at the result, I decided that the line height may be a little different than the font size, so I reduced it just a little more. It’s not very scientific but the result looks good.

A quick note about the Polymer.dom call. Polymer needs to deal with the Shadow DOM and, for those browsers without Shadow DOM, a fake version that they call “Shady DOM”. The Polymer.dom() abstracts the difference away from you, so it works in whatever browser you need. It has a restricted subset of functions for finding and manipulating the DOM – I’m sure that will be expanded over time so that you can do anything in the Polymer.dom() API that you can in the regular DOM API. There are some caveats with using Polymer.dom() to manipulate the DOM, so make sure you read the documentation first.

Icons and Observers

The last thing I needed to do was to implement the icons. I’ve got my icons from the Windows 8 Metro Invert Iconset. This set is large and has all sorts of things. I’m not sure I’ll stick with it. I’ve downloaded two icons – one for sharing and one for groups. Both icons are PNG format and 128x128px. I added them into my dnd-gridcharacter.html file like this:

<dom-module id="dnd-gridcharacter">
    <link rel="stylesheet" href="dnd-gridcharacter.css">
    <template>
        <div class="content-wrapper">
            <div id="partyIcon"><img src="/style/icons/group.png"></div>
            <div id="shareIcon"><img src="/style/icons/share.png"></div>
            <div class="characterPicture"><content select="img"></content></div>
            <div class="characterName"><content select="h1"></content></div>
        </div>
    </template>
</dom-module>

<script src="dnd-gridcharacter.js"></script>

Note that I have changed the class to an ID for the partyIcon and shareIcon DIVs. This is because I want to reference them in code explicitly. I’ve also changed the CSS to match this change. I have not wired the logic up at this point, and I had to add a little bit of CSS to get the icons to be resized and the right size.

I want to ensure that the party and share icons only appear by default when those attributes are set. To do this, I’ve added a couple of famous characters to my grid in Index.cshtml:

@{ ViewBag.Title = "Home Page"; }

<h1>Home Controller</h1>

<div class="container-fluid">
    <div class="row">
        <div class="col-lg-2 col-md-2 col-sm-4 col-sx-12">
            <dnd-gridcharacter party shared>
                <img src="/style/avatars/gnome/wizard.jpg">
                <h1>Finckeewack<br>Clusterbomb</h1>
            </dnd-gridcharacter>
        </div>
        <div class="col-lg-2 col-md-2 col-sm-4 col-sx-12">
            <dnd-gridcharacter party>
                <img src="/style/avatars/personal/elminster.png">
                <h1>Elminster<br>Aumar</h1>
            </dnd-gridcharacter>
        </div>
        <div class="col-lg-2 col-md-2 col-sm-4 col-sx-12">
            <dnd-gridcharacter shared>
                <img src="/style/avatars/personal/drizzt.jpg">
                <h1>Drizzt<br>Do'urden</h1>
            </dnd-gridcharacter>
        </div>
    </div>
</div>

@section htmlelements {
    <link rel="import" href="/jspm_packages/github/Polymer/polymer@0.8.0/dist/polymer.html">
    <link rel="import" href="~/elements/dnd-gridcharacter.html">
}

I’ve downloaded some different images to represent them. Elminster should have the party icon but not the shared icon and Drizzt should have the share icon but not the group icon.

Right now, I don’t know when, or indeed IF, the observers are called. To determine this, I put a console.log statement to find out:

blog-code-0417-1

Based on the console, the observers are called before the element is “ready” even on element creation, so I don’t have to do any work in the ready() method. The observer just needs to change the display property based on whether the newValue is true or not, like this:

    //#region Property Observers
    partyObserver: function (newValue, oldValue) {
        this.$.partyIcon.style.display = newValue ? "block" : "none";
    },

    sharedObserver: function (newValue, oldValue) {
        this.$.shareIcon.style.display = newValue ? "block" : "none";
    }
    //#endregion

Note the use of this.$ – this is a collection of the elements with IDs in my component and I can use this to easily identity the various blocks in my shadow DOM.

The Final Result

The final result looks like this on screen:

blog-code-0417-1

This is pretty much what I envisioned when I first created the powerpoint version (for reference – I’ve shown it again below):

blog-code-0416-2

The difference is that I’ve done all the code and the component is fully responsive to changes in sizes and can be instantiated as many times as I want. I may need to do more to implement other items in my application, but this is looking good now.

This is probably a baseline web component for me. It isn’t the very basic version that I implemented in the polymer-helloworld component, but it doesn’t have a lot of bells and whistles either. As a result, I’ll be able to use this as a model going forward.

Got an idea on how to improve my web component? Let me know in the comments.

I’ve checked in my work on this web component using tag cs-0.0.4.

Designing a simple Polymer Web Component: Part 1 – Setup

I thought I’d go through my design process for a web component. There are three pieces to a web component. The HTML markup, the styling and the Javascript to implement it. My side project needs several widgets that I will implement in web components. Getting a good handle on the design process will assist when it comes to that.

Step 1: Have a good idea on what you want to do

It seems silly, but do you know what you want the end product to look like? My top level page is going to be the cast of characters that I have access to. Each one can be a member of a party and/or shared with other people. I would like it to have a picture, the characters name and indicators for whether it is a member of a party or shared. My first attempt is to borrow images from the Internet to design where things are going:

blog-code-0416-2

This was done with PowerPoint – I had it handy. However, you can use any tool you care to. Got gimp? An excellent choice. How about paint.net? Another excellent choice. Just use what you know and have access to.

The idea is that the left hand top icon indicates that the character is a member of a party. The right hand top icon indicates that it is shared. The picture in the middle will either be a default one based on the characters race and class or I will allow the user to upload one. One of the friends I game with draws characters for each of us. Finally, the name of the character is at the bottom. I should be able to click on the whole thing and get the same action – the character sheet is opened. If I roll over the two icons at the top I should be able to see that it is shared (and with whom) and who else is in the party.

Decide on a rough layout

Now that I have the vision in my head, it is time to lay it out. Well, almost. The next step is to take all the imagery out of the equation and decide what blocks go where. I do this in PowerPoint as well, just to get it fixed in my mind. It helps when I am doing the style sheet. Here is what I drew up for my character grid component:

blog-code-0416-1

I’ve got a square block which will be dependent on the size of the screen – I’m a fan of responsive design. The icons will be 20% of the size of the block, the character will be 60% of the size. At the bottom is a section for the name of the character.

Decide how to lay out the HTML

When I include this character on the grid I want to specify whether it has the icons, the location of the picture and the name of the character. Something like this:

<dnd-gridcharacter party shared>
    <img src="/avatars/standard/dwarf/cleric.png">
    <h1>Finckeewack<br>Clusterbomb</h1>
</dnd-gridcharacter>

This layout provides everything I could potentially want from the component.

Produce the Template

The next step is to start lay down the template. I’m not going to worry about styling or interactivity at this stage – I just want to start producing the HTML. First of all, I create a directory under my src/elements directory for the element. Then I produce the dnd-gridcharacter.html file:

<dom-module id="dnd-gridcharacter">
    <link rel="stylesheet" href="dnd-gridcharacter.css">
    <template>
        <div class="content-wrapper">
            <div class="party-icon"></div>
            <div class="share-icon"></div>
            <div class="character-picture"><content select="img"></content></div>
            <div class="character-name"><content select="h1"></content></div>
        </div>
    </template>
</dom-module>

<script src="dnd-gridcharacter.js"></script>

Here I just used the outline I prepared for the polymer-helloworld.html file and inserted what I think will be my content. Everything is wrapped into a content-wrapper and then I have my four DIV areas to hold the four things I am interested in positioning.

I also need to add in a dnd-gridcharacter.js file that instantiates the web component:

Polymer({
    is: "dnd-gridcharacter",

    properties: {
        party: {
            type: Boolean,
            value: false,
            observer: "party-observer"
        },
        shared: {
            type: Boolean,
            value: false,
            observer: "shared-observer"
        }
    }
});

You saw the is: property in the Polymer initialization object when I was showing off the polymer-helloworld web component. However you may not have seen the properties. This has changed since the Polymer 0.5 days. In the prior version you could declare properties in the polymer-element element in the HTML file. Properties are now explicitly defined in the Javascript, along with their type and default value.

I also get to decide what type of data-binding I want. Inbound data-binding is implemented by using an observer. The string is the method to be called when a change is noticed. Outbound data-binding is implemented by using notify. In this case, an event is fired when the value of the property changes. You can also do two-way data-binding. Just implement both the observer and notify.

For this application I’m only interested in the inbound data-binding. I won’t be changing the state of party or shared myself. In order to implement the inbound binding, I’ll need to define two functions:

    partyObserver: function (newValue, oldValue) {
        // ... change the party icon according to newValue
    },

    sharedObserver: function (newValue, oldValue) {
        // ... change the shared icon according to newValue
    }

These are defined inside the Polymer object just like is and properties.

Initial Styling

I also want to implement some initial styling based on my PowerPoint. It won’t be right the first go around but it will be something I can play with. I’ll put the stylesheet in dnd-gridcharacter.less:

.content-wrapper {
    display: block;
    position: relative;
    width: 100%;
    height: 100%;
    border: 1px dotted goldenrod;
    padding: 20px;
    background-color: teal;

    .party-icon, .shared-icon {
        position: absolute;
        top: 0;
        width: 20%;
        height: 20%;
        border: 1px dotted red;
        z-index: 5;
        background-color: white;
    }

    .party-icon {
        left: 10%;
    }

    .shared-icon {
        right: 10%;
    }

    .character-picture {
        position: absolute;
        top: 10%;
        left: 20%;
        width: 60%;
        height: 60%;
        z-index: 3;
        border: 1px dotted green;
        background-color:cadetblue;

        img {
            width: 100%;
            height: 100%;
        }
    }

    .character-name {
        position: absolute;
        top: 70%;
        left: 0;
        width: 100%;
        height: 30%;
        text-align: center;
        vertical-align: middle;
        background-color: beige;

        h1 {
            font-size: 36px;
            font-family: 'Segoe Script', cursive;
            color: #33;
        }
    }
}

This is most definitely the wrong CSS to be using. I’ve given each element a border color and a background. None of the icons or pictures are “there”. I’m hoping the positioning is somewhat good to go. What this does is give me a mechanism by which I can begin to alter the CSS within the browser so I can get it right.

A better designer than I would probably do this process differently. I’ve found I am terrible at understanding what CSS properties affect positioning and how they work when in a responsive display.

Checking it out

I’ve changed my Areas/Main/Views/Index.cshtml file to bring in an example of the work:

@{ ViewBag.Title = "Home Page"; }

<h1>Home Controller</h1>

<div style="width: 500px; height: 500px; position: relative">
    <dnd-gridcharacter party shared>
        <img src="https://placeimg.com/300/300/people/grayscale">
        <h1>Finckeewack<br>Clusterbomb</h1>
    </dnd-gridcharacter>
</div>
@section htmlelements {
    <link rel="import" href="/jspm_packages/github/Polymer/polymer@0.8.0/dist/polymer.html">
    <link rel="import" href="~/elements/dnd-gridcharacter.html">
}

Note that I’m using a placeholder image site to load an example image. I’ll replace that at a later data – it just isn’t important for me right now. Here is what the initial version looks like:

blog-code-0416-3

The good news is that it isn’t terrible. There are some things that are certainly wrong with it. Aside from the borders and colors (that I knew were going to be wrong) the image is the wrong size and in the wrong place, the text is the wrong size and the shared icon area is just not there – probably overlapping the party icon area.

Some things live to see another day. Tomorrow I’ll take a look at the debugging tools for CSS available in Chrome, add in some code to make multiple versions of the grid character so I can see how it scales and generally finish off the component.

Comparing Web Components: Part 3 – Bosonic and X-Tags

Aside from Polymer (which was relatively easy and definitely going in the right direction) there are two other libraries listed on the webcomponents.org website – Bosonic and X-Tags. In this article I will review each one and what it took to get them working.

TL;DR – I was disappointed in all the libraries. This may come off as my not understanding the libraries or just loving Polymer too much. I can live with myself for that.

X-Tags

I was actually disappointed in this library. I’m sure some people will get offended when I say this, but the X-Tag library is just a crude wrapper around the web components platform library (webcomponents.js) and does nothing more for me than the original vanilla javascript version. At least with the vanilla javascript version I could see what was happening. Not so fast on this one.

Firstly, there are things I could not get around. If I included webcomponents-lite.js, then I got an error in the x-tag-core library. No way around it – the current version of X-Tag doesn’t work with the current version of webcomponents.js. This made it unlikely that I will use X-Tag to start with.

Then there is the code. I set up a simple one page web component – it had a template, stylesheet and some Javascript. Here is the Javascript code:

        (function () {
            xtag.register('xtag-helloworld', {
                prototype: Object.create(HTMLElement.prototype),

                lifecycle: {
                    created: function () {
                        console.log("xtag-helloworld: lifecycle.created");
                        var tpl = document.getElementById("XTagHelloWorld").content;
                        this.appendChild(tpl.cloneNode(true));
                    }
                }
            });
        })();

Is this really any better than the vanilla JS version?:

(function () {
    // Find the template for this HTML element
    var template = document.currentScript.ownerDocument.querySelector("#noLibHelloWorld");

    // Create the prototype for the new HTML element
    var elementPrototype = Object.create(HTMLElement.prototype);

    // Set up lifecycle callbacks for the new HTML element
    elementPrototype.createdCallback = function () {
        // Create the shadow DOM and clone the template into the shadow DOM
        var shadow = this.createShadowRoot();
        shadow.appendChild(template.content.cloneNode(true));
    }
    document.registerElement("nolib-helloworld", { prototype: elementPrototype });
})();

In my eyes, this is practically identical. So what is the library buying me?

Finally, documentation – there is a single page of documentation. Not once does the page provide a complete end-to-end example. I did check out the examples in the x-tag github repo. Not one of the examples showed usage in a HTML Import – it was always a JS and CSS file together. Interesting, not one showed templates either – another core concept of web components.

Bosonic

The Bosonic library was doomed from the start. Rather than embrace web components (and utilize the polyfill), the Bosonic library decided to transpile the web components into a CSS and JS file that you could then include in your project. This is reasonable enough had they supported gulp – they don’t. This would actually add another step to my process:

  1. Turn the HTML/LESS/JS files into files appropriate for a HTMLImport
  2. Vulcanize the files so I can import them with one file
  3. Bosonize them so I can split them apart again

That extra step isn’t what I envisioned. The code is reasonable. For instance, in the case of the work I have been doing, here is the code:

        ({
            createdCallback: function () {
                var root = this.createShadowRoot();
                root.appendChild(this.template.content.cloneNode(true));
            }
        });

As with X-Tags, I can tie this back directly to the Vanilla JS version. Why do I need to do this scaffolding? Can’t the library detect I have a template and just do it? At least this library had support for templates and you could write the code in a single HTML file (although it was broken up for production usage).

In terms of documentation, I’d rate Bosonic as better than X-Tags but nowhere near as good as Polymer. The tutorial is a nice walk-through and introduces the major things you would need to do in digestible chunks, making it easy to get into Bosonic.

On the downside, I just don’t like their approach.

SkateJS

Given my disappointment with the former libraries, I decided to take a look elsewhere on the Internet to see if I could come up with anything comparable. SkateJS is a replacement for webcomponents-lite.js. Rather than use the W3C Web Components spec, it’s decided to use its own API.

The Verdict

There are really two answers here:

  1. If you don’t mind taking a dependency on a library including an API that isn’t stable yet and could change (in fact, it just did), then Polymer is probably your best bet. It does the scaffolding for you and has good documentation.
  2. If you care about the Polymer library dependency and the moving API target, take a dependency on the webcomponents-lite library and use the Web Components spec and Vanilla Javascript.

This is just my personal opinion. I highly recommend you do your own research. Take a simple component you are writing – maybe as a jQuery plugin or just a module of another app, and write it in each of the frameworks. You will figure out for yourself pretty quickly which one you prefer.

I’m going to take a bet that Polymer has gone through the major upheaval with the 0.8 release. Certainly, the information coming out of the project indicates this is so. There may be some refactoring to do when Polymer reaches 1.0, but it’s likely to be minimal. As a result, I’m taking that dependency on Polymer for my web components.

One thing to note about my project is that it is an ASP.NET MVC project; not a SPA project. As a result, the web components that I use are likely to be visual and relatively simple. I am not going to be using a multi-page router in a web component, for example. You should think about your own project and its needs when doing this research to ensure you get the best possible solution for your project.

Comparing Web Components: Part 2 – Polymer

Since I’ve had a little bit of time with Polymer, I decided to do that library next. However it has had a significant upgrade since my time with it. Version 0.8 has broken just about everything so don’t expect it to just “work”. There is a migration guide, however, and the API does a lot more for you, so it’s an improvement all round.

The Polymer folks like Bower for their distribution platform. This is a shame as jspm doesn’t support bower just now. However it does support GitHub just fine, so I can use that to install Polymer:

jspm install github:Polymer/polymer

Make sure it brings down Polymer v0.8.0

blog-code-0414-1

There are a couple of other changes that are necessary too. Firstly, Polymer uses the webcomponents-lite library. This is included in the webcomponents.js download from yesterday but it’s a different file. My Areas/Main/Views/Layout.cshtml file now looks like this:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="~/jspm_packages/npm/font-awesome@4.3.0/css/font-awesome.min.css" rel="stylesheet">

    <!-- Required Polyfills -->
    <script src="~/jspm_packages/npm/webcomponents.js@0.6.0/webcomponents-lite.min.js"></script>

    <!-- Components used -->
    @RenderSection("htmlelements", required: false)

    <title>@ViewBag.Title</title>
</head>
<body>
    <div class="flex-container">
        @RenderBody()
    </div>
    @RenderSection("scripts", required: false)
</body>
</html>

Additionally I’ve altered my Areas/Main/Views/Home/Index.cshtml as follows:

@{ ViewBag.Title = "Home Page"; }

<h1>Home Controller</h1>

<nolib-helloworld>No Library</nolib-helloworld>
<polymer-helloworld>Polymer</polymer-helloworld>

@section htmlelements {
    <link rel="import" href="~/elements/nolib-helloworld.html">

    <link rel="import" href="~/jspm_packages/github/Polymer/polymer@0.8.0/polymer.html">
    <link rel="import" href="~/elements/polymer-helloworld.html">
}

As with the no library version, I’ve created a directory src/elements/polymer-helloworld to store my custom element. Note that I am bringing in the Polymer library before the polymer-helloworld.html component, as a dependency. Within that directory, I’ve created a polymer-helloworld.less file with the following contents:

.outer {
    border: 2px solid #777;
    border-radius: 1em;
    background: blue;
    font-size: 20pt;
    width: 12em;
    height: 7em;
    text-align: center;
}

.boilerplate {
    color: white;
    font-family: sans-serif;
    padding: 0.5em;
}

.name {
    color: black;
    background: white;
    font-family: "Marker Felt", cursive;
    font-size: 45pt;
    padding-top: 0.2em;
}

Note that I’ve just changed the color of the “name badge” – this is so that I can distinguish between the CSS elements. If the CSS for each custom element is distinct (as it should be with Shadow DOM) then one name badge will be blue and one will be red. My next file is the polymer-helloworld.html file:

<dom-module id="polymer-helloworld">
    <link rel="stylesheet" href="polymer-helloworld.css">
    <template>
        <div class="outer">
            <div class="boilerplate">
                Hi! My name is
            </div>
            <div class="name">
                <content></content>
            </div>
        </div>
    </template>
</dom-module>

<script src="polymer-helloworld.js"></script>

Finally, the polymer-helloworld.js file is almost non-existent as the library takes care of most of the scaffolding for me:

Polymer({
    is: "polymer-helloworld"
});

Once this is done, a build of the components is possible. Check out the wwwroot/elements/polymer-helloworld.html file.

In development, this comes at a cost. Webcomponents-lite.js is 77K (although the full library is 258K – ouch!). In addition, polymer brings in 51 files. This is bound to be slow when loading over the Internet. We can speed it up by using vulcanize on Polymer itself. This is part of the production build of polymer and is distributed by bower in this fashion. Completing the build yourself is not a hardship however. Just bring up a PowerShell prompt and run the following:

blog-code-0414-2

I also need to alter the Index.cshtml file to bring in the vulcanized version instead of the source version:

@{ ViewBag.Title = "Home Page"; }

<h1>Home Controller</h1>

<nolib-helloworld>No Library</nolib-helloworld>
<polymer-helloworld>Polymer</polymer-helloworld>

@section htmlelements {
    <link rel="import" href="~/elements/nolib-helloworld.html">

    <link rel="import" href="/jspm_packages/github/Polymer/polymer@0.8.0/dist/polymer.html">
    <link rel="import" href="~/elements/polymer-helloworld.html">
}

This knocks down the imports to one 87K import instead of 51 files covering about the same space. More importantly, the load time of the page was down about 70% on my system.

Comparing to the Vanilla Javascript version

When it comes to code, there really is no comparison. The amount of code I had to write was practically nothing when I used the Polymer library. That means that all the scaffolding was done for me and I could concentrate on the code necessary to implement the component.

The CSS/LESS code is just the same and there is no practical difference between the templates. The code reduction comes at a cost but I expect this is a cost I can live with.

The Polymer version of my application is on GitHub and tagged as cs-0.0.3.