A Few Paragraphs on Angular 2

Look! I’m back! I may end up writing here more often that I have over the past couple of years as I’m significantly cutting back on the amount of time I spend on Twitter. If you’ve enjoyed me saying “get off my lawn” on Twitter over the past few months, you’ll have to come here to read those thoughts. There is the benefit of paragraphs and formatting on the site, so there’s that. If you’re curious what the hell I’m talking about, this tweet-storm is a great example. That kind of stuff will live here now, if the mood strikes me.

The mood has struck! Read on!


I just finished up a long-term consulting gig and, while I’m kicking off a shorter-term a project for another long-term client, I’m also looking to set up my next big project. That’s the big question for me right now- what am I going to be doing for 2017?

As part of that process, I’m finally going to do a deep dive into Angular 2. I worked with it a little bit at my last client, but that’s not really enough for me to really feel like I know it. People are interested in it. I’m interested in it. So… I’m looking at it.

I’m starting with Switching to Angular 2. I’ve got a bunch of Angular 1.* experience so a book written for people looking to move from 1 to 2 seems like a decent place to start.

Between the book and the exposure I had to it on my previous project, my initial take is that it feels like everything that’s right and wrong about the web all wrapped up into one package.

It’s “right” in that it’s really well put together. The general framework architecture combined with the use of TypeScript make it a very compelling alternative for certain types of applications and teams. Like Angular 1 before it, it works for me for some things.

It’s “wrong” in that it’s just ridiculous. It doesn’t make sense for most of what people actually need to do on the web.

Modern web development is generally too damn complicated for its own good. That complexity is heightened by the interconnected, patchwork nature of modern front end development. If you buy into this mode of development you are relying on a matrix of software that no human could possibly vet. You’re basically acknowledging you’re going to live with random bugs, dependency issues, and reams of alpha software you’re supposed to trust going into production.

Angular 2 is exactly that.

On my first project with Angular 2, I experienced weeks of flaky builds as the development landscape shifted randomly underneath us. Many dependencies were also flaky and/or barely maintained. So much fun! Once the builds stabilized, I was flabbergasted to take a look at how much code was required to run the application. node_modules had over 1000 dependencies and our main.bundle.js was over 4.5MB. This was for a read-only application. It didn’t even do anything. I can’t help but think that’s ridiculous. For complicated, large-scale applications I can see the benefits, but for something simple… holy cow that’s a lot of code to solve the kinds of problems I was able to solve with a few hundred KB of pure JavaScript in 2006.

More on it as I get deeper into this dive.


On a final, related note, I’m really interested in exploring a way to marry the best of modern web development with a more stable, accessible (in both senses) and minimalist approach. There’s got to be something more appropriate for smaller applications and general “web” development.

Doing the Same Thing Over and Over Again and Expecting Different Results

Here I am taking a shot at shorter form writing. Watch me write!

The biggest job/career related error I made this past year was going against my own policy and talking to a company I had a bad feeling about from the beginning. I’ve actually known about this company for a long time and think poorly of them. The thing is, a recruiter came along and told me how much they were paying for a high profile role they were trying to source. That number was higher than the honestly very high number I have in my head to go work for someone else at this point. So, against my better judgment and against my own stated policy of not talking to people unless I’m sure the company will be a good fit, I talked to them.

I’m a dumb-ass.

The one part of the conversation that sticks with me is the “big” question in the interview. Apparently, they’ve got a lot of separate development teams who have worked in multiple versions of Angular on different components that have to play nice together on the same page. As you can imagine that has caused problems. Apparently, they’re also kicking off some development using React. With that cluster in mind, they asked, how would I help solve the issues they were having with all these interoperability concerns at an architectural level.

My answer was simple. I said, “Stop doing that. Don’t use React and standardize on one Angular version.”

I could hear the frustration in the interviewer’s voice as he said, “that’s not really an option” as if pointing out the obvious solution to their self-inflicted problem was an insult to him personally. I could tell he wanted to hear some hair-brained technical solution (“I know we’ll write REACTANGULAR and it will normalize across all Angular versions”) that would rescue them from a disaster of their own making, without having to do hard work. He lead me down that path a little with some follow-up questions. The thing is, that’s precisely the kind of bullshit is never going to come out of my mouth. I wasn’t going to blow smoke up his ass just so that he can ignore the obvious solution. To me, when you’re doing something so fundamentally wrong, the best solution is to bite the bullet and do something fundamentally right to counteract it.

How they thought introducing an entire second library to the mix was a good idea is something that will forever confound me. They’ve already identified this as a problem and they’re willingly making it more complex. That’s insanity.

Suffice it to say, they didn’t like me for the role.

So many companies are obsessed with being on latest and greatest libraries and frameworks. If, like this company, you want to be a great engineering organization you should focus on doing great work. If you’re architecture is a patchwork monster it doesn’t matter if you’ve got the new and shiny. You’ve just got a new and shiny patchwork monster.

I Made a Scatter Plot Data Visualization with AngularJS and SVG. Here’s How I Did It.

This post is a longer examination of the new scatter plot visualization I added to my upcoming data visualization presentation for jQuery Conference. As with the other Angular examples I’ve posted recently, this one is based on the data I keep about the world’s most valuable comics. This particular visualization lives on the page I keep detailing record comic book sales. Take a look. It’s pretty cool, especially if you’re fascinated by comic books that have sold for more than $100,000.

For reference, it looks like the following. It’s 20 years of comics sales plotted horizontally with their sale prices (ranging from $100,000 to $2,500,000) plotted vertically. You can see a couple of clusters of activity based on different events in the marketplace.

chart

So, how did I do it? And why did I do it this way? D3 actually has a few scatter plot examples out there, so I could have used one of those, but as I thought about it I decided I wanted to do something hand-rolled. A scatter plot is actually pretty easy to map out and, as an added bonus, I could lay out the basics of the chart in Illustrator, which allowed me to demo the fact that SVG can be authored like any image by a graphic designer and then manipulated with JavaScript and CSS.

So let’s take a look at the particulars.

First we’ll start with the markup. This is Angular, after all. I’ve simplified the markup a bit, taking out some of the elements representing grid lines. Check the source on Github for all the details.

The interesting bits, from the Angular perspective, happen around line 30. The core of the visualization is in the circle element. It’s an ng-repeat that goes through the items collection in the controller’s scope. It’s filtered by the venues property.

Take note of the prefixes on the next set of attributes. For starters, as I normally do, I prepend data-* to Angular attributes as that’s the way custom attributes are defined in the spec. I like to play by the rules. You’ve probably seen that before. What’s probably not so familiar is the use of the additional ng-attr-* prefix. If you’re familiar with Angular you know you should just be able to do fill="{{colorPicker(it.venue)}}" and Angular should evaluate the results of the colorPicker method and insert it in as the value of the fill attribute. This doesn’t work with SVG elements. Some browsers will parse the entire SVG element before Angular has a chance to evaluate the SVG attributes. So if you put n Angular expression inside an SVG attribute it will throw an error. ng-attr solves this by binding the attribute solely to Angular’s discretion. Here, I’m using this pattern three times. The fill attribute, which provides the color coding for the different venues s these comic books have sold (with the handy colorPicker method that accepts the it.venue as an argument) , and the cx and cy attributes which indicate the center of the circle.

The cx and cy attributes are passed through custom filters which transform the data into usable x and y coordinates. I’ll talk about those in the section on the Angular filters. Following the filters there are two mouse events used to show and hide a simple (svg) tooltip.

The tooltip is in the next section. Doing boxes in SVG isn’t quite the same thing it is with HTML. You can’t just throw a box in there and have text flow inside the box like you can with a DIV or something, so this would have been easier with an HTML tooltip. That said, I wanted to do this in SVG so it’s all in SVG. In this case I’m doing it with a solid box with several text elements layered on top. All of these tooltip elements show based on the tooltip model on the scope. If the price is truthy, the tooltip shows. Otherwise, it’s hidden. For each text element and the rect element, I’m using x and y coordinates generated with the same Angular filters in use on the circles and using the transform attribute to move the element around based on that common x/y. Each of the text elements also expose the data from the model.

Following the tooltip code, in the ‘legend’ g element there are several rect elements which allow for quick filtering by sales venue. ng-mouseover and ng-mouseout are used to update the venues filter.

That’s the markup. SVG isn’t that scary, is it?

 <div data-ng-app="comicsApp">
  <div data-ng-controller="chartCtrl"> 
    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
    width="980" height="600" viewBox="0 0 980 600" xml:space="preserve">
      <g id="lines">
        <line fill="none" stroke="#000000" stroke-miterlimit="10" 
         x1="90.828" y1="-8" x2="90.828" y2="579.297"/>
        <line fill="none" stroke="#B5B5B6" stroke-miterlimit="10" 
         x1="0" y1="579.297" x2="981.996" y2="579.297"/>
        <line fill="none" stroke="#595858" stroke-miterlimit="10" 
         x1="734.275" y1="49.246" x2="734.275" y2="579.161"/>
        <!--about 50 lines cut-->
      </g>
      <g id="text">
        <text x="10" y="16">price in USD</text>
        <text x="71" y="574">$0</text>
        <text x="480" y="595">2003</text>
        <text x="78" y="595">1993</text>
        <text x="881" y="595">2013</text>
        <text x="25" y="553">$100,000</text>
        <text x="25" y="468">$500,000</text>
        <text x="16" y="363">$1,000,000</text>
        <text x="16" y="256">$1,500,000</text>
        <text x="16" y="151">$2,000,000</text>
        <text x="16" y="45" >$2,500,000</text>
      </g>
      <g id="dynamic">
        <circle  data-ng-repeat="it in items | filter : venues" 
         opacity="0.8" 
         data-ng-attr-fill="{{colorPicker(it.venue)}}" 
         data-ng-attr-cx="{{it.date | xDate}}"
         data-ng-attr-cy="{{it.price | yPrice}}" 
         data-ng-mouseover="updateTooltip(it)" 
         data-ng-mouseout="updateTooltip(0)" r="7" />
        <rect data-ng-show="tooltip.price" data-ng-model="tooltip" 
         transform="translate(-55,-100)" 
         data-ng-attr-x="{{tooltip.date | xDate}}" 
         data-ng-attr-y="{{tooltip.price | yPrice}}" 
         width="150" height="80" 
         fill="white" style="filter:url(#drop-shadow)" />
        <text data-ng-show="tooltip.price" data-ng-model="tooltip" 
         transform="translate(-45,-90)" 
         data-ng-attr-x="{{tooltip.date | xDate}}" 
         data-ng-attr-y="{{tooltip.price | yPrice}}">
         {{tooltip.title}} {{tooltip.issue}}</text>
        <text data-ng-show="tooltip.price" data-ng-model="tooltip" 
         transform="translate(-45,-75)" 
         data-ng-attr-x="{{tooltip.date | xDate}}" 
         data-ng-attr-y="{{tooltip.price | yPrice}}" >
         {{tooltip.pedigree}}{{tooltip.collection}}{{tooltip.provenance}} {{tooltip.grade_src | srcFilter}} {{tooltip.grade}}</text>
        <text data-ng-show="tooltip.price" data-ng-model="tooltip" 
         transform="translate(-45,-60)" 
         data-ng-attr-x="{{tooltip.date | xDate}}" 
         data-ng-attr-y="{{tooltip.price | yPrice}}" >
         {{tooltip.price|currency}}</text>
        <text data-ng-show="tooltip.price" data-ng-model="tooltip" 
         transform="translate(-45,-45)" 
         data-ng-attr-x="{{tooltip.date | xDate}}" 
         data-ng-attr-y="{{tooltip.price | yPrice}}" >
         {{tooltip.date}}</text>
        <text data-ng-show="tooltip.price" data-ng-model="tooltip" 
         transform="translate(-45,-30)" 
         data-ng-attr-x="{{tooltip.date | xDate}}" 
         data-ng-attr-y="{{tooltip.price | yPrice}}" >
         {{tooltip.venue}}</text>
      </g>
      <g id="legend">
        <rect x="125" y="5" width="15" height="15" fill="#D95B43" 
         data-ng-mouseover="venues='comic connect'" 
         data-ng-mouseout="venues=''"></rect>
        <text x="145" y="15" class="legend">Comic Connect</text>
        <rect x="245" y="5" width="15" height="15" fill="#ECD078"  
         data-ng-mouseover="venues='heritage'" 
         data-ng-mouseout="venues=''"></rect>
        <text x="265" y="15" class="legend">Heritage</text>
        <rect x="325" y="5" width="15" height="15" 
         fill="#C02942" data-ng-mouseover="venues='comiclink'" 
         data-ng-mouseout="venues=''"></rect>
        <text x="345" y="15" class="legend">ComicLink</text>
        <rect x="405" y="5" width="15" height="15" fill="#542437" 
         data-ng-mouseover="venues='pedigree'" 
         data-ng-mouseout="venues=''"></rect>
        <text x="425" y="15" class="legend">Pedigree</text>
        <rect x="485" y="5" width="15" height="15" fill="#53777A" 
         data-ng-mouseover="venues='metropolis'" 
         data-ng-mouseout="venues=''"></rect>
        <text x="505" y="15" class="legend">Metropolis</text>
        <rect x="565" y="5" width="15" height="15" fill="#69D2E7" 
         data-ng-mouseover="venues='jp'" 
         data-ng-mouseout="venues=''"></rect>
        <text x="585" y="15" class="legend">JP/Mint</text>
        <rect x="645" y="5" width="15" height="15" fill="#FA6900" 
         data-ng-mouseover="venues='mastronet'"  
         data-ng-mouseout="venues=''"></rect>
        <text x="665" y="15" class="legend">Mastronet</text>
        <rect x="725" y="5" width="15" height="15" fill="#FE4365" 
         data-ng-mouseover="venues='pgc'" 
         data-ng-mouseout="venues=''"></rect>
        <text x="745" y="15" class="legend">PGCMint</text>
        <rect x="805" y="5" width="15" height="15" fill="#666666" 
         data-ng-mouseover="venues='unknown'" 
         data-ng-mouseout="venues=''"></rect>
        <text x="825" y="15" class="legend">Other/Unkown</text>
      </g>
    </svg> 
  </div>
</div>

Now let’s take a look at the JavaScript. First up is the controller. This is pretty simple as far as these things go. $scope.items is first populated with data provided by an Angular factory. The factory is a simple $http.get so I’m not showing it here. I just organized the data request into a factory so two controllers could share the same code for getting comics data. Following that, the $scope.tooltip model is set with a single property, price set to zero. This falsy value ensures that the tooltip we previously defined in the HTML isn’t shown by default. Following that is a small method designed to update the tooltip model with data representing the currently selected comic book. Finally, there’s a small method and related array used to choose colors for the different venues. The method accepts a string argument and matches against a list of known venues, returning the proper color.

That’s the whole controller.

angular.module('comicsApp.controllers', ['comicFilters','comicsFactories']). 
  controller('chartCtrl', ["$scope",'dataService',function( $scope, dataService )  {
    $scope.items = dataService;
    $scope.tooltip = {
      price:0
    }
    $scope.updateTooltip = function(it) {
      $scope.tooltip = {
        price:it.price || 0,
        venue:it.venue,
        date:it.date,
    	 	title:it.title,
    		issue:it.issue,
    		pedigree:it.pedigree,
    		collection:it.collection,
    		provenance:it.provenance,
    		grade_src: it.grade_src,
    		grade : it.grade
      } 
    }
    $scope.colorPicker= function( venue ){
      switch (venue) {
        case "Heritage":
          return $scope.colors[0];
        case  "Comic Connect":
          return $scope.colors[1];
        case "Comiclink":
          return $scope.colors[2];
        case  "Pedigree":
          return $scope.colors[3];
        case "Metropolis":
          return $scope.colors[4];
        case  "JP The Mint":
          return $scope.colors[5];
        case "Mastronet":
          return $scope.colors[6];
        case  "PGCMint":
          return $scope.colors[7];
        default:
          return $scope.colors[8];
       }
    }
    $scope.colors = ["#ECD078","#D95B43","#C02942","#542437","#53777A","#69D2E7","#FA6900", "#FE4365","#666666"];
  }
]);

Now let’s take a look at the filters. As I mentioned earlier, this particular visualization isn’t generic, so these are only useful in the context of this particular implementation. Which is fine. I’m not doing a million of these.

The first, xDate, defines the x axis. It takes the date (in the form yyyy-mm-dd) and splits it into and array containing the years, months and days. I calculate the total number of months from 1993 by subtracting 1993 from the year and then multiplying that number by 12. I then adding that number to the number of months from the original date array. After that the numbers of months is fudged into a pixel measurement as the offset of the left of the chart, 90, is added to the number of months multiplied by 3.3333, which is a rough “month” unit on this particular chart.

The y axis filter is easier. It calculates a pixel representation of the book’s value (the value divided by 4700, the number of dollars per pixel) and that number is subtracted from 579, which is the offset from the top of the SVG element to the baseline of the chart.

If you were doing a generic chart that could take any similar data and produce a scatter plot, you would have to do these calculations on the fly. Getting the minimum and maximum values out of the data and creating a range and scales depending on the specific data. Since I defined the data and parameters for this before I wrote a line of code.

Yay for lazy.

angular.module('comicFilters', []).filter('xDate', function () {
    "use strict";
    return function (input) {
        if (input !== undefined) {
          var date = input.split("-");
          var years = date[0] - 1993;
          var months = (years * 12) + parseInt(date[1]);
          return 90 + months * 3.3333;
          
        }
    };
}).filter('yPrice', function () {
    "use strict";
    return function (input) {
      if (input !== undefined){
        return 579 - (input/4700);
      }
    };
})

And there you have it. Check out the $100,000 club repo for all the source code from this visualization and keep your eyes peeled for my jQuery Conference presentation where I’ll be talking about this as well as D3, the canvas element (with the web audio API) and Google Maps.

The Project (soon to be) Formerly Known as ng-grid

I’ve go a bunch of small updates to share (and one big one.) I’m starting with this one since it fits with the Angular kick I’ve been on.

I’ve recently gotten involved with the ng-grid project housed under the Angular UI banner. We’re using it at work, so it makes sense for me to pitch in to help keep the project humming along as best it can.

We had a meeting last week and hatched plans to rewrite the core of the project in order to juice performance and ease development going forward. Working in financial services, grids are a big deal for me and I’ve never been a huge fan of any of the ones out there. I’m hoping this project will end up being the quality grid I’ve always been looking for as a consumer.

On the name

While it’s called ng-grid at the moment, it’s going to get a name change for 3.0, in order to better fit with the rest of the Angular UI stable. I’m not 100% sure of this, since we haven’t followed up since the meeting, but it will likely be UI Grid.


So, yeah. If you’re an Angular type and are looking for a data grid, I’ve got your back.

Easy Autocomplete with the datalist Element, the list Attribute and AngularJS’s ng-repeat Directive

Continuing to write about some Angular features I’ve been working with recently, I thought it would be interesting to show off one of the little conveniences I was able to put together using just a couple of Angular’s core features. This example leverages basically two basic features of Angular and two HTML5 features to create an easy, live autocomplete widget.

The pieces we’re going to use are:

  • Angular models This demo shows how easy it is to use Angular’s models. While they can get more complicated, this example shows the base case of simply binding to a variable in scope, creating dynamic links that update the UI when the data is updated with minimal or no JavaScript interaction.
  • ng-repeat Obviously if you’ve worked with Angular for any length of time you’ll be familiar with this directive. Here, it’s used here to iterate over a collection and create a dynamic datalist element.
  • datalist and list The datalist element and the list attribute are the two new HTML features that bind up the autocomplete functionality. In short, the datalist element defines a list of autocomplete entries. The list attribute binds the datalist to an input using an id reference. This combination is available in Chrome, Opera and Firefox with buggy support in IE10+

Let’s see how it all goes together.

First up, since this is Angular, let’s look at the markup.

To get started you need to define an Angular controller. This one is named MainCtrl. Since this is just a simplified demo to illustrate the autocomplete widget, it doesn’t do much, but the code it’s pulled from is a form used to add information about individual comic books to a simple database. Many of those comics are from the same titles (Amazing Spider-Man, Action Comics, etc.) so it’s handy to have an autocmplete list in order to improve data entry efficiency.

The input itself has two pieces to note, the data-ng-model attribute and the list attribute.

Note: As always, I append data- to Angular attributes in order to follow the HTML spec’s directions on custom attributes. That’s just me. You might want to let it all hang out. Fair play.

The data-ng-model attribute defines the model for the input as the title property of variable named item bound to the controller’s scope. Interestingly, this variable doesn’t exist at run-time. Instead of erroring with a warning about item being undefined Angular handles the creation of it once the form is submitted. This is a great example of how casual Angular is with their models. There’s no ceremony here. Add the data-ng-model attribute and the binding is done for you. If the variable exists in scope, the input is bound to it. If it doesn’t exist, Angular creates it. That’s pretty sweet.

The list attribute references the datalist element that the input should look for in order to build value hints. The value of the attribute is the id of the datalist you want to use.

The button at the end of the form is the next interesting piece of markup. On that input we’re using data-ng-click in order to bind the addItem function to click events on the form. Angular will look for addItem in the global namespace and in the controller’s scope. As you’ll see in the JavaScript example, we’re safely binding the method to the controller’s scope. If you click this button after adding a new title the title will be immediately added to the autocomplete list.

Finally, there’s the datalist element which uses data-ng-repeat to build out the list of autocomplete options. This directive is bound to the titles property of the controller scope. Since Angular models are bidirectional, once you update $scope.titles this list will be updated with new values. Pretty sweet. As you can see, this datalist element has the id we referenced earlier in the list attribute of the input.

<body data-ng-controller="MainCtrl">
    <form>
      <div>
        <label>title</label>
        <input type="text" data-ng-model="item.title" list="comicstitle">
      </div>
      <div>
        <input type="Button" value="Add" data-ng-click="addItem(item)">
      </div>
    </form>
  </div>
  <datalist id="comicstitle">
    <option  data-ng-repeat="ttl in titles" value="{{ttl}}"> 
  </datalist>
  </body>

Now that you’ve seen the markup, let’s look at the JavaScript that binds it all together. It’s actually pretty simple. Most of the wiring is done in the markup so the JavaScript is pretty sparse. That said, there are some interesting things so let’s look at it in-depth.

For starters we’re defining the starter list of titles as a variable on the controller’s scope. It’s a simple array bound to $scope.titles.

Have I mentioned that data binding is one of my favorite things about Angular? There’s absolutely no ceremony with creating a model. It’s just a variable on the controller’s scope (or even the global scope if you’re super lazy.)

After the model, the only other thing on the controller is a function called addItem.

This function is the method referenced in the data-ng-click attribute in the markup. It does a couple of things. The first is that is pushes the new value to $scope.titles. This example uses lodash’s contains function to test whether or not the title already exists in the array before it’s added. That keeps the list unique.

The next bit is another neat illustration of Angular models. Since the item we created when we added a title, setting it the object to an empty object is a shortcut to clearing the values out of the form. In this case there’s just the one form element, but if there were fifty or five hundred form elements with their data-ng-model attributes bound to properties of item this single line would clear all the values out of every bound form element.

app.controller( 'MainCtrl' , function( $scope ) {
  $scope.titles = [ "Action Comics" , "Detective Comics" , "Superman" , "Fantastic Four" , "Amazing Spider-Man" ];
  $scope.addItem = function( item ) { 
    if ( !_.contains( $scope.titles , item.title ) ){
      $scope.titles.push( item.title );
    } 
    $scope.item = {};
  }
});

Check it out, in action, with this plunker.


And there you have it. Let me know if you have any questions, comments or corrections in the comments.