Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 - Directive not updating model

I have a directive on an html input box that holds numeric values. When a user pastes a number into the textbox I have a directive that "cleans" the number (strips commas, dollar signs, etc). The cleaning code seems to work fine however my model is not being updated with the cleaned value even though the text box is showing my cleaned value.

How do I get my model updated with the new value?

Plnkr here

Here is a stripped down example:

app.ts

@Component({
  selector : 'my-app',
  template : `
  <div>
    <br/>
    <br/>
    <p>Stack Overflow person - give focus to text box and then lose focus by clicking elsewhere in the screen. <br/>The model is not updated.</p>
    <br/>Model value: {{ balanceAmount }}
    <br/>
    <br/>
    <input type="text" [(ngModel)]="balanceAmount" myCurrencyFormatter  /><br/>
  </div>
  `,
})
export class App {
  name:string;
  constructor(private mycurpipe: MyCurrencyPipe) {
    this.balanceAmount = 1234567.89;
  }
}

Currency-Formatter-Directive.ts

@Directive({ selector: "[myCurrencyFormatter]" })
export class MyCurrencyFormatterDirective implements OnInit {

  private el: any;

  constructor(
    private elementRef: ElementRef,
    private currencyPipe: MyCurrencyPipe
  ) {
    this.el = this.elementRef.nativeElement;

  }

  ngOnInit() {
    this.el.value = this.currencyPipe.transform(this.el.value);
  }

  @HostListener("focus", ["$event.target.value"])
  onFocus(value) {
    this.el.value = this.currencyPipe.parse(value); // opossite of transform
  }

  @HostListener("blur", ["$event.target.value"])
  onBlur(value) {
    this.el.value = this.cleanNumber(value); //"987654" ;//this.currencyPipe.transform(value);
  }
  
  cleanNumber (value: number) {
    return 8888888; // clean logic goes here, removed for plunk example
  }
  

}

Plnkr here

like image 539
ClaytonK Avatar asked Mar 02 '17 21:03

ClaytonK


1 Answers

You need to add Emitter for your model. This is the way to implement 2 way binding in Angular 2. Take a look at line @Output() ngModelChange = new EventEmitter(); and how I used this variable to emit the change to caller.

import { Directive, HostListener, ElementRef, OnInit, EventEmitter, Output } from "@angular/core";
import { MyCurrencyPipe } from "./my-currency.pipe";

@Directive({ selector: "[myCurrencyFormatter]" })
export class MyCurrencyFormatterDirective implements OnInit {

  private el: any;
  @Output() ngModelChange = new EventEmitter();

  constructor(
    private elementRef: ElementRef,
    private currencyPipe: MyCurrencyPipe
  ) {
    this.el = this.elementRef.nativeElement;

  }

  ngOnInit() {
    this.el.value = this.currencyPipe.transform(this.el.value);
  }

  @HostListener("focus", ["$event.target.value"])
  onFocus(value) {
    this.el.value = this.currencyPipe.parse(value); // oposite of transform
    this.ngModelChange.emit(this.el.value);
  }

  @HostListener("blur", ["$event.target.value"])
  onBlur(value) {
    this.el.value = this.cleanNumber(value); //"987654" ;//this.currencyPipe.transform(value);
    this.ngModelChange.emit(this.el.value);
  }
  
  cleanNumber (value: number) {
    return 8888888;
  }

}
like image 55
Hung Cao Avatar answered Nov 28 '22 21:11

Hung Cao