Custom getters/setters for formInput.value in Angular?

Viewed 35

I'd like to be able to create a formal separation between the underlying value of a form input, how it's displayed and then how user input is transformed back into the underlying value.

Transforming the value as displayed in the formInput

Let's say I'm designing the logic for allowing users to format the value of a cell in a spreadsheet. Let's assume the cell UI is just a textInput.

I want to allow the user to format the value as a percentage: 10% or alternatively as a currency $0.10. In both cases the underlying value is 0.1 but the formatting changes how I display it in my textInput.

cell.value = 0.1 # number

# format as percentage
textInput.value = "10%" # string

# format as currency
textInput.value = "$0.10" # string

# format as number
textInput.value = 0.1 # number

It's obviously not too hard to do this. But it would still be nice if there was a way to do it natively. To distinguish between textInput.value and textInput.displayValue.

Transforming the value as parsed from the formInput

So continuing the same example from above, we can see that in the first two cases, the value that's in the formInput needs to be transformed before it can be saved to the cell.

# When we update values we see that:

# When formatted as a percentage
textInput.value = "150%"
# then
cell.value = 1.5

# When formatted as a currency
textInput.value = "$0.10"
then 
cell.value = 0.1

I can write code to do all of this but it has the hint of a common problem about it. Does Angular offer anything native to deal with these transformations? Can you have custom getters and setters for formInput.value?

1 Answers

I imagine you want to make a kind of valueAsNumber of the html input but more general. So you can create a directive

@Directive({
  selector: 'input',
  exportAs: 'valueAsNumber'
})
export class ValueAsNumberDirective {
  value: number = 0;
  formattedValue:any;
  @HostListener('input', ['$event.target.value']) _transform(value: string) {

    this.formattedValue=value

    //your logic here, I simple convert to number a value
    this.value = +value;
  }
}

See that as selector I use input -so each tag input is applied- and as exportAs I choose valueAsNumber.

So you can, e.g.

<input name="name" #id="valueAsNumber" [(ngModel)]="name" >

Or if you has a FormControl named control

<input name="name" #id2="valueAsNumber" 
     [value]="control.value?id2.formattedValue|| control.value:''" 
     (input)="control.setValue(id2.value,{emitEvent:false})" >

See a stackblitz

Related