1

I would like to "autofill" an input depending on other form values. "id" should be "name" + "." + "combo":

 <input matInput name="id" required placeholder="ID" #idValue readonly/>
 <input matInput ngModel name="name" required placeholder="NAME" autoFillId /> 
 <mat-form-field>
   <mat-select ngModel name="combo" required placeholder="COMBO" autoFillId >
       <mat-option value=1>Value 1</mat-option>  
       <mat-option value=2>Value 2</mat-option>  
   </mat-select>
</mat-form-field>

And this is my directive:

@Directive({
  selector: '[autoFillId]'
})

export class AutoFillDirective {

 @Output() idValue: EventEmitter<string> = new EventEmitter();
 value: string = ".";

@HostListener('input', ['$event']) onInputChange($event) {
  this.value = this.value.split(".")[0] + "." + $event.target.value;
  this.idValue.emit(this.value);
}

@HostListener('change', ['$event']) onChange($event) {
  this.value = $event.value + "." + this.value.split(".")[1];
  this.idValue.emit(this.value);
}

}

It works separatelly, I mean, if I got "undefinded.2" if changes the combo or "myName.undefined" if changes the input.

How can I do it together?

3
  • Where do you use idValue output? Commented Feb 1, 2018 at 9:31
  • I forgot it, editted Commented Feb 1, 2018 at 9:33
  • How is your template reference variable #idValue connected with @Output? Commented Feb 1, 2018 at 10:02

1 Answer 1

1

So, I took a little time to test and debug your code and this is what I found out:

1) You are calling 2 different instances of your directive

You're calling autoFillId in the combo and the input, so each of them will have a different instance of the directive. That means they both will have a different instance of this.value and since the value is never shared between the two instances, you'll always have only one side working.

2) select triggers both input and change events

@HostListener('change', ['$event']) onChange($event) {
  this.value = $event.value + "." + this.value.split(".")[1];
  this.idValue.emit(this.value);
}

This will be triggered on clicking on the select.

@HostListener('input', ['$event']) onInputChange($event) {
  this.value = this.value.split(".")[0] + "." + $event.target.value;
  this.idValue.emit(this.value);
}

This will be triggerd on selecting an option. That's what causing the undefined to appear.

There are multiple solutions to solve your problem, if you want to keep this behavior on a directive you'll have to pass the changed value to the other instance of the directive.

<select name="combo" required placeholder="COMBO" [autoFillId]="currentId" (idValue)="getId($event)">
       <option value=1>Value 1</option>  
       <option value=2>Value 2<option>  
<select>

your.component.ts

currentId = "."

getId(event) {
  this.currentId = event;
}

autofill.directive.ts

@Directive({
  selector: '[autoFillId]'
})

export class AutoFillDirective {

  @Output() idValue: EventEmitter<string> = new EventEmitter();
  //This input will load the value of the ID when changed
  @Input('autoFillId') value: string;

  @HostListener('input', ['$event']) onInputChange($event) {
    /* We need to check if the event is triggered by the input or the select
       We can do this by checking the constructor name for example.
    */
    if($event.constructor.name === 'InputEvent') {
      this.value = this.value.split(".")[0] + "." + $event.target.value;
    } else {
      this.value = $event.target.value + "." + this.value.split(".")[1];
    }
    this.idValue.emit(this.value);
  }

}

And here you go. You can check the working example here : StackBlitz

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

Comments

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.