Thursday, September 18, 2014

Working with SVG in Angular

{
I don't have a good picture, so here's Igor with an SVG mustache.


Recently I posted about how to handle SVG in Ember. Angular has some issues itself with SVG, and it's worth discussing here, partially because I recently contributed a lot to the effort to get SVG working in Angular.

For the most part, Angular won't have too many problems with SVG, as long as you're using attribute-style directives, and you're not creating new directives. The issues Angular has with SVG will become more apparent when you're dealing with custom directives, particularly those using custom-elements, transclusion or template strings.


Angular 1.3.0-beta.19 has first class SVG support


The short story is, if you want to use SVG with Angular, it's a good idea to use 1.3.0 beta 19. I submitted and issue, then did a late-night hack-session with Igor Minar get SVG working in Angular. The approach was basically to track namespace while Angular was traversing the DOM looking for directives during $compile. The code in that area is a little tangled because of how it uses closures to pass around transclusions, found directives, and other important pieces of information. After we had it mostly working, Tobias Bosch and Igor (and probably others on the team) went back through the code and cleaned it up, fixing a few issues we didn't find the first time.

So what about 1.2?


The current stable version is 1.2. It is my personal opinion that if you want SVG support, at this point you're better off upgrading to 1.3.0-beta.19. This is because the hacks you'd have to perform to get SVG 100% working with Angular 1.2 would be much more than the work it would take to upgrade your app, and any subsequent beta-related code breakage.


Angular's issues with SVG


The problems with SVG in Angular are the same problems found in almost any framework, with one interesting exception, cloning custom elements.


1. Parsing HTML


This happened in cases where template strings were being converted into DOM elements so they could be compiled.  Parsing HTML strings was done with a wrap map that didn't support SVG elements. I went through what a wrap map is in my previous post about Ember and SVG, but as a refresher: Basically, you create a div object, then you set it's innerHTML to your HTML string, which is sandwiched between the proper tags. So if you had a string like '<td>whatever</td>', you'd create an HTMLDivElement with document.createElement, then you'd concat '<table><tbody><tr>', your string and the closing tags, then assign it to div.innerHTML. After than you'd grab the nodes from the appropriate place in the DOM tree of div.


2. Cloning custom elements


The reason this one is interesting is because Angular leverages the existing DOM as it's view, where other frameworks process templates and output DOM. This means that Angular can do efficient things like clone existing elements to create new elements. The also means that Angular is going to try to clone everything, even custom tags, exactly as they exist in the DOM. SVG 1 doesn't know what to do with custom tags. SVG 2 will treat them like <g> tags, but no browser supports SVG 2 yet, AFAIK.  So what happens when you clone <my-tag><circle /></my-tag>? It clones successfully, but <my-tag> has no layout, so everything underneath it will not render. This means that all directives that are custom elements for SVG need to have `replace:true`. This is something that is true even in Angular 1.3.0 beta 19 and higher.


3. SVG validation error messages


Since Angular is using real DOM to set up it's views, that means you're liable to run into situations where you're trying to bind to an attribute in svg like `<rect x="{{x}}"/>` The problem here is you'll get error messages all over your console saying that {{x}} is an invalid value for rect (or something like that). Fortunately, there is already a fix in angular for this in the form of the `ng-attr-` binding style. That means you can do `<rect ng-attr-x="{{x}}"/>` and everything will will be fine.

Custom SVG elements in Angular 1.3.0-beta.19 and higher


There is a new `templateNamespace` property in the directive configuration object that you'll need to set, and you'll want to set `replace` to true. But other than that, it's now pretty straight forward.

Here's an example:


Wednesday, September 17, 2014

Working with SVG in Ember

(Tomster constructiony logo thing... unsure what artist to credit)

At the time of this post, working with SVG in Ember can be a PITA to say the least. At Netflix, I'm working on an Ember application that is at least 90% SVG, and I've hit a lot, if not all, of the pain points you might have before finding this post. Hopefully someone else finds this helpful.
The issues faced in Ember with SVG are the same issues faced by most frameworks. In fact, as of right now (now meaning while I'm typing this), there are no stable versions of JavaScript "frameworks" that fully support SVG properly. Angular, Ember, React and Polymer all have some pain around handling SVG. Some of them attempt to handle it, React for example, but there are certain cases where it will still break.


First Problem - Partials getting parsed incorrectly


This happens when the root of a template is an SVG element. Ember, like JQuery, React, and in some cases Angular, use a "wrap map" technique to parse HTML strings.  This essentially creates a div tag, puts your string wrapped in some other tags into the div's innerHTML, then pulls out the child nodes you required. That's a simplified version of the technique, and I can go over that in another post. The "map" comes in when trying to determine what to "wrap" the string you provided with. For example wrapping a <td> with <table><tbody><tr>.

The problem with this technique is that SVG elements, being in a different namespace than HTML elements, will not be created properly if they're not inside of an <svg> tag. And all 50 or so SVG tags are simply not in the wrap map.


Second Problem - CSS Classes not being applied properly


Under the hood Ember uses JQuery to add and remove classes from elements. The problem here is that JQuery doesn't support SVG. I could go on a rant here about how I don't like JQuery, but meh.  The reason JQuery doesn't work to add and remove classes from SVG elements is that JQuery tries to do so by setting element.className to a string. In SVG, element.className is an SVGAnimatedString, and you must set baseVal to the string instead. But better still, if you're in IE8 and newer the "modern browsers" JQuery 2.x and higher purports to target, you can just use classList to add and remove classes. Alternatively, setting class via setAttribute('class', 'whatever') will also work with SVG.


The Solution (for now): 1.7.0 beta.5 with a script


Thanks to Stefan Penner, I was able to push through a PR to Ember that exposes the wrap map used in Handlebars via Ember._metamorphWrapMap. This allowed me to create a patch script that updates the wrap map with the appropriate elements for SVG. That same patch also updates JQuery's addClass and removeClass to use classList internally, which might break for really old browsers. (Also, as of right now I'm not supporting passing functions to those methods but feel free to submit a PR if you need that feature).


  1. ember 1.7.0-beta.5 has the wrap map exposure. (via bower: bower install ember#1.7.0-beta.5)
  2. ember-handlebars-svg is a script I made to update the wrap map and fix class manipulation. (via bower: bower install ember-handlebars-svg)


After that everything should "just work". No other JQuery patches or anything are required unless you're trying to use JQuery for animation or something, in which case, I'd recommend ditching that and using D3. There are still a few places you could have a problem, specifically if you try to use an svg <a> tag as a root element to a template, and that's unavoidable because of the wrap map approach, but other than that, you *should* be okay. (should, haha).


The FUTURE!!!!


In short, the future of SVG in Ember looks 100% awesome. And the answer is "HTMLBars".

I've talked about this issue at length with Stefan Penner, Kris Seldan, Erik Bryn and Matthew Beale and how it's going to be solved in the future of Ember. Currently SVG in 1.8.0 with metal-views is broken again. But not to worry: HTMLBars and metal-views will allow for a more complete solution to this problem that will use namespace tracking instead of clumsy wrap maps to provide functionality to properly create elements in each namespace. This means it will work 100% of the time, where a wrap map will still have some issues (for example both HTML and SVG have an <a> tag).


Stay up to date


When it comes to the status of HTMLBars and SVG support, I'd recommend following these folks on Twitter:

Kris Seldan
Erik Bryn
Matthew Beale
Stefan Penner
and of course Tom Dale

Generally, when there's a new release or a big, new feature added to Ember, Tom tweets it immediately. Stef's mostly good for information regarding Ember-CLI, but the others are all involved in the development of HTMLBars and SVG support, so they're important to follow. Also, when HTMLBars is released with SVG support, I'm liable to sing it from the rooftops. ;)

Wednesday, April 30, 2014

Embular Part 6 - Two Paths Up The Same Mountain

Years ago when I was learning kung fu, my Shifu would talk about kung fu and tai chi as "two paths up the same mountain". One path was external and physical. The other path was internal and introspective. That was to say that in both kung fu and tai chi you were starting from two difference places, but you were on a journey to the same point. When you reached that point, the only logical choice was to continue down the other path.

I feel that Angular and Ember are nearing this point. And I think they're reaching it at pretty much the same time. Simply cresting the mountain isn't enough; Now it's time for both frameworks to take a trip down the other side.

It seems to me that Angular's path has been primarily driven by a desire to create a highly extensible, clean, simple, concise API, to allow developers the power and freedom to accomplish their goals. They've certainly done that. In spades. But not without some pain to those developers. With freedom comes the ability to shoot yourself in the foot and enough rope to hang yourself with.

Ember, on the other hand, chose a path of guiding developers to create software easily and safely by providing a broad set of tools, structure and rules to follow. And they have definitely succeeded. But again, not without some pain for the developers. That broad set of tools, the expected structure and all of the rules that go with them must be learned in order to master the framework, and it’s perhaps too much for some to digest.


The Angular and Ember communities are the ones pushing the web forward


All of the new features available to us in modern browsers are powerful and amazing, but it’s these two frameworks that truly enable developers to create content that leverages that power in a way that’s pushing the web forward.

It is my hope that there will be increased cooperation between these two core teams, so that they can create something more perfect than they each already have. It certainly seems possible. There are a lot of future developments in this space that both frameworks have overlapping concerns with: Web Components, Shadow DOM, ECMAScript 6 (and beyond), even the future of HTML standards.

More importantly, I hope to see more interaction between the Angular and Ember communities (meaning you, dear reader) in general. Sharing techniques and strategies across frameworks only serves to give everyone a better understanding of web development and help these two frameworks evolve.

Maybe one day they will be one framework… Maybe one day we’ll all be Embular developers.




Links to the rest of this series:


Part 1 - Comparing Ember and Angular
Part 2 - What's Great About Angular
Part 3 - What's Great About Ember
Part 4 - What Angular Could Learn From Ember
Part 5 - What Ember Could Learn From Angular
Part 6 - Two Paths Up The Same Mountain

Embular Part 5 - How Ember Should Be More Like Angular

Constructor-based dependency injection as an obvious feature. Angular forces a constructor-based DI style that uses constructor functions with parameters. The style is carried throughout the framework and is plainly obvious to any developer that is writing code against Angular. In essence, it forces dependency injection. As an added bonus, this style of dependency declaration and injection enables Angular to detect circular dependencies at run-time.

Ember on the other hand, does not have this exact same mechanism. While you can inject your dependencies at time of creation with Ember via EmberObject.create({ deps: here }), the actual injection of those dependencies is optional. Meaning if one of those dependencies doesn't exist, it will still create the object. There also currently isn't a mechanism for circular dependency checking. The final issue related to how Ember handles the injection of dependencies is that it's not really apparent to the developer where dependencies are being "injection". The short answer: Anywhere you see this.get('something") is an entry point for a dependency. So there are multiple points where dependencies can be injected into your classes, whereas in Angular, there's one obvious point they are injected from, and it helps guide the developer towards dealing with dependencies in that manner.

Angular has a cleaner, neater API. Angular’s api revolves around a small set of primitives: controllers, service providers, directives, and filters. Along with a uniform DI syntax, these primitives allow Angular to be learned quickly and easily by new developers. Angular gives you a powerful set of tools, and then gets out of your way.

In contrast, Ember’s API has a broad surface area. There are many different types of controllers and other Ember primitives and it’s really hard to tell what you should and shouldn’t worry about using when you’re first starting out.  Combine this with an API that isn’t always easy to read and it can be difficult for a developer new to Ember to figure out what’s really happening. For example: App.FooController = Ember.Controller.extend({ foo: 'bar' }) to create a controller, while fairly terse, doesn't make any sense to someone from outside Ember. It reads like "set App.FooController  equal to Ember.Controller, and extend Ember.Controller with this object literal I'm giving you were foo is set to 'bar'".... When I first saw this format I was thinking, "What am I extending? Is this like $.extend? If so, why am I extending this Controller object over and over again?" By that token, angular.controller('FooCtrl', function($scope) { $scope.foo = 'bar'; });  just reads more fluently. "Angular, create a controller, named FooCtrl, it needs $scope, and it should put 'bar' on foo on scope".

Even computed properties, one of Ember's better features, don't read easy on the eyes to new developers. excitedFoo: function() { return this.get('foo') + '!!!'; }.property('foo')  ... Anyone new is going to be like "What the hell is this property method on this anonymous function? Where did that come from? How do I call this new function?"

Handlebars is ugly. There I said it. It's ugly. <div {{bind-attr thing="this" blah="that"}}></div> Is just plain ugly compared to dealing with Angular's templating... which is just plain HTML.  That said, however, HTMLBars is coming, and it will completely change all of that and *should* level that part of the playing field.

Angular can stand alone. Angular doesn't require any additional libraries to to function. Ember on the other hand, requires JQuery and Handlebars to function. Which only adds to Ember's already fairly immense download size. Generally speaking though, this is not a big deal. Once it's downloaded, it's downloaded. But it's worth mentioning because some people do care about this, for whatever reason.

Angular is a lot more lightweight. Let's compare the two current production versions: Angular 1.2.16 (104K min / 37K gzip) vs Ember 1.5.1 (277K min / 75K gzip) is almost half the size gzipped, and almost a third the size if your server admin forgets to enable gzip compression on your web server. And to be clear, that doesn't include the other two files that Ember requires: JQuery 2.0.1 (81K min / 28K gzip) and Handlebars 1.3.0 (43K min / 13K gzip). Those bring the required download to spin up an Ember app to around (401K gzip / 116K gzip) versus (104K / 37K) for Angular. For added fairness we'll include Angular's routing module (4K min / 2K gzip), but that's hardly going to make a difference.  But this probably isn't a big deal. This particular concern is really only a concern the first time a user hits a page, because all of these files should be cached after that. Still, some people look at file size and might not like what they find.

NEXT: Embular Part 6 - Two Paths Up The Same Mountain

Embular Part 4 - How Angular Should Be More Like Ember

Angular has a lot to learn from Ember. I think the ease of use in Angular and it's wide spread popularity may have gotten the idea into the community's head that it's "the best", but that's simply not the case.

Ember's use of convention over configuration. Angular allows developers to follow whatever convention they choose, which sounds like freedom to some, but on a large team it's more chaos than anything. Inconsistent names are a pet peeve at best, and a debugging nightmare at worst. For example a developer could name a controller "FooCtrl", "FooController", or "fooControllerer" or "fooServiceThing"... all legal names, none of them consistent. In fairness, Angular does provide a style guide, but in my experience getting people to follow a convention is a lot easier when a framework enforces and rewards the behavior.

Ember doesn't allow logic in templates. Angular, on the other hand does, via "expressions". These expressions are not quite "Turing-Complete" on their own, but they are very, very close. Expressions in templates are dangerous because they're harder to test. They also move what should have been a concern of your controller into your view. Angular's expression parsing engine is extremely impressive. It really is. Anyone that loves JavaScript should just go look at it, it's lexing pseudo-JS into tokens and parsing into a function that can be called against any JS object, usually scope. The problem with expressions is that they've allowed developers to put way, way too much logic into the templates, which makes that logic harder to test, and impossible to test in isolation. For example ng-bind="someVar + 'some string' + dangerZone('!!!')" or maybe something like: ng-click="foo = 'bar'; blah(foo + bar + '!!!); shazbot = nanoo && nanoo" ... that's totally legal in Angular, and completely insane. Ember does not allow this, you can bind to properties, calculated properties, or in the case of events, actions on the controller; All of which are easily tested in isolation.

Robust routing. As I've stated above, Ember's routing is flat out the best I've seen. The third-party ui-router for Angular comes close, but in the end, it's just a pale replica of what Ember has done, as best I can tell. That's not to belittle ui-router at all, it's a fine piece of code craftsmanship, but Ember has spent more time so far refining routing, and it shows. ngRoute, which is the Angular core offering doesn't even compare, and if it has a "best feature" it's simply that it's not included with Angular by default any longer.

Wire up more for the developer. I realize this might not be a goal the Angular team has, but in the end, Ember has solved the problem of "how can we help the developer" much better when it comes to wiring things up. In the case of routing, as mentioned in my previous article, when you setup a route in Ember and you simply give it a name, it will automatically know where to look for that route’s controller, model and template, as well set up the path it’s looking for.

For example in Ember:
Router.map(function(){
   this.route(‘foobar’);
});

would be this in Angular:

$routeProvider.when(‘/foobar’, {
   templateUrl: ‘/templates/foobar.html’,
   controller: ‘FoobarController’
});

That’s not really the end of it though, Ember also has a {{link-to}} helper that allows the developer to create a link to a page, by route name, and also pass a model to that route via the link {{link-to “foobar” shazbot}} will take whatever value (object or otherwise) is in the current controller’s `shazbot` property, as pass it as a parameter to the route, which carries over into the controller as a property.

Ember also has a feature which enables very simple two-way binding to query parameters. Basically, this means when a query parameter such as `#/routePath?foo=bar` becomes `#/routePath?foo=wee` then a property `foo` on the current controller will update from `”bar”` to `”wee”. Likewise, if you update the controller property `foo` to be something else, it will reflect it in the query param in the url bar.

Inheritance and mixins. Ember allows the developer to create a controller, or a component, or a route, or anything really, and then create subclasses of any of those things through basic inheritance. This is a very powerful tool. Combine that with Ember's mixins, and you've got a powerful toolset at your disposal that simply doesn't exist in Angular, at least not without some finagling

Embular Part 3 - What's Great About Ember

Ember also has a long list of what's great about it. It's a list that should be well known, but I feel at times that Ember fans just stink at explaining Ember's merits. Particularly to Angular fans. As I've stated above, my experience with Ember isn't as comprehensive as it is with Angular, but there are a few things about Ember that I absolutely revere and I'm excited to tell anyone who will listen:

Two way binding that doesn't allow you to write untestable code. Yeah, we've got this "two-way binding" thing in every framework these days. But where Ember shines is it forces you to write testable code. By this I mean it doesn't allow for logic in your views the way some other frameworks like Angular do. That means that everything you bind to in your view is exposed as a single, unit-testable property somewhere.

Convention over configuration. Ember uses convention to help the developer organize their code. In Ember 1.5+ this means using ES6 modules so you even know where your files are and what they're named. For example, a route named "test" would automatically look for a "test.js" file under the controllers directory, and a "test.hbs" Handlebars template under the templates directory. Likewise with files for models and the route itself. Convention over configuration means that the one stupid developer, on that other team that you hate dealing with, that always names things in stupid ways, is forced not to be a big, stupid, dumbface.

Adherence to standards. Ember developers have gone to great lengths to try to make sure Ember is moving itself, and your application's codebase towards web standards. For example, custom components are named in a convention that complies with the W3C's web components draft. Having worked with an Ember core team developer, I can tell you that their concern with future-proofing your application by trying to adhere to standards is obvious.

Ember polyfills ES5 (and ES6) functionality where it can. So if you're in a crappy browser, Array.prototype.forEach, map, reduce and filter now all work! This is in contrast to doing things like using angular.forEach, underscore/lo-dash's _.each or JQuery's $.each functions. Frankly, it's just better practice.

Extremely robust routing OOTB. Ember's routing is just flat out better than anything else I've seen out there. Better than Angular's ngRoute, better than Sammy.js, better than ui-router. It's really, really good. I've even heard rumblings that Angular might use Ember's router in the future, but that could just be gossip.

Ember solves problems and wires things up for you. What I mean by this is that in other frameworks, like Angular, you're going to have to wire quite a few things up by hand. In Ember when you add a route named ‘smith’, it’s automatically going to look for a controller either named SmithController or in the appropriate file (if you’re using Ember 1.5’s ES6 modules). This goes the same for a smith template, or a SmithRoute, etc. But none of those things are required, they’re also stubbed in for you automatically. It’s also going to look for a client-side route path “/smith”.

NEXT: Embular Part 4 - How Angular Should Be More Like Ember

Embular Part 2 - What's Great About Angular

Everyone knows that Angular is ridiculously popular. And for the most part the list of it's best features is well known, but for sake of comparison, here's my version of what makes Angular great:

Two-way binding to POJOs. Two-way binding is a must-have these days for JS frameworks. The fact that Angular was the first to market with robust two-way binding to "plain old JavaScript objects" (POJOs), is really what got it going I think.

Constructor-based Dependency Injection. This framework is built around its own IOC container that actually uses a pseudo-constructor-based DI approach that is generally preferred by developers from most contemporary backgrounds (such as Java or C#). This makes Angular highly testable, as well as providing the ability for Angular to easily detect circular dependencies.

Angular helps you organize your code. Angular has the idea of "modules" which help you break your code in reusable libraries. These could be the equivalent of a namespace in .NET or a package in Java. Angular's declaration patterns also help keep code out of global scope, for the most part. It also makes it easy to encapsulate these modules into single files, which would be like "assembly" or "jar" equivalents. This can be a very powerful tool when you're organizing large projects.

Simple bootstrapping. Angular has the simplest bootstrapping process of any modern framework I can think of. Just include one JS file, and add an ng-app directive to the page and you're in business.

Plain HTML for templating. In Angular, you don't have to learn much in the way of custom templating language. The only thing that's different from plain HTML is really the binding shorthand such as {{foo}}, which is generally optional.

You can extend HTML to do what you need it to do. Angular's directives allow you to create your own custom behaviors for any custom (or existing) HTML you choose. This is an incredibly powerful tool. It can be used to create reusable "controls", event bindings, interactions like modal dialogs or slider controls, and even validation.

It's flexible and stays out of the developer's way. Angular hands the developer a set of tools to develop a few primitives like Controllers, Services, Providers, and Views and then gets out of the way. This clears the path for the developer to create whatever he might need to create to get his/her project going, and in whatever way the developer chooses to do so. There are so many ways to skin a cat in Angular that it's pretty easy to discover a path to your goal.

Angular is easy to learn.  Angular's best feature is really a combination of all of the above. Aside from directives, Angular is very easy to learn. Its consistent API, use of plain HTML and plain JavaScript objects are an ingenious approach to a JavaScript application development platform not just because of the wizardry that's gone into developing Angular, but because it's so easy to pick up and use. Having worked in an environment where I had to get a team of 50-60 developers from "zero" to "proficient" in Angular, I can tell you it wasn't hard at all. Most of them just "got it".

It's backed by Google. Everyone knows that, and I think that helps some people "trust" Angular a bit more. Personally, I think this is a silly reason to choose a technology, but, c'est la vie, this is something that some people consider corporate backing when they're choosing a framework. One added benefit to a corporately backed OSS effort is there is a paid, full-time staff working on it.


NEXT: Embular Part 3 - What's Great About Ember