Angular Lesson 2

[Update (4/25/2019): It hasn’t been long since I wrote this, but I have improved my technique sense then. I will edit to include a Github repo with live code you can follow along with.]

It’s late, I’m bored, got a second wind, so Lesson 2 coming at ya. If you haven’t gotten the feel for my tutorial style yet, here is what to expect. I’m going to minimally describe how to actually build something, but mainly it’s an excuse to explore the Angular ecosystem, figure out how people do things, learn the idioms, complain that Angular is not Vue, etc. I’ve been know to stumble on some cool library first and think up some excuse to use it after the fact.

I’m putting code samples related to this Angular series of posts in a Github repository at https://github.com/xerocross/angular-examples. (That’s my Github.) Different examples are organized into different branches. You can find code related to today’s lesson on a branch called dumb-sequence-explorer. In the branches, we are always starting from the result of ng new at the command line, so it comes with a lot of stuff there that I won’t necessarily be using. I suggest you clone my repo into a local folder, open it in your favorite code editor, and also run ng serve --open to start the live server.

This time I wanted to make a widget that takes text input in the form of a series of numbers and shows the result of processing it in several different ways. Specifically, it should do what you see in the image below. You type in a sequence of numbers and it spits out the sequence of ratios and the sequence of differences. It’s live-updating, but I’m not going into things like form validation. If you enter invalid data, you get what you get. Form validation is the topic of a much more boring post for someone else to write.

You can use the built in ng generate functions on the command line to generate some scaffolding. I’m going to run ng generate component sequence-explorer. That generates 4 files and it even nicely adds the component to your app.module.ts file. The logic happens in the file sequence-explorer.component.ts. I am going to remove the constructor method and the ngOnInit method because I don’t plan to use those. Rather, I’ll comment them out so it’s easy to see what I’ve done.

This is an image, not a widget. It doesn’t do anything.

I was pretty sure right away that I wanted an element in the controller to directly map to the input string. That is, I put a line at the top of my SequenceExplorerComponent class reading mySequenceString : string = "";. An alternative would be to parse the input in memory and only save the parsed value. Somehow to me that idea violates my sense of what is right, and I cannot put my finger on why.

So, of course, how do you bind input to a variable in the controller? The first way to do this I found was to use this bit of notation [(ngModel)]="mySequenceString". Put that inside the html input element. This does two-way data binding exactly the way you want. Text in the form becomes the value of mySequenceString (and vice-versa, if we care). For this to work for some reason you have to go over to app.module.ts and import { FormsModule } from '@angular/forms' and then include FormsModule in the imports array. For now I’m willing to just accept that as a cumbersome black box.

Oh, and to make this component actually appear in the screen, we need to put < app-sequence-explorer></ app-sequence-explorer> in the template of the root component, which is AppComponent. With that done, we have a an input form and in principle it is bound to the class variable, but there is no way to see that yet. Even so, I’m going to (git) commit my work.

Now as I flip back and forth among so many files, I’m really starting to miss Vue and its beautiful vue-loader package. In case you are unfamiliar: a very idiomatic way to write Vue components is to put the template, script, and styles all in one file, a .vue file. They are cleanly separated: template at the top, scripts in the middle, styles at the bottom. And this is fully optional. If anything is long enough so it needs to be factored out into its own file, then you can easily do that. But you don’t have to.

Those .vue files even look better. It’s not just that everything is JavaScript and the template is crammed into a long string literal or wrapped in back ticks. The template is wrapped in <template></template>. The script is wrapped in <script></script>, etc. Then at build time Webpack and vue-loader just make it work. ❤ Vue.

But this is Angular. Having the template in a separate file seems slightly better to me than cramming it into a “template” string inside a decorator.

Anyway, now the question is this: how do I do anything with that data from the user? Whenever it changes, I need to parse it and then process it in at least two different ways—I want the ratios between the consecutive numbers, and I want the differences between consecutive numbers. So, in Angular, how do you watch a variable and do something when it changes? Back in AngularJS days, we had $watch. It wasn’t pretty, but it’s what we had.

I found this deeply unhelpful question and answer page on StackOverflow:
https://stackoverflow.com/questions/34569094/what-is-the-angular-equivalent-to-an-angularjs-watch. Basically someone asks “where did $watch go” and they say something like, “you don’t have to anymore”. What? I’m trying to respond to changes in the data. Basically, I want computed values. Or…I want whatever is idiomatic Angular for computed values.

Let me clarify a few points in case we are not on the same page. It’s relatively simple to have changes to that form input element fire a function. Here’s how it goes. I add notation like this to the input element: (ngModelChange) = "processSequenceString($event)". With that in place, whenever there is any change to that value, it fires the function processSequenceString, which I define in my controller class. For some reason I don’t understand, it is idiomatic to use “$event” to refer to the argument of this function even though it just resolves to the value. So in this case $event is just the input string and if I want I can define a function processSequenceString(val) that splits the string at commas, throws away any whitespace, and tries to parse each element as a number. Assuming valid input, the result is an array of numbers that we can store somewhere.

Example. I could write it like this: processSequenceString (val) { let arr = val.split(/ *, */g) .map((v: string) => parseFloat(v)) .filter((v:number) => !isNaN(v)); this._mySequence = arr; }. This will do in a pinch, but it will break at the slightest invalid input. Also I can throw in a console log so I see the results. And this will verify that the connection between template input and controller class is actually happening.

I don’t love this solution, but at least it keeps a live-updating array of the numbers our user entered. The question is this: how do we also do live-updating secondary processing to that list? How do we also compute the list of ratios between consecutive numbers? And the list of the differences between consecutive numbers? The specific processing we want to do doesn’t matter. The point is that I have 2 functions I also want to run any time that data changes, and later it might be more.

Here’s one crappy solution: in the processSequenceString function, I could explicitly call two other functions that do that processing and update variables to store it, and then the template can display the results of those variables. That would work, but I hate it. First reason I hate it: having to explicitly store something that is not state but is the result of doing some computation on state—that’s crappy. I don’t like the idea of little accessory variables like that. It violates the law of single source of truth.

Also: I should be able to write functions that listen for changes to my sequence and respond accordingly without having to explicitly add them to some onChange handler like that. That style of doing things is contrary to the whole WAY of modern frameworks—having to explicitly wire things together imperatively is not what we want. We want something more declarative. *I* want something more declarative.

Wait. What the hell does “declarative” mean? Sometimes I think even people who have been doing this for 30 years don’t know what that word means. And it’s not even, like, an obscure bit of jargon contrary to the plain English definition. I read this in the Angular docs earlier: “Observables are declarative—that is, you define a function for publishing values, but it is not executed until a consumer subscribes to it. ” That is not what declarative means. That sounds like some other desirable quality, but it’s not declarative. Declarative means you say what, not how. It’s the difference between “let there be light” and “here’s how you make sticky rice…”.

Most programming is not declarative. We are not at the Godlike “fiat lux” stage of computer programming just yet. Most of the time, we have to tell computers what we want them to do in excruciating detail.

Enter computed values. Computed values are something I learned from Vue and I love them so much I strongly believe they need to be written directly into the standard. Vanilla JavaScript should have computed values…somehow. The idea is very simple. My list of ratios depends directly on the sequence the user inputs. The sequence is state. The list of ratios can be computed from state. It needs to be recalculated every time that input changes. And I can give you a function for doing that computation, some kind of updateRatioSequence function. The crux of the matter is who executes that update function and when, and does that computation happen only when necessary.

In Vue, it is possible to define the value of a property in this way. We might have a property called simply ratioSequence and to that property is assigned a function you can run that computes its value. But it’s not just a getter function. The engine only actually executes that computation when one of the values going into it has changed. I’m not sure exactly how Vue does that. It’s quite magical really because you don’t have to explicitly list which values to watch. Somehow the Vue engine scans the computation function and it knows when it needs to recompute based on which variable references it sees in the function definition. The rest of the time if you ask for that value, you get something from cache. It doesn’t just re-compute every time you ask for that value.

I’ve done my Googling, and as far as I can tell up to now, Angular simply does not have any such thing as computed values. I found this article on exactly that point:
https://www.beyondjava.net/computed-properties-in-angular. That article suggests using a third-party library called mobx-angular for computed values. I’m not sure why one would use mobx-angular. The parent library mobx works with Angular out of the box without any sort of wrapper, and it’s a robust and well-maintained project as of now. But I’ll come back to that in a moment. [Update: I was incorrect, as we will soon see.]

To illustrate my point, I have written a getter function for the ratios sequence. Any time “ratios” is references, the getter function will be executed, and it logs “ratios was computed” to the console. It is easy to show why this is crummy. I added another input to the template inviting you to type in some extraneous string, and for good measure the value is bound to an extraneous variable in the class. It’s irrelevant. It’s connected to nothing else. But if you type anything in that input, Angular will execute that ratios getter function again and get the same value again. Check the logs.

I think this raises an important question about Angular that I don’t have a good answer for. What is the idiomatic Angular way of doing the thing I’m trying to do? (That is: watching data and performing computations from it to populate more values.) Using a third party library for something so basic does not seem like the way of Angular. From what I’ve seen, the Angular team likes to personally write every iota of code you use, and they want to ship it all to you in a gigantic, complicated machine where it’s difficult to pull any of the individual parts away from each other. (Dear Angular folk: I exaggerate slightly in good fun.)

I suspect that somehow the Angular way of doing this has something to do with what they call “Observables”. There’s this library RxJS that describes itself as being “reactive” programming for JavaScript. It is literally just a set of wrappers you can put around streams of data (like promises, but with more than just one of them on the way), and various operations you can pipe that data through. What they call an “observable” is a data stream. And you can subscribe to it and do stuff with that data. So it’s data streams plus pub-sub.

Somebody way up the chain of command over at Angular smoked something good and thought RxJS was just the dopest thing ever, and so in Angular now everything is based on these “observables” for some reason. They even have this entire much more complicated way of binding data from forms (reactive forms:
https://angular.io/guide/reactive-forms ) that is explicitly based on observables. Also RxJS is a peer dependency of Angular.

I went down this path for, you know, a little while trying to figure out if there was actually something useful to get out of thinking of anything in my widget as an observable. Then I decided. No, there is not. So I figured let’s use MobX:
https://github.com/mobxjs/mobx . (By the way, I can only assume that is pronounced “MO-biks”.)

I don’t love the idea of using MobX to mimic computed values because it’s not small. I’m sure it does all kinds of other cool stuff in addition to the one tiny thing I want from it. I just want computed values. But I also value learning about other projects, especially cool ones that a lot of people seem to really like. So for my Tiny Widget number 2, I installed mobx (not mobx-angular, which is broken as of this post). [Correction: it’s not “broken” exactly, but I encountered many warnings and errors upon trying to test and build it myself.]

I import at the top like so: import { observable, computed } from 'mobx' in my controller. When I want to watch a variable like my number sequence, I declare it like this: @observable _mySequence : number [] = [];. Then to define a computed value, I declare it and define it like this @computed get differences (): number[] {/* computation function here */ }.

I’m leaving the vanilla ratios getter in place, but in my code now I’m going to put the @observable decorator on _mySequence and I’m adding a new differences method to which I add the @computed decorator.

But here’s the rub. It’s not working. I mean, no. Actually, the widget appears to function perfectly, and it does—it just does so with a lot of unnecessary computation. Those damn computation functions are being executed every time the data model changes, even when it’s not something I declared as an observable. Remember that extraneous input? I specifically stuck in another irrelevant input and bound it to the controller and did nothing with it, but when I change that value, all the computed values get computed again, mobx or no mobx. You can see it all in the console log.

MobX looked so promising. I really do hope I am in error here. I will investigate further and I’ll happily write a retraction if I discover that I’m wrong here. I suppose this little investigation into computed values in Angular has led nowhere. I do not have a satisfactory answer yet. If I Google around again tomorrow, maybe I’ll find some super-tiny module that does exactly what I want. Just Angular computed values. But I also do want to learn what MobX is all about. It’s worth noting that MobX appears to be this huge thing. Gzipped it’s like 37 kb, and there’s at least one book about using it. It looks like a serious, professional project with many fans.

Also, I just know that before this journey into Angular is over I’ll have to actually learn RxJS and figure out why people started talking about data stream processing using the phrase “reactive programming”. I was talking about this on Twitter because I thought maybe RxJS was actually doing something deep that I did not understand, and a guy sent me this article: https://gist.github.com/staltz/868e7e9bc2a7b8c1f754. It’s a useful read, but after reading it I still see nothing deep or interesting going on. I definitely don’t want to start calling a finite array of numbers in memory a data stream or an “Observable”.

I do understand you can think of the input to my widget not just as its current static value but as a stream where each new element is the updated value after some change made by the user. I just don’t see why that kind of complexity needs to be exposed to me as a user of Angular. That should be hidden so I don’t have to deal with it. My view on this may later change, but for now that’s my view.

I’ve left much unanswered, and I still have more things to complain about, so there will definitely be a Lesson 3.

[Update: Lesson 2 has a direct continuation as Lesson 2 (part 2), located here:
https://adamcross.blog/2019/04/22/angular-lesson-2-part-2/ .]

2 thoughts on “Angular Lesson 2

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s