As I've been digging into Angular 2, I've been trying to build a custom HTML select menu, much like the one I built in AngularJS 1.x. This has proved to be quite a challenging task. Not only because the DOM (Document Object Model) is more heavily abstracted in Angular 2 but, also because the flow of data, in Angular 2, only goes in one direction. And, this one-way data flow must fundamentally change the way we traditionally think about select menus and the role of the option list within said menus.
| || || |
| || |
| || || |
To borrow from the ReactJS lexicon, if a select menu is an "uncontrolled component," the interplay between the select menu and its embedded option list matches how we normally think about select menus. But, in the world of one-way data flow, where an HMTML select menu is a "controlled component," the option list takes on much more of an "advisory" role in how the select menu must manage its value.
See, the complexity of the situation is that, in a one-way data flow scenario, a component cannot change its own value (when that value is exposed as an input property). It can only emit value changes events to which the calling context may or may not react. This has significant implications on how a custom select menu can react to changes within its own option list.
For example, consider the following select menu events:
- The currently-selected option's value changes.
- The currently-selected option is destroyed.
- The option list is cleared entirely.
- The option list is replaced with new options.
In a traditional, "uncontrolled" select menu scenario, all of these events would change the value bound to the select menu. However, in a one-way data flow architecture, none of these events can inherently change the value bound to the select menu as this would be considered a "side effect" of the event (which is exactly what one-way data flow is trying to prevent).
As such, it would follow that any changes to the option list, within a custom select menu, can do nothing but affect how the select menu is rendered (leaving the value unchanged). So, for example, if the currently-selected option is destroyed, but the [value] input binding to the component has not changed, the select menu can do nothing more than update the rendering to indicate that the component value is no longer reflected in the option list. How that state is portrayed to the user is left up to the developer.
One-way data flow may make your data easier to reason about; but, the constraints of a one-way data flow architecture don't necessarily make your components easier to build. And, if you're building on top of native input controls, enforcing the intended constraints of one-way data flow can be quite a hurdle. It's been a very interesting learning experience trying to think about this in the context of a custom select menu in Angular 2.
I see your pain... Im curious to see what solution you ended up with and why?
I'm still working on it :D Hopefully, I'll have something to post in the next few days.