programing

Angular2+ 자동 포커스 입력 요소

lastmoon 2023. 8. 15. 11:24
반응형

Angular2+ 자동 포커스 입력 요소

입력 요소를 자동 포커스하려면 어떻게 해야 합니까?이 질문과 비슷하지만 AngularDart에서는 그렇지 않습니다.이와 같은 것:

<input type="text" [(ngModel)]="title" [focus] />
//or 
<input type="text" [(ngModel)]="title" autofocus />

Angular2는 이 기능을 지원하는 빌드가 있습니까?

가장 가까운 질문은 이것입니다. 하지만 "입력 상자 목록"이 없기 때문에 더 짧고 쉬운 해결책은 없을까요?제공된 링크*ngFor="#input of inputs"사용되고 있지만 제어 템플릿에 입력된 것은 하나뿐입니다.

현재 코드는 다음과 같습니다.

import { Directive, ElementRef, Input } from "@angular/core";

@Directive({
    selector: "[autofocus]"
})
export class AutofocusDirective
{
    private focus = true;

    constructor(private el: ElementRef)
    {
    }

    ngOnInit()
    {
        if (this.focus)
        {
            //Otherwise Angular throws error: Expression has changed after it was checked.
            window.setTimeout(() =>
            {
                this.el.nativeElement.focus(); //For SSR (server side rendering) this is not safe. Use: https://github.com/angular/angular/issues/15008#issuecomment-285141070)
            });
        }
    }

    @Input() set autofocus(condition: boolean)
    {
        this.focus = condition !== false;
    }
}

사용 사례:

[autofocus] //will focus
[autofocus]="true" //will focus
[autofocus]="false" //will not focus

오래된 코드(예전의 답변, 만일의 경우):
저는 결국 이 코드로 끝났습니다.

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

@Directive({
    selector: '[autofocus]'
})
export class Autofocus
{
    constructor(private el: ElementRef, private renderer: Renderer)
    {        
    }

    ngOnInit()
    {        
    }

    ngAfterViewInit()
    {
        this.renderer.invokeElementMethod(this.el.nativeElement, 'focus', []);
    }
}

에 코드를 ,ngOnViewInit작동하지 않습니다.요소에 초점을 직접 맞추는 것은 권장되지 않으므로 코드에서도 모범 사례를 사용합니다.

편집됨(조건부 자동 포커스):
며칠 전에는 첫 번째 자동 포커스 요소를 숨기고 다른 요소에 포커스를 맞추고 싶지만 처음이 보이지 않을 때만 해당하므로 조건부 자동 포커스가 필요했고 다음 코드는 다음과 같습니다.

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

@Directive({
    selector: '[autofocus]'
})
export class AutofocusDirective
{
    private _autofocus;
    constructor(private el: ElementRef, private renderer: Renderer)
    {
    }

    ngOnInit()
    {
    }

    ngAfterViewInit()
    {
        if (this._autofocus || typeof this._autofocus === "undefined")
            this.renderer.invokeElementMethod(this.el.nativeElement, 'focus', []);
    }

    @Input() set autofocus(condition: boolean)
    {
        this._autofocus = condition != false;
    }
}

편집됨2:
Renderer.invokeElementMethod는 더 이상 사용되지 않으며 새 Renderer2는 이를 지원하지 않습니다.따라서 기본 포커스로 돌아갑니다(예: DOM - SSR 외부에서는 작동하지 않음!).

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

@Directive({
    selector: '[autofocus]'
})
export class AutofocusDirective
{
    private _autofocus;
    constructor(private el: ElementRef)
    {
    }

    ngOnInit()
    {
        if (this._autofocus || typeof this._autofocus === "undefined")
            this.el.nativeElement.focus();      //For SSR (server side rendering) this is not safe. Use: https://github.com/angular/angular/issues/15008#issuecomment-285141070)
    }

    @Input() set autofocus(condition: boolean)
    {
        this._autofocus = condition != false;
    }
}

사용 사례:

[autofocus] //will focus
[autofocus]="true" //will focus
[autofocus]="false" //will not focus

autofocus최소한 페이지 초기화에 사용할 수 있는 기본 HTML 기능입니다.그러나 많은 각도의 시나리오에서 작동하지 않습니다. 특히,*ngIf.

원하는 동작을 얻기 위해 정말 간단한 사용자 지정 지침을 만들 수 있습니다.

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

@Directive({
  selector: '[myAutofocus]'
})
export class AutofocusDirective implements OnInit {

  constructor(private elementRef: ElementRef) { };

  ngOnInit(): void {
    this.elementRef.nativeElement.focus();
  }

}

위 지침은 저의 사용 사례에 적용됩니다.

사용방법

<input *ngIf="someCondition" myAutofocus />

편집: 포커스를 부르기에는 너무 이른 사용 사례가 있는 것 같습니다.OnInit라이프 사이클 방법이 경우 다음으로 변경합니다.OnAfterViewInit대신.

변수를 할 수 .#myInput:

<input type="text" [(ngModel)]="title" #myInput />

요소가 구성요도합니다록되를 구현하도록 .AfterViewInit을 를사하 요의기잡습준으로 .ViewChild을 맞춥니다.ngAfterViewInit잠금 해제:

export class MyComponent implements AfterViewInit {
    @ViewChild("myInput") private _inputElement: ElementRef;

    [...]

    ngAfterViewInit(): void {
        this._inputElement.nativeElement.focus();
    }
}
<input type="text" [(ngModel)]="title" #myInput />
{{ myInput.focus() }}

템플릿 내부 입력 직후 {{myInput.focus()}}을(를) 추가하기만 하면 됩니다.

다음 지침은 Angular 4.0.1을 사용하는 경우에 사용할 수 있습니다.

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

@Directive({
  selector: '[myAutofocus]'
})
export class MyAutofocusDirective implements AfterViewInit {
  constructor(private el: ElementRef)
  {
  }
  ngAfterViewInit()
  {
    this.el.nativeElement.focus();
  }
}

다음과 같이 사용합니다.

<md-input-container>
    <input mdInput placeholder="Item Id" formControlName="itemId" name="itemId" myAutofocus>
</md-input-container>

OnInit 라이프사이클 이벤트를 사용하는 옵션은 저에게 적용되지 않았습니다.저는 또한 다른 답변에서 렌더러를 사용해 보았지만 저에게는 통하지 않았습니다.

true/false 기능이 필요하지 않지만 항상 자동 포커스를 설정하려면 Makla의 솔루션을 보다 짧게 구현할 수 있습니다.

autofocus.dll.ts:

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

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

export class AutofocusDirective implements AfterViewInit {

    constructor(private el: ElementRef) {
    }

    ngAfterViewInit() {
        // Otherwise Angular throws error: Expression has changed after it was checked.
        window.setTimeout(() => {
            this.el.nativeElement.focus();
        });
    }
}

사용 사례:

<input autofocus> //will focus

AfterViewOnInit 대신 Init은 내용이 채워질 경우 입력 필드의 내용 뒤에 커서를 놓습니다.

모듈에서 자동 포커스 지시문을 선언하고 내보내는 을 기억하십시오!

스마트 자동 포커스(다이나믹 포커스) 지침

Angular 오토포커스 지시사항에 대한 제 견해는 이렇습니다.

다음 지시어는 부울 값을 입력으로 수락하고 요소가 동적으로 초점을 맞출 수 있도록 평가된 부울 식을 기반으로 요소에 초점을 맞춥니다.

또한 지침을 적용할 수 있습니다.input/button/select/a요소를 직접 또는 상위 요소에도 적용할 수 있습니다.DOM에서 자동으로 초점을 맞출 첫 번째 적합한 요소를 검색합니다.

코드

import { AfterViewInit, Directive, ElementRef, Input, NgModule } from '@angular/core';


const focusableElements = [
  'input',
  'select',
  'button',
  'a',
];


@Directive({
  selector: '[autofocus]',
})
export class AutofocusDirective implements AfterViewInit {

  @Input()
  public set autofocus(shouldFocus: boolean) {
    this.shouldFocus = shouldFocus;
    this.checkFocus();
  }

  private shouldFocus = true;


  constructor(
    private readonly elementRef: ElementRef
  ) {
  }


  public ngAfterViewInit() {
    this.checkFocus();
  }


  private checkFocus() {

    if (!this.shouldFocus) {
      return;
    }

    const hostElement = (
      <HTMLElement>
      this.elementRef.nativeElement
    );

    if (!hostElement) {
      return;
    }

    if (focusableElements.includes(
      hostElement.tagName.toLowerCase())
    ) {
      hostElement.focus?.();

    } else if (hostElement?.querySelector) {

      for (const tagName of focusableElements) {
        const childElement = (
          <HTMLInputElement>
            hostElement.querySelector(tagName)
        );
        if (childElement) {
          childElement?.focus?.();
          break;
        }
      }

    }

  }

}


@NgModule({
  declarations: [
    AutofocusDirective,
  ],
  exports: [
    AutofocusDirective,
  ],
})
export class AutofocusModule {
}

사용 예

<!-- These are equivalent: -->
<input type="text" autofocus>
<input type="text" [autofocus]>
<input type="text" [autofocus]="true">

<!-- Conditional (dynamic) focusing: -->
<input type="text" [autofocus]="shouldBeFocused">
<input type="text" name="username" [autofocus]="focusedField === 'username'">

<!-- Using parent element: -->
<fieldset autofocus>
  <label>
    Username:
    <input type="text">
  </label>
</fieldset>

알려드립니다

이 코드는 최신 브라우저 환경에서만 완전히 작동하지만 다른 환경에서는 사용할 수 없습니다(예쁜 성능 저하).

IE11부터는 다른 모든 최신 브라우저와 마찬가지로 입력에 대한 네이티브 HTML 자동 포커스 속성도 Angular:

<input autofocus>
 
<input type="text" [(ngModel)]="title" autofocus>

갱신하다

아래 @adrug의 논평에서 언급한 바와 같이, 이 접근법은 함정이 있습니다.페이지가 로드될 때 한 번만 작동합니다.

Netanel Basal의 기사에서 설명한 것처럼, 더 나은 방법은 Angular Directive로 구현하는 것입니다.이미 다른 답변에서 제안한 바와 같이.

간단하지만 효과적인 이 기능을 사용해 보십시오.:

function addFocusInput() {
  document.getElementById('text-focus').focus();
}

addFocusInput();
<input id="text-focus" type="text" placeholder=""/>

이 게시물이 오래된 게시물이라는 것을 알지만 새로운 답을 찾는 다른 사람들을 위한 것입니다.각진 재료 대화 상자를 사용하고 있었는데 입력이 아닌 닫기 버튼을 자동으로 선택하고 있었습니다.

사용.cdk-focus-start(CDK의 일부)는 추가 코드 없이 이 문제를 해결합니다.

내 솔루션:

 <input type="text" id="searchInput">
// put focus on element with id 'searchInput', try every 100ms and retry 30 times
this.focus('searchInput',30,100);
focus( idElement:string, maxNbRetries:number, intervalMs:number){

    let nbRetries = 0;
    let elt = null;
    const stop$ = new Subject<boolean>();
    const source = interval(intervalMs);
    const source$ = source.pipe(
      tap(item=>{
        elt = document.getElementById(idElement);
        nbRetries++;
        if(nbRetries>maxNbRetries){
          stop$.next(true);
          console.log(`unable to put the focus on the element !`)
        }
      }),
      filter(item=>elt !=null),
      map(item=>{
        elt.focus();
        stop$.next(true);
      }),
      takeUntil(stop$)

    ).subscribe();
  }

포커스는 각 라이프사이클에서 잘 작동하지 않습니다.필드에 강제로 적용하기 위해 모든 'intervalMs'를 방출하는 관측치를 실행합니다.요소가 렌더링된 경우 ID로 찾을 수 있습니다.그런 다음 포커스를 설정할 수 있습니다.nbRetries > maxNbRetries 또는 요소 ID가 발견되면 takeUntil 연산자를 사용하여 관찰 가능한 항목을 중지합니다.

 myReactiveForm!: FormGroup;

 constructor(public el: ElementRef) { }

 onSubmit(myReactiveForm: any) {
   this.autoFocusOnError(myReactiveForm, this.el);
 }

자동 포커스에 이 기능을 사용합니다.

autoFocusOnError(form: any, el:any) {
  form.markAllAsTouched();
  for (const key of Object?.keys(form?.controls)) {
    if (form?.controls[key].invalid) {
       let rootElement = el.nativeElement;
       let invalidControl = rootElement.querySelector('[formcontrolname="' + key + '"]') ||
          rootElement.querySelector('[name="' + key + '"]');
    
       if (invalidControl?.tagName == "NG-SELECT") {
         invalidControl = invalidControl.querySelector("div.ng-select-container input");
       } else if (invalidControl?.tagName == "NG-MULTISELECT-DROPDOWN") {
          invalidControl = invalidControl.querySelector("div.multiselect-dropdown");
       }
       invalidControl?.focus();
       return false;
    }
  }
  return true;
}

언급URL : https://stackoverflow.com/questions/41873893/angular2-autofocus-input-element

반응형