codelord.net

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

Using ng-change instead of $watch in Angular

| Comments

In the olden days, before you used MVC frameworks such as Angular, you were probably used to doing stuff like this in jQuery:

1
2
3
4
5
function showNameChanged() {
    // stuff...
}

$('input.show-name').change(showNameChanged);

This achieves the simple task of performing an operation whenever the user typed something inside an input, using JS change events.

In Angular, though, most people would consider this code the equivalent:

1
<input type=text ng-model=show.name>
1
$scope.$watch('show.name', showNameChanged);

Now, you might think I’m being nit picky here, but I’d usually rather write it like this:

1
<input type=text ng-model=show.name ng-change="showNameChanged()">

ng-change?

I’m always surprised that this directive is foreign for a lot of newcomers to Angular, and that $watch seems to be the tool everyone reach for first. ng-change is a simple directive that operates much like using jQuery to register a change event listener.

In my opinion, this is the “real” equivalent of the first code sample we saw.

The differences

  • Using ng-change would call our showNameChanged() function only on actual changes to the input by the user. Watches, as you might know, are called in other cases too: right when they’re being defined the first time and on changes made to the value not by the user, e.g. programmatically.
  • I’m a big believer in expressing intent when writing code (you do know The 4 Rules of Simple Design, right?). If my intent is to only listen to changes by the user, and I don’t expect the input to be changed programmatically, I would rather explicitly show that. Using $watch means whenever you read this code in the future you’ll have to consider whether it’s being triggered by something else, too.
  • Another plus for intent for ng-change is that you can see from the template that this input is bound to something and how. Otherwise you’d need to start looking for the value in ng-model in the controller for usages. This way you can see right away who’s listening for these changes.
  • Less code. And less code == less things to debug. As you can see above we didn’t need to add another line to the controller to listen for input changes.
  • Using ng-change is a tiny bit more performant, since it uses one less watch expression. Since Angular knows it should only call the expression on change events it doesn’t need to keep evaluating it on every digest cycle, as opposed to, well, a watch. Yes, just this one doesn’t matter a lot, but across a big app these things stack up.

Of course, sometimes $watch is what you want. But sometimes – it ain’t!

Happy coding!

“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!

Comments