3

I want to format data (provided by user )to my own format or change them on the fly (eg. set 0 when user put a value lower than 0 or something like that). I mostly use a reactive forms solution to connect view with code behind. What I've done it by intercepting my binding between the variable of FormControl type and the control on the view thanks to a directive. I would like to stay with this but the problem is that the directive isn't real interceptor as a value change event occurs with wrong value and then is formatted by directive function (the change event is called second time). This is how I achieved that:

@HostListener("blur", ["$event.target.value"])onBlur(event: any) {
    let value = this.transformValue(event);
    this.control.setValue(value, { emitEvent: false });
    this.el.value = value;
}

Is there a way to achieve the real interception behaviour through directives?

EDIT: I've created a simple sample of my case. Please, take a look. What I want to achieve is only one (second) change event call.

https://stackblitz.com/edit/angular-ctnjup

2
  • Could you check please what is called first? Your directive handler or your data change handler? Commented Feb 9, 2019 at 14:44
  • Hi, definately data change handler is being called first. Take a look at my stackblitz's sample (look at the edited part of the post). Commented Feb 9, 2019 at 16:33

2 Answers 2

4

So, directive won't help you here, but, you can use that fact that valueChanges is Observable and make a clean and nice solution based on that. Basically you can use map + tap operators to map your changes and set them back to input before subscription. Example:

this.sub$ = this.formControl.valueChanges.pipe(
  map(x => x === "" ? 0 : parseFloat(x) || 0),
  tap(x => this.formControl.setValue(x, {emitEvent: false}))
).subscribe(x => {
  console.log("change: " + x);
  this.changes.push(x);
});

Working stackblitz example. Hope that helps.

Sign up to request clarification or add additional context in comments.

Comments

0

Jaume, in the constructor of a directive you can inject the ElementName and the control itself if the directive is applied to a input control

constructor(private elementRef: ElementRef,private control:NgControl) {
   //this.control was the control itself
}

So, you can add HotListener ove input, over focus,over blur...

@HostListener("blur", ["$event.target.value"])onBlur(event: any) {
    let value = this.transformValue(event);
    this.control.setValue(value, { emitEvent: false });
    this.el.value = value;
}

1 Comment

Hello, take a look at the link in the edited part of the post. I'm doing exactly how you described.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.