Angular 4 Reactive Form - Value for display

john Smith picture john Smith · Dec 30, 2017 · Viewed 9.1k times · Source

I'm using reactive form approach. I have input field which have correspondent formControl Object and while typing I'm doing formatting on the value - make all the input uppercase.

That of course works good - the value is updated in the view and in formControl as well.

The issue is That I would like to send to server the original value and not the formmated value (uppercase)

So I need something like value, and value for display in the formControl object.

See plunker - formatting value formControl

template:

  <input type="text" 
         class="form-control" 
         (blur)="handleOnBlur($event)"
         (input)="onChange($event)"
         formControlName="name">

model:

    valueForModel: string; 
    valueForDisplay: string;
    public myForm: FormGroup;        

 onChange(event) {
    const value = event.target.value;
    this.valueForModel = value;
    this.valueForDisplay = value.toUpperCase();

    event.target.value = this.valueForDisplay;
 }

 handleOnBlur(event) {

   consol.log(this.valueForModel);
    // Herer I'm calling the sever and the server actually works good
    // server return back the updated value - but it then override my value 
       in the dom
    // the value for display value    
   }

 ngOnInit() {

     this.myForm = this._fb.group({
        name: ['', [<any>Validators.required, 
            <any>Validators.minLength(5)]],
      });
  }

Can't find anything to help. any suggestion will be appreciated.

Answer

Andriy picture Andriy · Dec 31, 2017

Here is my solution which uses additional data-model-value HTML element attribute to store model value.

HTML:

    <form [formGroup]="myForm">
      <input formControlName="myInput" #inputRef >
    </form>

TS:

    ....
    @ViewChild('inputRef') inputRef;
    ....

    ngOnInit() {
      this.myForm = this._fb.group({
        myInput: ['', [Validators.required]]
      });

      // listen to input changes
      this.myForm.get('myInput').valueChanges.subscribe(val => {
        const elRef = this.inputRef.nativeElement;
        // get stored original unmodified value (not including last change)
        const orVal = elRef.getAttribute('data-model-value') || '';
        // modify new value to be equal to the original input (including last change)
        val = val.replace(orVal.toUpperCase(), orVal);
        // store original unmodified value (including last change)
        elRef.setAttribute('data-model-value', val);
        // set view value using DOM value property
        elRef.value = val.toUpperCase();
        // update model without emitting event and without changing view model
        this.myForm.get('myInput').setValue(val, {
          emitEvent: false,
          emitModelToViewChange: false
        });
      });
    }

STACKBLITZ