codelord.net

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

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.


Do you have an existing Angular 1.x app that makes you worried about its future?
You don’t want your app to be left behind and become legacy code.
But it’s not easy clearing the time to learn Angular 2.
And who has the energy to convince management that you need to change frameworks, delay your schedules and do the Big Ol’ Rewrite?

But what if you could make sure your app keeps its options open?
What if you could make it future-proof, all the while shipping features like a boss?
You’ll work in a codebase that uses the latest and greatest, have easy maintenance and happy stakeholders!

The Future-proof Angular Guide can help you get there.
With this no-fluff course you’ll learn how to quickly adapt your existing Angular 1.x app to the latest components paradigm, as you go about your regular work.
You’ll gradually turn your app into something that is modern and idiomatic, converting directives and getting rid of controllers.
And then, once your app is shaped The Right Way™, you’ll be able to keep shipping like a boss, and have your options open.

Sign up to be notified when the course is ready (and get more of these pragmatic Angular posts in the meantime).

Learn how to upgrade your Angular 1 app easily, step by step!

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.


Do you have an existing Angular 1.x app that makes you worried about its future?
You don’t want your app to be left behind and become legacy code.
But it’s not easy clearing the time to learn Angular 2.
And who has the energy to convince management that you need to change frameworks, delay your schedules and do the Big Ol’ Rewrite?

But what if you could make sure your app keeps its options open?
What if you could make it future-proof, all the while shipping features like a boss?
You’ll work in a codebase that uses the latest and greatest, have easy maintenance and happy stakeholders!

The Future-proof Angular Guide can help you get there.
With this no-fluff course you’ll learn how to quickly adapt your existing Angular 1.x app to the latest components paradigm, as you go about your regular work.
You’ll gradually turn your app into something that is modern and idiomatic, converting directives and getting rid of controllers.
And then, once your app is shaped The Right Way™, you’ll be able to keep shipping like a boss, and have your options open.

Sign up to be notified when the course is ready (and get more of these pragmatic Angular posts in the meantime).

Learn how to upgrade your Angular 1 app easily, step by step!

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!


Do you have an existing Angular 1.x app that makes you worried about its future?
You don’t want your app to be left behind and become legacy code.
But it’s not easy clearing the time to learn Angular 2.
And who has the energy to convince management that you need to change frameworks, delay your schedules and do the Big Ol’ Rewrite?

But what if you could make sure your app keeps its options open?
What if you could make it future-proof, all the while shipping features like a boss?
You’ll work in a codebase that uses the latest and greatest, have easy maintenance and happy stakeholders!

The Future-proof Angular Guide can help you get there.
With this no-fluff course you’ll learn how to quickly adapt your existing Angular 1.x app to the latest components paradigm, as you go about your regular work.
You’ll gradually turn your app into something that is modern and idiomatic, converting directives and getting rid of controllers.
And then, once your app is shaped The Right Way™, you’ll be able to keep shipping like a boss, and have your options open.

Sign up to be notified when the course is ready (and get more of these pragmatic Angular posts in the meantime).

Learn how to upgrade your Angular 1 app easily, step by step!

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!


Do you have an existing Angular 1.x app that makes you worried about its future?
You don’t want your app to be left behind and become legacy code.
But it’s not easy clearing the time to learn Angular 2.
And who has the energy to convince management that you need to change frameworks, delay your schedules and do the Big Ol’ Rewrite?

But what if you could make sure your app keeps its options open?
What if you could make it future-proof, all the while shipping features like a boss?
You’ll work in a codebase that uses the latest and greatest, have easy maintenance and happy stakeholders!

The Future-proof Angular Guide can help you get there.
With this no-fluff course you’ll learn how to quickly adapt your existing Angular 1.x app to the latest components paradigm, as you go about your regular work.
You’ll gradually turn your app into something that is modern and idiomatic, converting directives and getting rid of controllers.
And then, once your app is shaped The Right Way™, you’ll be able to keep shipping like a boss, and have your options open.

Sign up to be notified when the course is ready (and get more of these pragmatic Angular posts in the meantime).

Learn how to upgrade your Angular 1 app easily, step by step!

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!


Do you have an existing Angular 1.x app that makes you worried about its future?
You don’t want your app to be left behind and become legacy code.
But it’s not easy clearing the time to learn Angular 2.
And who has the energy to convince management that you need to change frameworks, delay your schedules and do the Big Ol’ Rewrite?

But what if you could make sure your app keeps its options open?
What if you could make it future-proof, all the while shipping features like a boss?
You’ll work in a codebase that uses the latest and greatest, have easy maintenance and happy stakeholders!

The Future-proof Angular Guide can help you get there.
With this no-fluff course you’ll learn how to quickly adapt your existing Angular 1.x app to the latest components paradigm, as you go about your regular work.
You’ll gradually turn your app into something that is modern and idiomatic, converting directives and getting rid of controllers.
And then, once your app is shaped The Right Way™, you’ll be able to keep shipping like a boss, and have your options open.

Sign up to be notified when the course is ready (and get more of these pragmatic Angular posts in the meantime).

Learn how to upgrade your Angular 1 app easily, step by step!

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?


Do you have an existing Angular 1.x app that makes you worried about its future?
You don’t want your app to be left behind and become legacy code.
But it’s not easy clearing the time to learn Angular 2.
And who has the energy to convince management that you need to change frameworks, delay your schedules and do the Big Ol’ Rewrite?

But what if you could make sure your app keeps its options open?
What if you could make it future-proof, all the while shipping features like a boss?
You’ll work in a codebase that uses the latest and greatest, have easy maintenance and happy stakeholders!

The Future-proof Angular Guide can help you get there.
With this no-fluff course you’ll learn how to quickly adapt your existing Angular 1.x app to the latest components paradigm, as you go about your regular work.
You’ll gradually turn your app into something that is modern and idiomatic, converting directives and getting rid of controllers.
And then, once your app is shaped The Right Way™, you’ll be able to keep shipping like a boss, and have your options open.

Sign up to be notified when the course is ready (and get more of these pragmatic Angular posts in the meantime).

Learn how to upgrade your Angular 1 app easily, step by step!

Not Everything in Angular Should Be a Singleton

| Comments

When all you have is a hammer, everything looks like a nail.

Angular services/factories are singletons. This has caused so many teams to forget about the joy of self contained objects that take care of themselves.

You don’t have to put all your code in static singletons and sling dummy json objects back and forth across your app.

You can enjoy real objects that make code easier to maintain!

How your code probably looks

You have a service for handling some kind of model, e.g. a Course would have a CoursesService. That service would be responsible for creating the courses and manipulating their data.

For example, you’ll use CoursesService.create(name, students, schedule). That will return some json object that you’ll then keep in your controller.

Whenever the controller would need some data about the course, it would have to use the service, passing it the object:

CoursesService.getEndDate(course)

Not only is this not very OOP-ish, it means that every binding you have in your template, e.g. to show the end date, would have $ctrl.getEndDate(course) which you’ll then implement in the controller just to proxy it to the CoursesService.

Also, having the course json object by itself isn’t usually enough, and to use it you’ll have to inject CoursesService.

Bleh.

How your code could look

Instead, we can create a real Course model that encapsulates its own data and knows how to manage by itself.

We create a service like so:

1
2
3
4
5
6
7
8
9
10
angular.module('app').factory('Course', function() {
  return Course;

  function Course(name, students, schedule) {
    this.name = name; // Etc.

    // Put the logic here!
    this.getEndDate = ...;
  }
});

And now, all of a sudden, our code has become nicer!

You create a course using new Course(...) and then just use this instance, instead of always holding on to an object and the service.

And, for example, your templates could now directly use $ctrl.course.getEndDate() instead of proxying it using the controller.

Huzzah!


Do you have an existing Angular 1.x app that makes you worried about its future?
You don’t want your app to be left behind and become legacy code.
But it’s not easy clearing the time to learn Angular 2.
And who has the energy to convince management that you need to change frameworks, delay your schedules and do the Big Ol’ Rewrite?

But what if you could make sure your app keeps its options open?
What if you could make it future-proof, all the while shipping features like a boss?
You’ll work in a codebase that uses the latest and greatest, have easy maintenance and happy stakeholders!

The Future-proof Angular Guide can help you get there.
With this no-fluff course you’ll learn how to quickly adapt your existing Angular 1.x app to the latest components paradigm, as you go about your regular work.
You’ll gradually turn your app into something that is modern and idiomatic, converting directives and getting rid of controllers.
And then, once your app is shaped The Right Way™, you’ll be able to keep shipping like a boss, and have your options open.

Sign up to be notified when the course is ready (and get more of these pragmatic Angular posts in the meantime).

Learn how to upgrade your Angular 1 app easily, step by step!

$scope.$watch and controllerAs

| Comments

You know that by now your Angular code should be pretty $scope free. The controllerAs syntax makes it so you shouldn’t be accessing $scope in order to store information on it.

But, scopes are still an important part of Angular and sometimes you have to use them.

One not-so-rare example is the $scope.$watch() function. With the introduction of controllerAs syntax we now have 2 seemingly interchangeable ways to use it. But, they are not exactly the same and I think you should only be using one. Let’s quickly go over it.

The olden days

In the pre-controllerAs days we would put everything directly on the $scope.

So, you might have $scope.foo and then, to watch for changes, you’d use $scope.$watch('foo', fooChanged).

That just worked. But with controllerAs it’s not that simple. If in your controller code you use this.foo, you can no longer just watch for changes using $scope.$watch('foo', ...).

That’s because the 'foo' part looking for foo directly on the scope, not your controller’s instance.

The bad option – using the controller’s name

The way a lot of people are solving this is by using the controller’s name in the expression.

If you’re using Angular 1.5’s components then the controllerAs name is $ctrl by default. So you’d use $scope.$watch('$ctrl.foo', ...).

If you have a different name, like stuffCtrl then you’d use $scope.$watch('stuffCtrl.foo', ...) etc.

I don’t like this for several reasons:

  • It feels foreign to me to use a name that’s essentially only used in the template (the controllerAs name), while the rest of the controller code uses this or vm.
  • Using this name means that in case you decide to rename it, you’ll have to look for it in both the template and the controller code.

The right way

It was always possible to pass a function to $watch() as the expression that you’re keeping track of.

Because of that, it’s possible to do something like this:

$scope.$watch(function() { return vm.foo; }, ...)

(Of course, it’s even nicer if you’re using ES6’s arrow functions.)

I believe this is better, even though it involves more typing, because it keeps your controller code consistent. You always refer to things the same, and there are no magic strings.


Do you have an existing Angular 1.x app that makes you worried about its future?
You don’t want your app to be left behind and become legacy code.
But it’s not easy clearing the time to learn Angular 2.
And who has the energy to convince management that you need to change frameworks, delay your schedules and do the Big Ol’ Rewrite?

But what if you could make sure your app keeps its options open?
What if you could make it future-proof, all the while shipping features like a boss?
You’ll work in a codebase that uses the latest and greatest, have easy maintenance and happy stakeholders!

The Future-proof Angular Guide can help you get there.
With this no-fluff course you’ll learn how to quickly adapt your existing Angular 1.x app to the latest components paradigm, as you go about your regular work.
You’ll gradually turn your app into something that is modern and idiomatic, converting directives and getting rid of controllers.
And then, once your app is shaped The Right Way™, you’ll be able to keep shipping like a boss, and have your options open.

Sign up to be notified when the course is ready (and get more of these pragmatic Angular posts in the meantime).

Learn how to upgrade your Angular 1 app easily, step by step!

Understanding Angular’s One-Way Binding

| Comments

Angular 1.5 introduced a new kind of binding option to directives/components. Along the often-used = for regular two-way binding and & for expression binding, we now have <: one-way binding.

What does it mean exactly?
When should you use it?
When shouldn’t you?
And why did we even need another kind of binding?
Sit tight!

How today’s two-way binding works

Today’s two-way binding basically has 3 aspects: passing the reference first, synchronizing changes from the parent and synchronizing changes from the child:

Passing the same reference means that when your child component is initialized with foo="$ctrl.foo" then Angular will pass it a reference to the same foo object as in the parent controller. This initializes them to start working off of the same data.

Because this is the same reference, changes made to a property on foo by either parent or child will be seen by the other, e.g. $ctrl.foo.baz = 'a'.

Synchronizing changes from the parent means that if our parent component overrides foo with a new object, i.e. this.foo = otherFoo then Angular’s watch will notice and change the child component’s foo to reference the same new object.

Synchronizing changes from the child are the other coin of the two way binding – if the child assigns a new reference it will also be copied to the parent.

You ain’t gonna need it

Even if you knew about the synchronization from the child to the parent, and most don’t know, it’s likely you never actually had to use it.

Having the objects be initialized with the same reference is enough for 95% of the components. The synchronization from the parent likely covers another 4.9%.

The other way around is just obscure, costs you in performance and, to be honest, sounds like a code smell.

Be explicit and don’t pay for what you don’t need

Basically, your rule-of-thumb should be to always default to one-way binding, like so:

1
2
3
4
5
6
7
angular.module('app').component('myComponent', {
  templateUrl: '...',
  bindings: {
    foo: '<' // <-- This!
  },
  controller: function() { ... }
});

It is always better to be explicit in code. One-way binding means you’re not doing anything funky to the object reference.

Also, there’s a performance penalty to using two-way bindings when you don’t need them. One-way bindings require less work on every digest and so you can also gain a small boost (I say small because from measuring it seems small – but it’s essentially free, why not?).

Cheers!


Do you have an existing Angular 1.x app that makes you worried about its future?
You don’t want your app to be left behind and become legacy code.
But it’s not easy clearing the time to learn Angular 2.
And who has the energy to convince management that you need to change frameworks, delay your schedules and do the Big Ol’ Rewrite?

But what if you could make sure your app keeps its options open?
What if you could make it future-proof, all the while shipping features like a boss?
You’ll work in a codebase that uses the latest and greatest, have easy maintenance and happy stakeholders!

The Future-proof Angular Guide can help you get there.
With this no-fluff course you’ll learn how to quickly adapt your existing Angular 1.x app to the latest components paradigm, as you go about your regular work.
You’ll gradually turn your app into something that is modern and idiomatic, converting directives and getting rid of controllers.
And then, once your app is shaped The Right Way™, you’ll be able to keep shipping like a boss, and have your options open.

Sign up to be notified when the course is ready (and get more of these pragmatic Angular posts in the meantime).

Learn how to upgrade your Angular 1 app easily, step by step!

Understanding Angular’s & Binding

| Comments

Angular has several cases where the syntax trips you up, or where it’s just not clear what should you use. Most famously, there’s services vs. factories and ng-show vs ng-if. More recently we now have components vs. directives.

Another thing that I’ve seen people get mad about time after time is the & binding for passing functions to directives/components. “The & callback binding trips me up EVERY TIME I just it.”

Let’s understand exactly what it is. Once you grok it, you’ll never get it wrong again.

Can you use it in a sentence?

First, here’s an example component that has one of these & bindings:

1
2
3
4
5
6
7
8
9
10
angular.module('app').component('foo', {
  templateUrl: '...',
  bindings: {
    callback: '&'
  },
  controller: function() {
    // ...
    this.callback();
  }
});

As you can see, we have a simple binding called callback. The usage of this component would look something like this:

<foo callback="$ctrl.myCallback()"></foo>

This means that whenever the foo directive would call the callback binding, the myCallback function on the caller’s controller would be triggered.

The tricky bit: parameters

Now, what everyone get mixed up with is using & with functions that get parameters.

Say that our callback wants to pass an argument. The component would be created like so:

<foo callback="$ctrl.myCallback(value)"</foo>

But inside the component, we calling syntax would look quite foreign the first time you see it:

this.callback({value: 'whatever'});

WAT

Yes. Doing something like this.callback('whatever') wouldn’t work.

What’s going on?

Technically speaking, when you use the & binding, Angular doesn’t just do 2-way binding the regular way.

It takes the expression you use, in our example $ctrl.myCallback(value) and saves it.

When you call it, Angular evaluates that expression on the parent scope.

You see, when using & you don’t have to pass function, though that’s what we do 99.9% of the time. You can pass in any expression, and it would work.

So, in our example, we could have used:

<foo callback="$ctrl.values.push(value)"></foo>

And whenever we’d perform this.callback({value: 'whatever'}) it would get appended to the parent controller’s values array.

Because the & binding is so generic, it doesn’t really have a notion of function parameters – the expression could be anything.

When you pass it the object, it is actually a mapping of local variables to override. Angular takes the expression and evaluates it in the parent scope, but with the values you pass it added as the locals.

Wiseass note: Yes, this means we can call this.callback({value: 'whatever', $ctrl: something}) and the function call would be performed on the something object and not on our parent controller – because we override it!

Dear god, why?!

This was done so that you’ll be able to pass expressions instead of functions to anything in Angular.

Have you ever used ng-click="$ctrl.value = true" or something along those lines? Sometimes it’s easier to not use a function.

The core team wanted us to have this flexibility, and the price is that we have to call function in a way that feels a bit clunky.

But remember: You’re not really calling a function, you’re evaluating the expression with those values!

Now you know

If you’ll make the mental switch from treating & as “function binding” to just “expression binding”, I think you’ll be alright from now on.

Don’t get tripped up - subscribe to get more posts and really understand Angular!