<input> 요소에 초점 설정


108

Angular 5로 프런트 엔드 응용 프로그램을 작업 중이며 검색 상자를 숨겨야하지만 버튼을 클릭하면 검색 상자가 표시되고 초점이 맞춰져야합니다.

지시어 등으로 StackOverflow에서 찾은 몇 가지 방법을 시도했지만 성공할 수 없습니다.

다음은 샘플 코드입니다.

@Component({
   selector: 'my-app',
   template: `
    <div>
    <h2>Hello</h2>
    </div>
    <button (click) ="showSearch()">Show Search</button>
    <p></p>
    <form>
      <div >
        <input *ngIf="show" #search type="text"  />            
      </div>
    </form>
    `,
  })
  export class App implements AfterViewInit {
  @ViewChild('search') searchElement: ElementRef;

  show: false;
  name:string;
  constructor() {    
  }

  showSearch(){
    this.show = !this.show;    
    this.searchElement.nativeElement.focus();
    alert("focus");
  }

  ngAfterViewInit() {
    this.firstNameElement.nativeElement.focus();
  }

검색 창이 초점으로 설정되지 않았습니다.

어떻게 할 수 있습니까?

답변:


128

쇼 검색 방법을 다음과 같이 수정하십시오.

showSearch(){
  this.show = !this.show;  
  setTimeout(()=>{ // this will make the execution after the above boolean has changed
    this.searchElement.nativeElement.focus();
  },0);  
}

15
왜 setTimeout을 사용해야합니까? 부울의 변경이 동 기적이지 않습니까?
Andrei Rosu

6
zonejs가 엉망이지 않습니까?
lawphotog

1
변경 사항이 렌더링되지 않았기 때문에 @AndreiRosu는, 그것없이 나는 오류가 발생했습니다
이슬람 Q.

13
이것은 작동하지만 명확한 설명이 없으면 마술입니다. 마법은 자주 끊어집니다.
존 화이트

1
패널이 열렸을 때 패널 내부에 요소를 집중하려고했기 때문에 0 시간 제한이 작동하지 않았습니다.setTimeout(() => { this.searchElement.nativeElement.focus() }, 100)
tclark333

41

이를 위해 html 자동 초점 을 사용해야 합니다.

<input *ngIf="show" #search type="text" autofocus /> 

참고 : 구성 요소가 유지되고 재사용되는 경우 조각이 처음 연결될 때만 자동 초점이 적용됩니다. 이 문제는 dom 프래그먼트가 연결될 때 자동 초점 속성을 확인하는 전역 dom 리스너를 보유한 다음 다시 적용하거나 자바 스크립트를 통해 초점을 맞추면 극복 할 수 있습니다.


47
이것은 여러 번이 아니라 페이지를 새로 고칠 때마다 한 번만 작동합니다.
moritzg

23

이 지시문은 표시되는 즉시 요소의 텍스트에 초점을 맞추고 선택합니다. 경우에 따라 setTimeout이 필요할 수 있지만 많이 테스트되지 않았습니다.

import { Directive, ElementRef, OnInit } from '@angular/core';

@Directive({
  selector: '[appPrefixFocusAndSelect]',
})
export class FocusOnShowDirective implements OnInit {

  constructor(private el: ElementRef) {
    if (!el.nativeElement['focus']) {
      throw new Error('Element does not accept focus.');
    }
  }

  ngOnInit(): void {
    const input: HTMLInputElement = this.el.nativeElement as HTMLInputElement;
    input.focus();
    input.select();
  }
}

그리고 HTML에서 :

 <mat-form-field>
     <input matInput type="text" appPrefixFocusAndSelect [value]="'etc'">
 </mat-form-field>

감사합니다,이 요청 HTTP를 기다리고의 경우에 나를 위해 일한 유일한 solusion입니다
Abdelhalim FELLAGUE CHEBRA

1
이 솔루션이 허용되는 답변보다 더 선호됩니다. 코드 재사용의 경우 더 깨끗하고 Angular 중심입니다.
derekbaker783

또한 모듈 선언에 지시문을 추가하는 것을 잊지 마십시오.
Elijah Dollin

11

여기에 무게를 두겠습니다 (Angular 7 Solution)

input [appFocus]="focus"....
import {AfterViewInit, Directive, ElementRef, Input,} from '@angular/core';

@Directive({
  selector: 'input[appFocus]',
})
export class FocusDirective implements AfterViewInit {

  @Input('appFocus')
  private focused: boolean = false;

  constructor(public element: ElementRef<HTMLElement>) {
  }

  ngAfterViewInit(): void {
    // ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.
    if (this.focused) {
      setTimeout(() => this.element.nativeElement.focus(), 0);
    }
  }
}


9

이것은 setTimeout없이 Angular 8에서 작동합니다.

import {AfterContentChecked, Directive, ElementRef} from '@angular/core';

@Directive({
  selector: 'input[inputAutoFocus]'
})
export class InputFocusDirective implements AfterContentChecked {
  constructor(private element: ElementRef<HTMLInputElement>) {}

  ngAfterContentChecked(): void {
    this.element.nativeElement.focus();
  }
}

설명 : 좋습니다. 다음과 같은 이유로 작동합니다. 변경 감지. setTimout이 작동하는 것과 같은 이유이지만 Angular에서 setTimeout을 실행하면 Zone.js를 우회하고 모든 검사를 다시 실행하며 setTimeout이 완료되면 모든 변경이 완료되기 때문에 작동합니다. 올바른 수명주기 후크 (AfterContentChecked)를 사용하면 동일한 결과에 도달 할 수 있지만 추가주기가 실행되지 않는다는 이점이 있습니다. 모든 변경 사항이 확인되고 전달되면 함수가 실행되고 AfterContentInit 및 DoCheck 후크 이후에 실행됩니다. 내가 틀렸다면 나를 바로 잡으십시오.

https://angular.io/guide/lifecycle-hooks 에서 하나 이상의 수명주기 및 변경 감지

업데이트 : Angular Material CDK, a11y-package를 사용하는 경우 더 나은 방법을 찾았습니다. 먼저 입력 필드가있는 구성 요소를 선언하는 모듈에서 A11yModule 을 가져옵니다 . 그런 다음 cdkTrapFocuscdkTrapFocusAutoCapture 지시문을 사용하고 html에서 다음과 같이 사용하고 입력에 tabIndex를 설정합니다.

<div class="dropdown" cdkTrapFocus cdkTrapFocusAutoCapture>
    <input type="text tabIndex="0">
</div>

위치 지정 및 응답 성과 관련하여 드롭 다운에 몇 가지 문제가 있었고 대신 cdk에서 OverlayModule을 사용하기 시작했으며 A11yModule을 사용하는이 방법은 완벽하게 작동합니다.


안녕하세요 ... cdkTrapFocusAutoCapture속성을 시도하지 않지만 첫 번째 예제를 내 코드로 변경했습니다. 알 수없는 이유로 (나에게) AfterContentChecked 수명주기 후크에서는 작동하지 않았지만 OnInit에서만 작동했습니다. AfterContentChecked를 사용하면 특히 동일한 형식의 지시문 없이는 포커스를 변경하고 마우스 또는 키보드를 사용하여 다른 입력으로 이동할 수 없습니다.
timhecker

@timhecker 예, 구성 요소를 cdk 오버레이로 마이그레이션 할 때 유사한 문제에 직면했습니다 (포지셔닝을 위해 오버레이 대신 CSS 만 사용할 때 작동 함). 지시문을 사용하는 구성 요소가 표시되었을 때 입력에 무기한 집중했습니다. 내가 찾은 유일한 해결책은 업데이트에 언급 된 cdk 지시문을 사용하는 것입니다.
SNDVLL

7

Angular에서는 HTML 자체에서 버튼 클릭시 입력에 포커스를 설정할 수 있습니다.

<button (click)="myInput.focus()">Click Me</button>

<input #myInput></input>

이 답변은 HTML에서 다른 요소를 프로그래밍 방식으로 선택하는 간단한 방법을 보여줍니다. 제가 찾던 것입니다 (모든 "초기 초점"답변은 초점을 변경하여 이벤트에 반응하는 방법을 해결하지 못함). 불행히도 반응해야했습니다. mat-select selectionChanged다른 UI 작업보다 먼저 발생 하는 이벤트 에 대한 것이므로 해당 지점에서 포커스를 가져 오는 것은 작동하지 않았습니다. 대신 메서드를 작성 setFocus(el:HTMLElement):void { setTimeout(()=>el.focus(),0); }하고 이벤트 처리기에서 호출해야했습니다 <mat-select (selectionChanged)="setFocus(myInput)">.. 좋지는 않지만 간단하고 잘 작동합니다. 고마워!
Guss

나를 위해 일하지 않았다. 나는 ERROR TypeError : Cannot read property '
Reza Taba

@RezaTaba, 'myInput.focus ()'함수를 호출 했습니까? 아니면 방금 'myInput.focus'를 썼습니까? 또한 입력 요소가 렌더링 된 div 내부에 있는지 확인합니다 (예 : * ngIf false로 인해 오류가 발생할 수 있음)
shaheer shukur

6

부울이 변경된 후 실행을 수행하고 시간 초과 사용을 방지하려면 다음을 수행 할 수 있습니다.

import { ChangeDetectorRef } from '@angular/core';

constructor(private cd: ChangeDetectorRef) {}

showSearch(){
  this.show = !this.show;  
  this.cd.detectChanges();
  this.searchElement.nativeElement.focus();
}

5
나는 그것이 작동하지 않았다, 각 7이 시도, 사용 시간 제한 괜찮 았는데
rekiem87

작동하지 않는 각도 8도 나에 대한 나쁜에 우리의 setTimeout으로 돌아 가야
안드레이 키부



1

구성 요소의 html :

<input [cdkTrapFocusAutoCapture]="show" [cdkTrapFocus]="show">

구성 요소의 컨트롤러 :

showSearch() {
  this.show = !this.show;    
}

.. @ angular / cdk / a11y 에서 A11yModule 가져 오기를 잊지 마세요.

import { A11yModule } from '@angular/cdk/a11y'

최고의 솔루션. 감사. 다른 솔루션으로 오류가 발생했습니다.
Reza Taba

1

나는 같은 시나리오를 가지고 있는데, 이것은 나를 위해 일했지만 당신이 가지고있는 "숨기기 / 표시"기능이 없습니다. 따라서 필드를 항상 볼 수있을 때 초점이 맞는지 먼저 확인한 다음 가시성을 변경할 때 작동하지 않는 이유를 해결하려고 시도 할 수 있습니다 (아마 수면 또는 약속을 적용해야하는 이유 일 것입니다).

포커스를 설정하려면 다음과 같이 변경해야합니다.

HTML 매트 입력은 다음과 같아야합니다.

<input #yourControlName matInput>

TS 클래스에서 변수 섹션 (

export class blabla...
    @ViewChild("yourControlName") yourControl : ElementRef;

귀하의 버튼은 괜찮습니다.

  showSearch(){
       ///blabla... then finally:
       this.yourControl.nativeElement.focus();
}

그리고 그게 다야. 내가 찾은이 게시물 에서이 솔루션을 확인할 수 있으므로-> https://codeburst.io/focusing-on-form-elements-the-angular-way-e9a78725c04f 덕분에


-1

더 쉬운 방법은 이것을하는 것입니다.

let elementReference = document.querySelector('<your css, #id selector>');
    if (elementReference instanceof HTMLElement) {
        elementReference.focus();
    }

3
DOM을 직접 쿼리하고 싶지는 않습니다.
Richard.Davenport
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.