Unit Testing $http service in Angular.js

Today @JohnCulviner (johnculviner.com) was asking me how to write a unit test in Angular.js for a controller that took a service which wrapped an $http call. There are at least two ways to do this, one with $httpBackend and one just using Jasmine.js spies.

Here is the full Plunker: http://plnkr.co/edit/HCddhg?p=preview

First I created a basic app with a controller and service which calls github

Second I created some unit tests, the first set using Jasmine SpyOn, the second using $httpBackend

The Jasmine Output

 

Why is Knockout.js or Angular.js slow at rendering lists

Knockout.js and Angular.js are great at many things, but rendering large lists of data is not one of them. Below I show you why, and how to fix it.

There Is No Magic JavaScript Framework

The strongest JavaScript framework/library/utility/shim in a developer’s toolbelt is their brain. There is no perfect [noun|verb|adjective].js that will will magically solve 100% of your apps features with clever engineering. These tools are built by humans. There are some good tools for solving specific problems, but one tool cannot possibly solve them all. A good dev knows when to give up on the tool he is using for solving a specific problem, and try something else.

A friend of mine was recently trying to use Knockout.js, a mvvm model-binding framework, to create a table with 1000 rows in HTML, and it was failing miserably.  Rendering took several seconds on an average PC, during which the browser page was hard locked. A completely unacceptable solution by any standard, and yet completely avoidable.

Here is an example plunkr of what he was trying to accomplish: http://plnkr.co/edit/xWpRm72qz2mV8hxbgOai?p=preview

Let’s look at a couple of things going on in the performance timeline. First thing you’ll notice is on my 2 year old Intel i7, its takes  853ms to render this start to finish, and uses 61MB to do so.

Rendering timeline

It calls the garbage collector 6 times:

Timeline garbage collection

With almost 300ms of that time to render:

Timeline rendering

Model binding frameworks are great at abstracting out complicated rendering and event wiring, but are terrible at rendering large amounts of HTML. They simply were not built to do this, and trying to make it work is a fool’s errand.

You might be thinking, “But hey, I bet Angular.js is faster!”. Nope, sorry, wrong again: http://plnkr.co/edit/Bkd2jgjHb1F0sagjF5Ke?p=preview. For any model binding framework, a lot of events and handlers need to be wired up for every binding context, with a context being a viewmodel in Knockout or a $scope in Angular. Most pages will typically have a low number of contexts, typically somewhere between 1 and 50, so even though the high amount of overhead per item is high, the actual total time ends up being low. Unfortunately that context wiring scales linearly, so when you have hundreds of contexts on a single page, one for each item in a list, that overhead becomes very apparent.

Use the right tool for the job

This problem has already been asked and solved — years ago. My current favorite tool for solving this problem is SlickGrid. The way it handles rendering is amazing, only actually showing the data you need to see on the screen, and dynamically adding/removing the rows you don’t need to see. A perfect solution.

Here is an example: http://plnkr.co/edit/hGCklkYvhgYq7mnrpRnw?p=preview

It takes 80 ms to render, uses 58MB, and 13ms of that time is rendering:

Slickgrid click

As you can see, using the right tool for the right job makes all the difference in the world.

 

Angular.js directives – Difference between controller and link

Angular directives can be a black hole of thoughts, and one of those being, “where do I put code, in ‘controller’ or ‘link’?”

The short short answer: ‘link’.

The longer short answer: Ask yourself “when do I want my code to run?”

  • Before compilation? – Controller
  • After compilation? – Link

What does this mean? While I would never condone putting DOM manipulation in an angular controller, I see it constantly, and its important to know what is actually going on and when functions are run. Example Plunkr: http://plnkr.co/edit/k5fHMU?p=preview

 But, but, but, more details please!

Ok, ok, fair enough. Couple of things to note:

  1. controller ‘$scope’ and link ‘scope’ are the same thing. The difference is paramaters sent to the controller get there through Dependency Injection (so calling it ‘$scope’ is required), where parameters sent to link are standard order based funcitons.  All of the angular examples will use ‘scope’ when in the context, but I usually call it $scope for sanity reasons: http://plnkr.co/edit/lqcoJj?p=preview
  2. the $scope/scope in this example is simply the one passed in from the parent controller.
  3. ‘link’ in directives are actually the ‘post-link’ function (see rendering pipeline below). Since pre-link is rarely used, the ‘link’ option is just a shortcut to setting up a ‘post-link’ function.

So, whats a real world example? Well, when I’m deciding, I go by this:

  • “Am I just doing template and scope things?” – goes into controller
  • “Am I adding some coolbeans jquery library?” – goes in link

 But, why!?!?!

Well, here is a great example of the angular compilation and linking pipeline: http://plnkr.co/edit/CW7cF0?p=preview

What this is telling you is that all child directives link functions get executed before the parent functions link functions. So something like the below will not work:

So why do we even have a ‘controller’ in the directive, seems dumb :-p

So we can do awesome stuff like using one directives controller in another. We simply set something we want to “this” and get it using the “require” option in the directive.

Many thanks to Josh Harris for his code reviews and awesome pipeline example above!

angular.js with svg

I’ve been working a lot getting angular.js to render svg. The simple cases are easy, where you just have some DOM elements and angular bindings. However, the challenge arises when you actually need to build something larger with it, ideally using angular templates. This is where angular falls apart, as angular only knows how to create HTML DOM elements, not SVG elements.

After much turmoil, on my project I settled on using jquery.svg.js to handle rendering the svg elements, and I attach angular bindings to those. Combined with custom angular directives, this has proved to be the easiest happy path for me.

Ideally what I wanted was to attach shape objects to the scope,  and let angular work its magic.

To get this rendered up, first we have to create a svg element using jquery.svg. I’m creating a custom svg directive that all of our shapes can live in:

Then we make a directive to render our shape:

A couple of things you’ll notice:

  • We need a reference to the parent jquery.svg element, which was attached to the ngSvgController. This is what lets us place svg elements on the page
  • Simply creating elements with bindings doesn’t do anything. We have to tell angular they exist using $compile
  • Some angular attributes need to be defined with ng-attr-[the real attribute], like ‘ng-attr-d’ was. This is called a late binding, and angular will create the real “d” attribute after $compile has happened. This prevents errors from showing up in your console.

The plunkr is much more complete, as I deleted some code to make browsing the code a bit easier. Here it is for your pleasure: http://plnkr.co/edit/Xk8wM3?p=preview

You can watch the progress on my poc project at: https://github.com/JasonMore/svg-poc