Angular: Controlled inputs

Created on 12 Apr 2017  路  6Comments  路  Source: angulardart/angular

Angular does not offer "controlled" inputs. Value of controlled input is always set by provided value from binding (model). In any case, model is source of truth and not DOM (input).

I would to have such functionality in Angular. It should be possible to update template compiler, so when both [value] binding and (input) event listener are set, Angular should preserve selection state of input before setting value, and restore selection state of input after it.

We use Angular with immutable (built) state, and our code expects that state is the single source of truth in application. When there are no controlled inputs, app state and DOM state can go out of sync. Currently it is not possible to listen to input event and update value in model, because on each input update selection state will be reset, and user will not be able to place cursor at middle of text and start typing, for example.

needs info

Most helpful comment

NgModel is for two-way binding. It is bad because following situation is possible:

  1. native input value is updated
  2. ngModelChange is triggered
  3. incoming value from model is not updated (for some reason).

In most cases model value is not updated in (3) because of bugs. But problem is, those bugs are hard to spot because visually state of input is correct. In controlled scenario value of input element will be reset to model value after last rendering.

In React/Inferno it's almost trivial to create controlled inputs, because value of input is just set each time after render() is executed, resetting native input's value if it is different. To not reset focus state of input, Inferno sets value from to model to value of input only when those two are different.

I don't think I can implement this with current angular hooks. One possible way would be to listen for turnDown event on zone within directive and perform update of native input value if it is different. But that seems ugly.

@matanlurey What do you think about it?

All 6 comments

I'd need a concrete example of what you'd expect this to look like/do.

I want that my model was the source of truth, and not DOM. Hover, DOM elements like input have their own internal state so framework should do additional work to make situation when model state and DOM state are out of sync impossible (more info here).

<input ref-input [value]="value" (input)="value=input.value">
This is similar to React <input type="text" value={this.state.value} onChange={this.handleChange} /> version of controlled input. In this case value property is actually single source of truth, however angular will set value property on input on every change and it will reset input's selection state. User will not be able to put cursor in the middle of text and start typing. There is easy fix for this hover - before setting value on input, just check that it is actually different from what value input already has. This is approach used by Inferno (source code). So angular template compiler could add additional check in compiled template if target element is native input.

Shouldn't <input [(ngModel)]="value" do what you want?

It's not clear what we need here that ngModel does not provide.

Please re-open if you disagree, would be happy to discuss further.

NgModel is for two-way binding. It is bad because following situation is possible:

  1. native input value is updated
  2. ngModelChange is triggered
  3. incoming value from model is not updated (for some reason).

In most cases model value is not updated in (3) because of bugs. But problem is, those bugs are hard to spot because visually state of input is correct. In controlled scenario value of input element will be reset to model value after last rendering.

In React/Inferno it's almost trivial to create controlled inputs, because value of input is just set each time after render() is executed, resetting native input's value if it is different. To not reset focus state of input, Inferno sets value from to model to value of input only when those two are different.

I don't think I can implement this with current angular hooks. One possible way would be to listen for turnDown event on zone within directive and perform update of native input value if it is different. But that seems ugly.

@matanlurey What do you think about it?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

double11one picture double11one  路  6Comments

matanlurey picture matanlurey  路  3Comments

supermuka picture supermuka  路  5Comments

AndreyChernykh picture AndreyChernykh  路  4Comments

filiph picture filiph  路  4Comments