- 7 minutes read

There are no computed properties in Angular. Period. So what happens when you Google for computed properties?

Yeah, something unexpected happens. There's a tool called MobX which is well-known as a lightweight alternative to Redux and ngrx/store. As it turns out, it's lightweight enough to use without introducing a central data store. You can use it to implement computed properties without further ado.

Wait - what is a computed property?

If you're reading this, you're probably familiar with the change detection of Angular. We all love this. Each time an attribute in a component or a service changes, the screen is updated. It just happens. Easy as pie.

Until... well, one day or another, you'll display the result of a function. Some things are just too difficult to express in the EL language in the HTML template language, so it's natural to refactor the code. Shift it from the HTML snippet to the component, where it belongs.

Thing is, it definitely belongs there, and it even works, but the method is frequently called. The details seem to vary. Sometimes Angular decides that the result of the method doesn't change. But I've also seen thousands of calls per second.

OK, methods don't work. What about getters?

Another logical step - and an even more vicious trapdoor - is to guard your attribute with a getter. In theory, getters are just attributes, only the actual implementation remains in the dark. And that's precisely the problem. The intention is to hide the implementation from hurried developers who just want to use the attribute. "I don't care how it's calculated, just give me the getter."

However, we also hide the implementation from Angular. And that's bad. Angular doesn't have a clue when the attribute changes. Mind you, there might be a complicated formula in the getter. So it always assumes the value to be changed. As a result, Angular calls the getter time and again, diligently refreshing the screen with data that's already there.

Got it. But sure Angular has a solution for that?

There are two native solutions offered by Angular.

The first solution is to use an Observable. That's pretty cool, because Angular has been optimized with respect to Observables. The disadvantage is that Observables are an abstraction making it difficult to wrap your head around.

In the old days, we all complained about the amount of boiler-plate code introduced by languages such as Java. My favorite saying is "code that's not there is code you don't have to understand." Observables take this to another level. They are not just boiler-plate, they are difficult to understand, let alone debugging.

Don't get me wrong: I love the concept of reactive programming in general and Observables in particular. I just don't want to introduce them as long as there's a simple alternative. Little is won if you've implemented your application with an elegant pattern, only to find yourself in maintenance hell. Or to find your younger co-worker in maintenance hell. Many companies leave bug fixing to the rookies, because it's a good way to learn the application (it is!) and because developing new features is more prestigeous. I don't object this, but it's not an excuse to let the rookies struggle with code the "old hands" barely manage to understand. Mind you, we've all been rookies some time ago.

Talking about newbies: dear young professionals, the same applies to you, too. We all are proud about what we've learned, and be honest, we all are eager to show off. In the software industry, that's a bad trait. As a rule of thumb, boring code is good code. I don't like that rule, but then, I don't like co-worker complaining about my code, either. (And, boy, they did complain about me all-to-clever code!)

Cutting a long story short: Observables are an incredibly powerful concept, but at the same time, it's incredibly difficult to grasp. It's closely related to multithreading, which has a reputation of being difficult. I'd rather you avoid it unless absolutely necessary. Thanks!

OnPush

The other traditional solution is OnPush. In theory, this one looks very promising. It's about immutable data types, which is always good, and it gives you all the control you need. The drawback is that it shifts the burden of change detection to the programmer. It's a powerful idea, but again, I'd prefer to use it for the complex use-cases. Refactoring a lengthy boolean expression to a method isn't such a use-case.

Sometimes pure pipes are an alternative, too. But that's restricted to special cases.

Introducing computed properties

Vue.js has a really clever solution. There are (ordinary) properties, and there are computed properties. The latter are usually functions. The magic of Vue.js sees to it that the function is calculated only once. After that, the result is stored, until one of the parameter values changes. Then - and only then - is the function called again.

Angular doesn't offer such a solution. So I had little hope when I researched the topic.

MobX to the rescue

Can you imagine my surprise when I read the to our question on StackOverflow?

As it turns out, introducing computed properties to Angular consists of two simple steps:

  1. npm install --save mobx-angular mobx
  2. Use @observable and @computed attributes for bound properties

The general idea is to annotate the attributes which are used in a method with @observable. This advises MobX to observe the value of the attribute. If it changes, the entire MobX scope is marked dirty.

Methods are annotated with @computed. These methods are called if the MobX scope is dirty. After the first call, the values are cached, until one of the @observed properties change again.

A source code example (which is a simplified version of the code found at on StackOverflow) looks like so:

import { observable, computed } from 'mobx-angular'; @Component({ selector: 'app-multiplication-demo', template:

A =

B =

A * B = {{ getAB() }}

}) export class HomeComponent extends GenericAnimationContainer { @observable a: number = 2; @observable b: number = 3; @computed get AB() { return this.a * this.b; } }

Does this solve the problem?

A quick debugging session shows that we've solved our problem. Our @computed method is called only once, and only when one of the parameters change.

But wait - does this mean the method isn't called by Angular?

Not necessarily. Maybe Angular has been optimized with MobX in mind. If so, it can detect that there's no change so the change detection algorithm can calm down.

But I don't think so. More likely Angular still calls the method, possibly thousands of times per second. But this time, it just sees the proxy method generated by MobX. This is a fast method merely returning the value from the cache.

So chances are the CPU load is reduced to the point of hardly being noticeable. Please do check this before putting the MobX solution into production. That said, I reckon MobX is a satisfying solution in most cases.

Wrapping it up

Everybody and the grandma knows MobX as a library managing your application state. It is. But it's small and flexible enough to be used in different ways. You can define multiple MobX scopes in your application, and you can use such a tiny scope to simulate computed properties. Less pathetically speaking, you can use MobX to cache the result of your method calls.


Comments