0

Long stroy short, i'm currently working on a directive that applies a function to a control value when modified. That function modifies the control value only in on the model side. That goes like this :

// import ...

// @Directive
export class ControlValuePipeDirective implements OnInit{

  @Input() ngxControlValuePipe?: (value? :any) => any;

  constructor(
    private ngControl: NgControl
  ) {}

  ngOnInit(): void {
    if (this.ngxControlValuePipe === undefined) {
      console.info("No method was provided to the ngxControlValuePipe directive. Ignoring it.")
    }else{
      this.ngControl.valueAccessor?.registerOnChange((value: any) => {
          this.ngControl.control?.patchValue(this.ngxControlValuePipe ?
            this.ngxControlValuePipe(value) : value,
            {emitModelToViewChange: false})
        }
      )
    }
  }
}

The problem I have is when I add validators to a control like so :

// import ...

// @Component
export class AppComponent {
  public profileForm: FormGroup;

  constructor() {
    const streetControl = new FormControl('', [Validators.maxLength(10)]);
    // this.profileForm = ...
  }

  public editValueOnTheFly(value: any): any{
    return value + ' this more than ten chars length string';
  };
}
<!-- more html -->
<input id="street" type="text" formControlName="street" [ngxControlValuePipe]="editValueOnTheFly">
<!-- more html -->

If my streetControl control value gets modified in the view, then the models get's edited using the editValueOnTheFly method, which adds a long string to the model value. This triggers the validation and invalidates the control as the new model value is longer than 10 characters.

Is there any way I can run the validators on the value that is shown in the view (which is not modified)?

1 Answer 1

0

Because you want to avoid validation of the value modified by ControlValuePipeDirective, I propose you to separate your data model and form model.

ControlValuePipeDirective should not update form's model:

export class ControlValuePipeDirective implements OnInit{
    ...
    ngOnInit(): void {
        if (!this.ngxControlValuePipe) { return; }

        this.ngControl.valueAccessor?.registerOnChange((value: any) => {
            this.ngxControlValuePipe(value); 
        }
    }
}

AppComponent's editValueOnTheFly will be responsible for profile model update:

interface ProfileModel {
    street: string;
    ...
}

export class AppComponent {
    public profileForm: FormGroup;
    private profileModel: ProfileModel;
    ...
    public editValueOnTheFly(value: any): any{
        const updatedValue = value + ' this more than ten chars length string';
        this.profileModel = { ...this.profileModel, street: updatedValue };
    }
}

Also profileModel field can be replaced by Subject, to be able to subscribe to the profile model's changes.

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

5 Comments

Yes in fact this would work in a certain manner, but doesn't achieve what I'm trying to accomplish. In a certain way, my objetive is to change the behavior of the validation / the way the value is stored in the model. All of this without adding any code to what a casual form group creation code would look like.
Earlier you said: "I want to run the validators on the value that is shown in the view, not on the value that got modified (in the model)". I provided solution which works in this way: 1) it validates initial form's model value(value in the view) 2) directive doesn't invokes validation because it doesn't change form's model.
But if you don't want to separate data model and form model then I see only such way: form controls with your directive should not contain validators at all. So no validation on patchValue invocation. But because you still need validation on form creation, you can simply invoke this validation manually at ngOnInit stage. If it's what you want to achieve I can provide it as another anwer.
I'd be very interested at your answer but it still won't achieve what I'm looking for. I'm probably trying to do something that is just not possible the way validators are set.
Then please update your question with details what you're looking for. You need provide the requirements in such a way that it would be possible to verify that they have been achieved.

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.