I've been developing in Angular since before it even released officially (from version 2.0.0-rc.5 I think) and it sped up development quite a bit. Although it gives developer quite a powerful and fast tool for developing web applications, there are a few shortcomings to it, one of which lies within the FormGroup.
Note that I'll be talking about use cases in really big and complex projects and therefore problems I discuss may seem a little exaggerated if You're not familiar with what convoluted business requirements may look like.
Angular Forms have single method for setting value:
setValue() which takes value and options. After setting the value,
valueChanges event is dispatched to notify about the change.
Normally it's enough, but sometimes we want to know whether the change came from the user (and maybe trigger some rest call) or was applied programmatically (and do NOT trigger the rest call).
FormArray objects store their status in single field named, well, status, the only problem being, it doesn't account for some business cases such as:
- Changing control value programmaticaly when it's disabled
- Checking validity of disabled control
Let's imagine that we have two fields dependent on each other. When field #1 changes value, #2 should be disabled or enabled based on some logic. When disabled, #2 should have it's value either cleared or set to some predefined value. In this case we can first setValue and then disable. But what about the case when #1 changes value again and #2 should have whole another value ? we need to call
This is tedious and surely, there should be easier to do this.
In order to clear the control value we have to call
reset() method and pass some value into it. I'd argue that this is not good design. In the Angular repo You can read that this method:
Resets the form control, marking it `pristine` and `untouched`, and setting the value to null.
Well, this all well and nice BUT we have the ability to set control value when we create it and that changes a lot. When we pass value at creation, shouldn't
reset() restore that value ? Of course it should, that's what reset means. Current behaviour of this method does not match the name, there should be another method called
clear() which will work as
reset() works right now, and
reset() should restore the initial value.
Angular forms, although tight to input, have no connection to the view itself which normally is a very good thing. But as usual, there is one case where I think it should be and that's the visibility of the input.
Let's imagine that we have input #1 which decides whether to show input #2 or #3. Right now we can only listen for changes in #1 and then set some variable (ideally only 1) which tells us which other input to show: #2 or #3. Not only that but we also need to clear control value when hiding it and resetting it to some default value when it's shown.
It would be much easier if the
Forms contained state called
visibility and methods
hide(). Those methods could also handle resetting and clearing value of the controller when shown or hidden respectively.
And so, we've listed shortcomings - what now ? Do we expect Angular devs to fix these for us ? Do we say to 'no' to business requirements ?
The answer to both questions is no. We cannot expect anyone to fix this, because, in their case it may not be broken. They are writing framework for everyone to use, we cannot expect everyone to have the same problems. As to second question - let's be real. Unless it really is undoable in any way, we cannot say no to business requirement. We can point stupid ones, but we cannot say no just because we want to.
There are only two solutions left:
- to extend or rewrite the Angular Forms, which is easier than you may think,
- or use what we have and write bunch of if statements.
Obviously, I'm going with the first solution and in the near future I'll follow through with article about how I extended Angular Forms and some tips on what I would do differently next time.
Hope You enjoyed my thoughts on Angular Forms 😊 If you have another use cases or know the reasons behind Angular devs decisions to write things that way, let me know in comments below 😊
We continue this topic in part 2