codelord.net

Code, Angular, iOS and more by Aviv Ben-Yosef

What Angular’s .equals and .toJson are for

| Comments

Why did Angular implement its own angular.toJson() if we already have JSON.stringify()?
Why isn’t angular.eqauls() always the same as other equality utilities, like lodash’s _.isEqual()?

I faced these questions when I first started doing Angular. Taking care to note the difference has helped me avoid some pitfalls along the way and understand Angular a little bit better.

The unique behavior of angular.equals

Once you use Angular enough you eventually notice that Angular tends to prefix its own properties and functions with $. For example, if you use ng-resource (though I think you shouldn’t) you will see methods such as $save(). Another case is scopes’ $apply, $watch, etc. and ngModelController’s $error and similar.

Because of that, the Angular team implemented .equals() so that it ignores properties that start with $. This means you can compare objects without fear of Angular’s properties getting in the way (like equality of two ng-resource instances):

1
2
angular.equals({a: 1}, {a: 1}) === true
angular.equals({a: 1}, {a: 1, $a: 2}) === true

.equals() also differs from other utilities in that it completely ignores functions:

1
angular.equals({a: 1}, {a: 1, b: function() {}}) === true

This allows us to compare objects considering only their data, not their functions or Angular-added properties.

The curious case of angular.toJson

One of the first functions any developer doing JavaScript comes across is JSON.stringify(). At first, I didn’t realize why Angular would need to add its own way of doing that.

Well, it turns out that the Angular team didn’t do it because they just happen to like rewriting everything. toJson is different in that it ignores properties starting with $$. Yes, that’s two $ signs, unlike equals().

While Angular uses the $ prefix to denote its own properties, $$ means private Angular stuff, or “don’t touch this.”

The fact toJson ignores these means you won’t get unexpected attributes on your data. The most common use case is the fact Angular adds a $$hashKey property to elements in ngRepeat (when you don’t use track by).

Say you use ng-repeat to display some list of objects you got from the server, and then after the user changes them you send them back to update the server. The silently-added $$hashKey might end up in your database, or trip up server-side validations about unexpected fields.

That’s why Angular provides toJson and uses that by default for serialization (e.g. in $http).

The companion fromJson() is plainly a wrapper around JSON.parse(), probably to provide the symmetry.

Now you know!

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!

Configuring components with ui-router and ngRoute

| Comments

Angular 1.5’s .component() method is very cool, as I wrote about previously. And in general the migration path to Angular 2 recommends that we all stop using controllers in favor of components.

A lot of us are used to using controllers as the route-level objects. Each route has a controller that’s responsible for that specific route, and comes with its own template, etc.

This was comfortable since both ui-router and ngRoute allow us to easily set a controller that handles a route and inject it with dependencies using resolve.

Achieving the same with components isn’t as straightforward, but doable. Note: You might be thinking otherwise, but yes, components should be used for things that aren’t reusable, like handling a specific route. They should actually be used by default for anything that’s not a service in your app.

ngRoute

Say that we’ve got this component:

1
2
3
4
5
myMod.component('inbox', {
  templateUrl: 'inbox.component.html',
  bindings: {mails: '='},
  controller: function() {...}
});

Passing it the mails dependency using resolve is pretty simple:

1
2
3
4
5
6
myMod.config(function($routeProvider) {
  $routeProvider.when('/inbox', {
    template: '<inbox mails="$resolve.mails"></inbox>',
    resolve: {mails: function(Mails) { return Mails.fetch(); }}
  });
});

Yes, ngRoute has a handy $resolve property exposed on the scope by default, which saves us some keystrokes and boilerplate in this case.

ui-router

While the upcoming 1.0 release will handle components in a cleaner way, the above solution is available to us since version 0.3:

1
2
3
4
5
6
7
myMod.config(function($stateProvider) {
  $stateProvider.state('inbox', {
    url: '/inbox',
    template: '<inbox mails="$resolve.mails"></inbox>',
    resolve: {mails: function(Mails) {return Mails.fetch(); }}
  });
});

Yes, that’s eerily similar to the ngRoute way. Now we get rid ourselves of controllers and get onboard the component train. Choo-choo!

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!

$scope.$apply: What Is It Good For

| Comments

Angular has a lot of magic going on. It keeps track of all bindings and templates, and it seems like no matter what you throw at it, it will make sure that everything gets rendered and stays synced.

For a lot of us this binding magic is what initially pulled us to Angular.

But, of course, it’s not really magic, and you can come across situations where things stop working – exactly because Angular is no longer able to keep track of everything.

In those cases, the solution is almost always the $scope.$apply() function. Let’s understand why it’s needed, when should you use, and how.

The digest loop on one leg

Angular’s magic basically works by having a “heartbeat” – every time Angular sees something happened it goes over all your watchers and updates templates, syncs bounded properties, executes promises, etc.

The ability to know that something happened relies heavily on the assumption that you, the coder, won’t “step outside” of Angular’s sight.

Whenever changes happen as a result of something Angular-originated, we’re all good. So if you use ng-click to update things, or ng-model to bind a value, run code after a $timeout or talk with the server using $http, you’re all good.

Notice how all of the above are Angular-specific? That’s exactly why.

If you’ll use jQuery’s ajax() function instead of $http, you’ll see things stop working. Same goes for listening to click events natively and not using ng-click, using setTimeout, and so on.

The price we have to pay in order to enjoy the magic, is to keep using Angular’s way of doing things.

But you can’t always be inside the walled-garden of Angular

Even if you really want to, sometimes you have to do stuff another way.

The common cases are:

  • Using a non-Angular widget/plugin: Like a data visualization using D3.
    Just because it’s not using Angular doesn’t mean you don’t want to handle the events like clicks in your Angular components.
  • Binding to events natively: Angular has handy directives like ng-click, ng-focus, etc.
    But it doesn’t have a directive for every event type there is.
  • setTimeout et al: In general you should use $timeout and $interval.
    But what if you’re using code that doesn’t know about them?
    A common example is Lodash’s _.debounce() function–it uses setTimeout internally.
  • Performance: Sometimes stepping outside of Angular is necessary.

What it looks like if you don’t use $scope.$apply

Usually, if your codebase has one of the above situations and you don’t handle it properly, things will feel “lagged”.

That means that, for example, you’ll click on something and expect it to change something on the screen, but it won’t change until some time passes, or you click something else.

That’s because the changes you made actually happened in the data model, but Angular’s digest loop didn’t execute to update the templates.

Once something else triggers the digest, like a click that uses ng-click or a $http call being resolved in the background, things will render and you’ll finally see what you hoped to see in the first place.

How to return to Angular’s supervision

It’s actually pretty easy. You just need to make sure to perform your code inside a $scope.$apply() block.

For example, say that we have a native event handler for the scroll event:

1
2
3
4
5
6
element.on('scroll', function () {
  $scope.$apply(function() {
    // Now we really do stuff, for example:
    updateNavigationState();
  });
});

It’s that simple. Once you do this, Angular will execute the code in the function you pass $apply and then run a digest loop so your changes are propagated throughout the app.

There’s a slight catch here, though: You need to make sure to call $apply from outside of the Angular “zone”. If you call $apply from within it, e.g. inside a function that gets called by ng-click, you’ll get an error.

This is one of the only remaining reasons to inject $scope into your controllers in modern Angular.

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!

Angular 2 Is Out: Should You Start Using It?

| Comments

“Should I learn Angular 1.x or Angular 2?”
“Can we start developing in Angular 2?”
“When should we start migrating our 1.x app to Angular 2, if ever?”
“Is anyone really using Angular 2 yet?”

In all the time I’ve been working in Angular and blogging about it, the most frequently asked question by far has been “when should I start using Angular 2?” It’s been this way since it was announced 2 years ago. Now that 2.0 has finally been released it’s becoming even more frequent.

I decided to put into writing the same answer that I’ve been giving my clients lately.

Keep in mind, this is my pragmatic recommendation for companies with teams, new hires, paying clients and business goals (i.e. businesses).

tl;dr No Angular 2 in production yet

I think the responsible approach for anyone who needs to consistently ship features in the upcoming months and support the project they’re working on for at least a year, is to wait and see how things turn out.

Yes, Angular 2 is great. Yes, I’m sure it’s going to be sooo stable and full of rainbows from now on.

But maybe, it’s gonna get changed some more in a significant way real soon. I certainly don’t feel confident enough in its stability yet to recommend any company to invest hundreds of thousands of dollars and risk missing deadlines just to be on the bleeding edge.

Why not just yet

Changes are coming

I love the core Angular team, I trust them to be professionals and I’ve been making a living writing Angular for 4 years now.

And yet, I’m not as confident as they are about the near-term stability of Angular 2. I’m pretty certain we’ll have some more medium-sized changes soon.

I mean, there were still major changes going on just 2 months ago. And now we’re really really really done changing the router? I hope so, but won’t be putting money on that.

Wait a few more months, see how things look after a few update releases.

3rd party libraries are still not baked

This is one of the most crucial points. You don’t just want Angular 2, you want an ecosystem.

Lots of libraries are still working on finalizing their Angular 2 support (and given the previous section, can you blame them for not being ready yet?).

Writing a big project now means you might be able to use the final Angular 2.0, but most other libraries will be in alpha/beta. It’s cool and edgy, but it’s not how you run a business.

If you’re not into TypeScript you’re gonna have a bad time

The Angular 2 docs for plain JavaScript, both ES5 and ES6/2016 are still MIA.

The vast majority of material you’ll find is in TypeScript. TypeScript looks very nice, and the team is pushing it very hard to be the default in Angular 2.

But can we be 100% certain that TypeScript will be the most popular way to do Angular in a year? Google has a nasty track record with languages-that-compile-to-JS (cough GWT cough Dart cough). Are we sure this is the one that’s going to take off?

And since TypeScript is used mainly in the Angular corner of the universe, it means investing in learning a language, tool chain, editors, and more – quite a leap of faith.

If you want to do it in JS, which is officially supported, you’re gonna have a very hard time finding resources right now.

Heck, there’s even Dart(?!?) documentation on the official site before the JS docs. I mean, come on.

Lack of docs and knowledge in general

In my side projects I might enjoy investing lots of time digging into a problem in order to understand how best to use a tool for a specific need.

At work, where my real intention is to deliver working products, I rather focus on my business’s problems and actually find answers for questions on Stack Overflow etc. Yes, things are getting better, but they’re not quite there yet.

Not just for Angular 2 itself, but also for all the libraries which haven’t reached a stable release yet or aren’t widely used (i.e. all of them).

Hiring experienced developers in the near term

I’ll be the first to say that any developer worth their salary should be able to learn whatever tool is thrown at her. And yet, no one can become a master in something this complicated in a couple of days.

If you have business goals you need to accomplish and expect to hire more developers soon, it will be about an order of magnitude easier to get someone experienced in Angular 1.x than 2.

Who should use Angular 2 in production?

Anyone that doesn’t care about the above.

That’s basically people working on small scale projects, POCs and prototypes.

Then when should we start using Angular 2?

I used to think 2.1 would be a good time, but with the announcement of semantic versioning coming to Angular, it sounds like Angular 3 will be good time (expected to be released in Q1 2017).

In the mean time

LEARN

Just because you shouldn’t writing major projects in it at work doesn’t mean you can’t start prepping for it.

Start learning, do some tutorials, play with TypeScript, write a few sample apps (yes, you’re probably going to write another To Do app).

It’s good to be in the loop, and even if things change – you don’t care about maintaining your sandbox code, you just care about starting to be acquainted with the concepts.

Don’t get stressed about the hype

The JS community is mainly obsessed with hype, and in our Angular part of the world, that means Angular 2 stuff.

You can’t open reddit/ng-newsletter/whatever without seeing Angular 2 posts. Actually, on most of them the majority is Angular 2 posts.

This might make you feel like you’re the only one keeping the lights on for Angular 1. You’re not. Really.

I promise.

Heck, I wrote quite a few Angular 2 posts. That doesn’t mean you should start using in in production just yet.

Prepare your existing Angular codebase

Maybe in 6 months we’ll all as a community come to the realization that it’s best to rewrite all your existing code in TypeScript and Angular 2.

Maybe we’ll just settle on interoperability between Angular 1.x and Angular 2.

And maybe we’ll see Angular 2 needs some more time and keep at it with plain 1.x

(And yes, maybe you’ll decide that it’s best for you to drop Angular entirely. Ssssh.)

But, in just about 99% of the cases you’ll profit from making sure the current Angular 1.x development you do is modern Angular 1.5.

Writing component-based Angular, getting rid of controllers, etc. will benefit most code bases and make pretty much any future move easier.

I wrote about some aspects here.

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!

Animating Transitions in 2 Minutes with ngAnimate and CSS

| Comments

In my previous post, which is a short introduction to ngAnimate, we saw how just including ngAnimate in a project and a dozen lines of CSS can add slick animations to ng-repeat easily.

That was a very simple use-case, and in this post I want to show you how you can use it to animate transitions inside any container you have, with about the same complexity!

Our example, simple pagination

Say we have a regular component that displays a list. It has basic pagination – we only display a fragment of the list and there’s a “next” button to move on to the next fragment.

Our animation-less component would look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
angular.module('app', ['ngAnimate']).component('parent', {
  template: [
    '<button ng-click="$ctrl.nextPage()">Next</button>',
    '<div class="container">',
      '<div class="page">',
        '<div ng-repeat="line in $ctrl.pages[$ctrl.currentPage]" 
              ng-bind="line.text"></div>',
      '</div>',
    '</div>'
  ].join(''),
  controller: function() {
    var self = this;

    this.currentPage = 0;
    this.pages = [
      // Here be pages of stuff...
    ];

    this.nextPage = function() {
      self.currentPage = (self.currentPage + 1) % self.pages.length;
    };
  }
});

Now if you’re following along you can see that this is basically Angular 101. A simple component with a list of pages, and our template just displays that list with a little button to advance pages. Nothing fancy.

At this point we are sans-animation. Pressing the “next” button would instantly swap the contents of the page.

Not the best UX in the world, right?

Introducing ng-animate-swap

ng-animate-swap is a nifty little directive that’s part of ngAnimate (full docs here). What it does is… well… animate when you swap things!

Where in the previous post we saw how ngAnimate adds events to a set of situations it knows (e.g. leave, enter and move for ng-repeat), ng-animate-swap allows us to add leave and enter events to any DOM element!

You do it by passing ng-animate-swap an expression to watch for. Whenever that expression changes, it will trigger the animation to swap the container from the previous state to the new one.

In our case, we would like to swap the element with the page class, so it will animate whenever you move between pages.

The line we change in the template, after the changes, looks like this:

1
<div class="page" ng-animate-swap="$ctrl.currentPage">

Pretty simple, right? We tell ng-animate-swap to listen for page changes.

Now, with a dozen or so lines of CSS we’ll add a basic animation and, voila, here’s your slick animation:

I won’t go into the CSS in this post, but you can see if for yourself, along with a live example, here.

With basically no JavaScript changes and very minimal template changes, ngAnimate gives us a lot of power to add animations to our apps.

Keep that in mind the next time you need to spice a screen up a little.

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!

ngAnimate Basics: Pure CSS ng-repeat Animations

| Comments

Little touches of animation can make any app feel so much more slick, mature and responsive. Adding animations, though, can be a PITA that involves making your tidy code messier. Add this class, stop that animation, find the right DOM element. Bleh.

Angular’s own ngAnimate can really save you a lot of work and keep your code clean. But its documentation can be a bit hard to grok.

In this post you’ll see how in just a few lines of CSS you can add nice animations to your ng-repeats, using ngAnimate.

Setup

First, make sure that your app has ngAnimate, since it doesn’t come built-in with the vanilla angular.js file. That means that you should probably add angular-animate to your dependencies manager, and make sure to add 'ngAnimate' to your module’s list of dependencies (e.g. angular.module('app', ['ngAnimate']).

ngAnimate basics

The way ngAnimate works is that it has support for several scenarios which you can then add animations for.

In our examples, we’ll use its support for 2 ng-repeat events: enter and leave. The enter event is triggered when a new element is being added to collection you are ng-repeating. The leave event, surprisingly, triggers when an element has been removed. (There are many more cases, like an element whose position changes in the collection, and support for ng-show, etc.)

To use these events with basic CSS animations, you need to handle 2 situations: once the event is starting to happen, and once the event has completed.

For example, let’s think about our enter event. We will make it so that every element that gets added to our list will not just “pop” on screen, but instead will slowly appear by animating its height from 0 to the wanted size (kind of like jQuery’s slide animations).

So, at the triggering of the enter event we will add the CSS property height: 0, and at the end of the event (called “active” in ngAnimate) we will set the height to its regular size.

Show me the code

Well, there’s actually not any real code, but some HTML and CSS. Yeah, it’s that simple :)

Say our list gets rendered like so:

1
2
3
<div class="slide" ng-repeat="item in $ctrl.list"
     ng-bind="item.name">
</div>

Notice that every element in the ng-repeat has the slide class. Lets animate it:

1
2
3
4
5
6
7
8
9
10
11
12
13
.slide {
  overflow: hidden;
  transition: 0.3s;
  height: 30px;
}

.slide.ng-enter {
  height: 0;
}

.slide.ng-enter.ng-enter-active {
  height: 30px;
}

As you can see, we set the regular CSS, and then handle the 2 states of the ngAnimate enter event: once it triggers the height is 0, and it slowly grows back to 30px. The actual animation is done by the browser automatically, because we’ve set the transition CSS property.

It looks like this:

That’s it, pretty simple right? I’ll be writing soon about more advanced ngAnimate techniques.

You can play with an online example here, which also shows the use of the leave event.

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!

Angular Interview Question Deep Dive: Implement ng-click

| Comments

For this post I decided to do something a bit different. We will go through an Angular interview question that I quite like:

How would you implement the ng-click directive yourself?

This sounds pretty simple, but as we’ll see, there are many little details and decisions that seem trivial that actually have significant impact.

I’m sure that even seasoned Angular veterans will pick up something new in this post. And on that note: let’s dig in!

The very trivial first implementation

First, I’ll say that a lot of newbie Angular devs find it hard to write custom directives – and that’s to be expected.

Now, let’s look at something that a newbie might write as an answer:

1
2
3
4
5
6
7
8
9
10
11
12
angular.module('app').directive('myClick', function() {
  return {
    scope: {
      myClick: '&'
    },
    link: function($scope, $element) {
      $element.on('click', function($event) {
        $scope.myClick({$event: $event});
      });
    }
  };
});

This should look pretty straightforward: we’ve created a template-less directive that has an isolated scope which allows it to receive the callback that we should execute on clicks.

Then, in the link function, we set up a click handler and whenever a click happens, we call the bound callback.

But why aren’t clicks always working?

If you’ll try to run this example and, say, have the click callback change something so that your view will get updated, you might notice things are acting a bit weird. Sometimes the click changes happen immediately, sometimes they only get updated after several clicks.

The issue is, of course, that we’ve forgotten to call $scope.$apply. The click listener is native code that Angular’s not aware of. That means that when our click handler runs Angular has no idea that it should fire off a digest cycle in order to update everything.

The fix is pretty simple: just change the click handler body to:

1
2
3
$scope.$apply(function() {
  $scope.myClick({$event: $event});
});

Nitpicker’s corner: Why use a directive instead of a component? If you’ve been following my post at all in 2016, you probably have seen me say that come Angular 1.5, directives are 98% dead and you should almost never write a directive. Guess what? This is exactly where you should be using a directive: for template-less logic. You can’t do it with a component.

Hey! Don’t you need to remove the click handler?

I’ve seen a lot of people get confused about the need to remove native event handlers.

The thing is, that since we’re adding a click handler to our directive’s root element, we are guaranteed that as long as the directive is alive, the DOM will be alive and vice-versa. The handler will die when the element will die, no need to get fancy here.

The need to cleanup comes in more complex scenarios where your handler’s logic might not be relevant for the whole duration of the DOM element that you’re binding on.

Is that it? No! Round 2

Well, I have to say that if someone would have written me the above answer, including the $scope.$apply, I would be already pretty pleased.

But that’s not really the “best” way to get this task done, as you can see by digging through Angular’s code by yourself (I’ll leave that as an exercise to you, dear reader, I promise it’s quite easy).

Our template-less directive actually has a bit of a performance hit that’s not really needed. For every element that we’ll want to listen for clicks on, we’ll be creating a new isolated scope, just to pass the callback in.

This isolated scope is never bound to the DOM itself, because our directive has no template, and so the scope is pretty useless.

Instead, the better and more efficient way of doing it would be by changing our template-less directive to also be scope-less:

1
2
3
4
5
6
7
8
9
10
11
12
angular.module('app').directive('betterClick', function($parse) {
  return {
    link: function($scope, $element, $attrs) {
      var callbackFn = $parse($attrs.betterClick);
      $element.on('click', function($event) {
        $scope.$apply(function() {
          callbackFn($scope, {$event: $event});
        });
      });
    }
  };
});

What just happened here?

Well, first of all, you can see that we’ve dumped the scope thing altogether, which means that this directive doesn’t create a new scope at all, but instead simply makes use of whatever scope it’s already in.

But, since we’re not using the dandy & binding anymore, we have to do some work on our own. We would like to get the callback like you would with ng-click: <div better-click="clicked($event)"></div>.

To get a hold of the function that we should call, we’re using the $attrs object to get the expression that we should use for the callback: $attrs.betterClick.

Then, we use the built in $parse service in order to parse the expression string into a function that we can call whenever we need to.

Inside our click handler we simply call this new function ourselves (with the right scope), whenever a click happens.

Voila!

Is this really worth the hassle? How much efficiency are we talking about?

Whenever I talk about Angular performance, I always stress that you have to measure your optimizations in order to make sure that they are, indeed, optimizations.

Our optimization: The seasoned Angular developer would realize that our optimization boils down, essentially, to not creating extra scopes for each click handler in our app.

As you can expect, click handlers are very common, and we’d like them to be as performant as possible.

In benchmarks I ran, it was clear that the performance hit of myClick directive is x2.5-x3 that of betterClick.

WAT?

Yes. That’s because every scope in our Angular app, even an isolated scope that’s essentially empty, is still another thing that Angular has to check in every digest cycle.

Once you have enough of these click handlers on screen, it adds up – which is exactly why the Angular core team implemented ng-click (and basically all the rest of the simple event handlers) in this way.

Back to our interview question

As I said, I wouldn’t expect a novice Angular developer to write this performant version.

Actually, I know many solid developers who have been doing Angular for years and yet wouldn’t have thought about this performance issue.

But, I would expect them to be able to reason about why the latter solution is better and know how to benchmark it themselves to prove it.

Cheers!

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!

Understanding Angular’s @ Binding

| Comments

I’ve written about the new > one way binding in Angular, and explained the magic behind & bindings. It only felt natural to explain what is likely the least-understood binding type: @.

I’ve seen people use it by mistake, not understanding how exactly it works and when you should (or shouldn’t) use it. There are also situations where it makes things more explicit and clearer. Let’s dig in!

An example: a password input component

Say we want to create a very simple component that’s used to enter a password. It has all the needed validations, and we’d like to use it throughout our app, wherever the user needs to enter a password.

Our first pass might look something like this:

1
2
3
4
5
6
7
8
9
10
angular.module('app').component('passwordBox', {
  template: [
    '<input type=password ng-model="$ctrl.ngModel"',
       ' placeholder="{{ $ctrl.placeholder }}">'
  ].join(''),
  bindings: {
    ngModel: '=',
    placeholder: '='
  }
});

This simply creates a password input element and allows us to specify a placeholder if it’s empty.

Here’s how you’d use it in a template:

1
2
3
<password-box ng-model="$ctrl.password"
              placeholder="'Enter password'">
</password-box>

Pretty straightforward, but can you guess what’s bothering me?

The placeholder attribute will almost always be a simple string – why does every user of our component need to wrap it in quotes? Are we saying it would also be acceptable to pass a non string value, like an object? Surely not!

For exactly this purpose we have the @ binding – it allows us to specify that we want to receive the string value of the attribute.

Changing the bindings definition in our component so placeholder uses @ makes the password box component a bit slicker:

1
2
3
<password-box ng-model="$ctrl.password"
              placeholder="Enter password">
</password-box>

Angular will now plainly take the value of the DOM attribute (which is always a string) and pass it along to our component.

What if you need the string to be dynamic?

Just because we’re using @ binding doesn’t mean we will always have to stick with static strings. For example, we can make the placeholder dynamic:

1
2
3
<password-box ng-model="$ctrl.password"
    placeholder="{{ $ctrl.user }}'s password">
</password-box>

Angular will automatically interpolate that string whenever $ctrl.user changes, and that change will be reflected in our password box component!

This is a little gem in Angular that’s worth knowing: it allows us to write easier-to-use components, and provides explicitness. A win-win!

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!

Stop ng-repeating options: use ng-options

| Comments

A pet peeve of mine is seeing Angular code with <select> tags that uses ng-repeat to generate the options, like so:

1
2
3
4
5
<select ng-model="$ctrl.mode">
  <option ng-repeat="option in $ctrl.options"
    ng-value="option" ng-bind="option.name">
  </option>
</select>

One of the great little details about Angular is the awesome ng-options directive, which I find more concise and is very powerful.

First, here is the basic translation of the above:

1
2
3
<select ng-model="$ctrl.mode"
  ng-options="o.name for o in $ctrl.options">
</select>

The trick here is that ng-options is completely in charge of creating the actual <option> elements for us.

Now, let’s see where it shines.

Nullability of a select

When using ng-options, once you initialize the ng-model value to one of the options there’s no way for the user to reset it to an empty value by default.

To allow setting it to null, we simply add a special empty <option> tag. Here’s how the above example would look with nullability:

1
2
3
4
<select ng-model="$ctrl.mode"
  ng-options="o.name for o in $ctrl.options">
  <option value=""></option>
</select>

Using an object as a value

Another thing is that a lot of developers miss the fact that Angular lets us use selects with values that aren’t simple strings, but actual objects.

In the first example I showed how you do it manually, using ng-value, instead of the value property. This tells Angular to bind to our model the actual object that the expression evaluates to.

ng-options of course does that automatically for us, but we can customize the bound value even more if needed, for example:

1
2
3
4
<select ng-model="$ctrl.mode"
  ng-options="o.value as o.name for o in $ctrl.options">
  <option value=""></option>
</select>

Disabling elements

Another reason that I usually prefer using native HTML elements and not wrappers (e.g. Select2) is because they usually pack so much under the hood.

For example, you can easily have a few options be disabled dynamically:

1
2
3
4
5
<select ng-model="$ctrl.mode"
  ng-options="o.name disable when $ctrl.disabled(o)
              for o in $ctrl.options">
  <option value=""></option>
</select>

The disable when clause lets you specify an expression that decides which options will be displayed but won’t be enabled for actual selection.

So, please, don’t roll your own <option> elements unless you have a good reason!

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!

Properly Wrapping Native JavaScript with $q Promises

| Comments

One of my most popular posts ever is the post about how a lot of Angular developers are using $q wrong (specifically $q.defer()).

Yes, in the vast majority of cases, you don’t really need to create a promise by your own from scratch.

But, in some cases it is a valid and powerful tool. The most common one is when you need to wrap some native JavaScript code that’s not promisified to make it play-along with your Angular awesomeness.

In this post we’ll quickly learn how it’s best to do it. There are 2 different ways of achieving this, let us go over them.

Our example would be a scenario where you’re writing some kind of image preloading service that should return a promise letting you know when the image has finished preloading.

Technique 1 – Using $q.defer()

This is the more barebones approach. The $q.defer() actually returns a “deferred” object.

This object has a .promise property, which returns your newly created promise.

It also has 2 methods, resolve and reject, which you can call at the right time to resolve or reject your promise:

1
2
3
4
5
6
7
8
function preloadImage(imgSrc) {
  var deferred = $q.defer();
  var img = angular.element('<img>');
  img.on('load', deferred.resolve);
  img.on('error', deferred.reject);
  img.attr('src', imgSrc);
  return deferred.promise;
}

As you can see, we first create the deferred object and then set up our preloaded image to point at it, and finally return the new promise;

Technique 2 – $q constructor

This is a very similar way to achieve the same thing, only more succinct:

1
2
3
4
5
6
7
8
function preloadImage(imgSrc) {
  return $q(function(resolve, reject) {
    var img = angular.element('<img>');
    img.on('load', resolve);
    img.on('error', reject);
    img.attr('src', imgSrc);
  });
}

As you can probably understand, $q’s constructor-function (or whatever this thing should be called) is syntax sugar for directly calling defer().

Personally I tend to use the second technique. Beginners usually understand it the first time they come upon it even without reading the documentation.

It also means a little less moving parts, which is always good.

And lastly, it’s just simpler – I have seen people waste several hours simply because they ended up doing return deferred instead of return deferred.promise, so why even risk it?

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!