Angular is pretty specialized
Published by marco on
I recently had a conversation about the pros and cons of using Angular and I found this year-old article that I’d prepared from my notes but never published. The article
Two-way binding between Signals and Query Params by Julio Castro (Software Engineering Corner by Zühlke Engineers) includes the following code snippet.
@Component({ selector: "app-root", standalone: true, imports: [AsyncPipe], template: ` <h1>Signals Demo</h1> <p>Your first name is: {{ firstName$ | async }}</p> `, }) export class AppComponent { private activatedRoute = inject(ActivatedRoute); firstName$ = this.activatedRoute.queryParams.pipe( map((allQueryParams) => allQueryParams["firstName"]) ); }
I cannot describe how gross I think Angular code is. None of this is “using the platform”. This is all JavaScript-first. It’s all custom, untyped, string-matching, gobbledygook. The firstName$
in the template isn’t checked. There are no type-safe views.[1] What the hell does | async
do? I’m sure it’s convenient, but this is more obtuse-looking than modern React.
The injection is also just magic that you have to know about. And why is it injected differently than the AsyncPipe
? There are probably good reasons for it, in Angular, but it looks pretty slapdash and ad=hoc as an API. It’s like there’s a different symbol or character or concept for every possible thing. The imports
is in a custom place. It’s all packed into a @Component
decorator that does a bunch of magic for you to build what is probably a web component (but I’m not sure). They wrapped every single possible API in something custom to Angular.
I hope I’m wrong, but this is so unappealing.
Reading a bit further and we see an example where some of the noise—e.g., the async
pipe—has been removed because of the magic of signals.
If you’re learning Angular, you’re not learning anything portable about web-programming. You won’t know HTML, you won’t know CSS, you won’t even necessarily know JavaScript or the browser APIs. You don’t use the platform. It’s a shame because the platform is already so powerful. In the old days, you needed a framework to shield you from the differences. Nowadays, the platform is more than well-specified, -supported, and -implemented to just write to directly. Learning the platform API is just as easy as learning whatever I’m seeing in Angular.
In fairness to the article, though, it’s well-written and offers some good techniques for making the best of a bad situation if you have to work in Angular. 🙃
But then there’s this.
“Since we are accessing the value of the
allQueryParams
signal in the effect, it will run every time this signal gets updated, which happens every time Angular emits a new value in theactivatedRoute.queryParams
observable.“Inside the effect, we are just updating the value of our
queryParamValue
signal. For that, notice that we need to pass theallowSignalWrites: true
option. This is necessary because updating signals in effects could lead to infinite loops and unexpected and intricate situations in general.”
This is the same kind of black magic for real-life situations as you see in React these days. I’m still a fan of using MobX for the state model, then attaching it to pure reactive web components. I’m still deciding whether that will scale to what I need, but I’m more and more convinced that none of the huge frameworks are the way to go. They’re just so much wrapping and bizarre APIs that feel legacy before they’re even officially released.
I’m not going to copy it in here but the final version of the read/write signal service based on query-parameter values is 41 lines of hairball code. Do I know how much code it would be to achieve something similar outside of Angular? No. No, I don’t. I just know that if I ended up having to learn how to do it and write it—and even if it ended up being more code—I would have learned the general platform and built a service that can work in any web site, not just one framework.