Angular 5 simulate keypress on input controls

隐身守侯 提交于 2021-02-08 10:22:56

问题


I'm trying to simulate tab key press when enter is pressed on input control.For that I use a directive:

 private el: ElementRef;
    @Input() onEnter: string;
    constructor(private _el: ElementRef, public renderer: Renderer) {
        this.el = this._el;
    }
    @HostListener('keydown', ['$event']) onKeyDown(e: any) {
        if ((e.which === 13 || e.keyCode === 13)) {
            e.preventDefault();


    const event = new KeyboardEvent("keypress", {
            "key": "Tab"
          });
          this.el.nativeElement.dispatchEvent(event);
............

code for enter key fires but no tab is sent


回答1:


Updated see better aproach in this stackblitz(sorry,I don't remember the post where I talk about it)

If you want to use ENTER to focus an element you can use a directive

@Directive({
  selector: '[next-tab]',
})
export class NextTabDirective {


  @Input('next-tab') nextControl: any;

  @HostListener("keydown.enter", ["$event"])
  onEnter(event: KeyboardEvent) {
    if (this.nextControl) {
      if (this.nextControl.focus) {
        this.nextControl.focus();
        this.nextControl.select();
        event.preventDefault();
        return false;
      }
    }
  }

  constructor(private control: NgControl) {
  }
}

You can use in a form like

  <form (submit)="Submit()">
      <input #input0 [next-tab]="input1"  />
      <input #input1 [next-tab]="input2"  />
      <!--the last not have [next-tab]-->
      <!-an ENTER make a submit -->
      <input #input2   />
       <button type="button" (click)="cancel()">Cancel</button>
       <button type="submit">OK</button>
   </form>

I would like not use this ugly work-around, but we can improve the directive sending as next-tab an array of controls

@Directive({
  selector: '[next-tab]',
})
export class NextTabDirective {

  @Input('next-tab') nextControl: any[]; //<--an array of controls

  @HostListener("keydown.enter", ["$event"])
  onEnter(event: KeyboardEvent) {

    //find the nextControl not disabled. We check if c is defined
    //This allow us to use *ngIf and not put the control
    let nextControl=this.nextControl.find(c=>c && !c.disabled);
    if (nextControl) {
      if (nextControl.focus) {
        nextControl.focus();
        nextControl.select();
        event.preventDefault();
        return false;
      }
    }
  }

  constructor(private control: NgControl) {
  }
}

The form is look like

   <form (submit)="Submit()">
      <!--see that we create an array-->
      <input #input0 [next-tab]="[input1,input2,input3]"  />
      <input #input1 [next-tab]="[input2,input3]"  />
      <!--if only one element, we make an array of one element-->
      <input #input2 [style.display]="existInput2?'inherit':'none'" [next-tab]="[input3]"   />
      <!--if we want make invisible control NOT use *nfIf, therefore, we must hidden and disabled too -->

      <input #input3 />
       <button type="button" (click)="cancel()">Cancel</button>
       <button type="submit">OK</button>
   </form>

Finally I put a stackblitz in https://stackblitz.com/edit/angular-v8fkkf




回答2:


There are a more "confortable way to do a "next-tab" th idea is that the next-tab directive has two variables "self" and "next-control". We not use @Input, the directive is like

@Directive({
  selector: '[next-tab]',
})
export class NextTabDirective {

  self:any;     
  nextControl:any;  //See that is not a @Input

  @HostListener("keydown.enter", ["$event"])
  onEnter(event: KeyboardEvent) {
    if (this.nextControl) {
      if (this.nextControl.focus) {
        this.nextControl.focus();
        this.nextControl.select();
        event.preventDefault();
        return false;
      }
    }
  }

  constructor(private control: ElementRef) {
    //we store in "self" the native element. This make us easy refered to 
    //html properties of control
    this.self=control.nativeElement;
  }
}

In the .html see that the directive is simply next-tab, not [next-tab] and not [next-tab]="". Take account that input4 is too "decorated" with the directive, and that all the input have a "name" html property

<form [formGroup]="myForm" (submit)="submit(myForm)">
  <p>
    <input type="checkbox" formControlName="ckDisabled"/>Disabled input 2
  </p>
  <p>
    <input type="checkbox" formControlName="ckInvisible"/>Invisible input 3
  </p>
  <p>
    Input 1: <input name="input1" formControlName="input1"
              next-tab/>
  </p>
  <p>
    Input 2: <input name="input2" formControlName="input2" tabindex=""
              [enableControl]="!myForm.controls['ckDisabled'].value" 
              next-tab/>
  </p>
  <p [style.display]="myForm.controls['ckInvisible'].value?'none':'inherit'">
    Input 3: <input name="input3" formControlName="input3"
              [enableControl]="!myForm.controls['ckInvisible'].value"
              next-tab
/>
  </p>
  <p>
    Input 4: <input name="input4"  next-tab formControlName="input4"/>
  </p>
  <p>
  <button>OK</button>
</p>
  </form>

And now the .ts. We use ViewChildren to get all the element that have a next-tab directive.

export class AppComponent implements OnInit,AfterViewInit  {
  //We use a ViewChildren to get all the controls width NextTabDirective
  //We use QueryList<NextTabDirective>. So the elements of "inputs"
  //will have the properties: self and nextControl

  @ViewChildren(NextTabDirective) inputs: QueryList<NextTabDirective>;

  myForm:FormGroup;

  constructor(private fb:FormBuilder){}
  //in ngAfterViewInit we asing to nextControl, the self of the next control
  ngAfterViewInit() {
      const controls=this.inputs.toArray();
      //controls will be [input1,input2,input3,input4]
      for (let i=0;i<controls.length-1;i++)
          controls[i].nextControl=controls[i+1].self;        }
}


  ngOnInit()
  {
   this.myForm=this.fb.group({
    ckDisabled:false,
    ckInvisible:false,
    input1:'',
    input2:'',
    input3:'',
    input4:''

  });
  this.onChanges();
  }
  onChanges()
  {
    this.myForm.valueChanges.subscribe((value)=>{
         if (this.inputs)
         {
           //see how we get the control using self.name
           const input1=this.inputs.find(c=>c.self.name=="input1");
           const input2=this.inputs.find(c=>c.self.name=="input2");
           const input3=this.inputs.find(c=>c.self.name=="input3");
           const input4=this.inputs.find(c=>c.self.name=="input4");

           input1.nextControl=(value.ckDisabled && value.ckInvisible)?input4.self:
                            (value.ckDisabled)?input3.self:input2.self;
           input2.nextControl=(value.ckInvisible)?input4.self:input3.self;
         }

    })

  }
  submit(form:any)
  {
    if (form.valid)
      alert("Fom submitted!!")
  }
}

there are a stackBlitz in https://stackblitz.com/edit/angular-dzdxmh



来源:https://stackoverflow.com/questions/50932956/angular-5-simulate-keypress-on-input-controls

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!