programing

Angular 2 NgForm에서 터치된 이벤트를 관찰하는 방법은 무엇입니까?

telebox 2023. 6. 11. 10:34
반응형

Angular 2 NgForm에서 터치된 이벤트를 관찰하는 방법은 무엇입니까?

에 대한 콜백을 구독할 수 있습니다.NgFormvalueChanges양식 컨트롤의 값 변화에 대응하기 위해 관찰 가능한 속성입니다.

같은 방식으로 사용자가 양식 컨트롤 중 하나를 터치하는 경우에도 대응해야 합니다.

클래스는 다음을 정의하는 것 같습니다.valueChanges관찰 가능 및touched속성이 부울로 정의되었습니다.

"컨트롤 터치" 이벤트에 대응할 수 있는 방법이 있습니까?

기본값을 확장할 수 있습니다.FormControl클래스, 추가markAsTouched네이티브 메소드를 호출하는 메소드와 당신의 부작용을 추가됩니다.

import { Injectable } from '@angular/core';
import { FormControl, AsyncValidatorFn, ValidatorFn } from '@angular/forms';
import { Subscription, Subject, Observable } from 'rxjs';

export class ExtendedFormControl extends FormControl {
  statusChanges$: Subscription;
  touchedChanges: Subject<boolean> = new Subject<boolean>();

  constructor(
    formState: Object,
    validator: ValidatorFn | ValidatorFn[] = null,
    asyncValidator: AsyncValidatorFn | AsyncValidatorFn[] = null
  ) {
    super(formState, validator, asyncValidator);

    this.statusChanges$ = Observable.merge(
      this.valueChanges,
      this.touchedChanges.distinctUntilChanged()
    ).subscribe(() => {
      console.log('new value or field was touched');
    });
  }

  markAsTouched({ onlySelf }: { onlySelf?: boolean } = {}): void {
    super.markAsTouched({ onlySelf });

    this.touchedChanges.next(true);
  }
}

ng2가 터치된 이벤트에 반응할 수 있는 직접적인 방법은 없습니다.(입력) 이벤트를 사용하여 Changes 이벤트를 발생시키고 (흐림) 이벤트를 사용하여 AbstractControl touched/untouched 속성을 설정합니다.따라서 템플릿에서 원하는 이벤트를 수동으로 구독하고 구성 요소 클래스에서 처리해야 합니다.

동일한 문제가 발생했습니다. 이 도우미 방법을 함께 사용하여 터치 상태가 변경될 때 알림을 받을 수 있는 양식으로 구독할 수 있는 관찰 항목을 추출합니다.

// Helper types

/**
 * Extract arguments of function
 */
export type ArgumentsType<F> = F extends (...args: infer A) => any ? A : never;

/**
 * Creates an object like O. Optionally provide minimum set of properties P which the objects must share to conform
 */
type ObjectLike<O extends object, P extends keyof O = keyof O> = Pick<O, P>;


/**
 * Extract a touched changed observable from an abstract control
 * @param control AbstractControl like object with markAsTouched method
 */
export const extractTouchedChanges = (control: ObjectLike<AbstractControl, 'markAsTouched' | 'markAsUntouched'>): Observable<boolean> => {
  const prevMarkAsTouched = control.markAsTouched.bind(control);
  const prevMarkAsUntouched = control.markAsUntouched.bind(control);

  const touchedChanges$ = new Subject<boolean>();

  function nextMarkAsTouched(...args: ArgumentsType<AbstractControl['markAsTouched']>) {
    prevMarkAsTouched(...args);
    touchedChanges$.next(true);
  }

  function nextMarkAsUntouched(...args: ArgumentsType<AbstractControl['markAsUntouched']>) {
    prevMarkAsUntouched(...args);
    touchedChanges$.next(false);
  }
  
  control.markAsTouched = nextMarkAsTouched;
  control.markAsUntouched = nextMarkAsUntouched;

  return touchedChanges$;
}
// Usage (in component file)

...
    this.touchedChanged$ = extractTouchedChanges(this.form);
...

나는 그럼 하는 것을 좋아합니다.merge(this.touchedChanged$, this.form.valueChanges)유효성 검사를 업데이트하는 데 필요한 모든 변경 사항을 관찰할 수 있습니다.

*편집 - @marked-down의 제안으로 새 값을 받은바로 쿼리하여 동기화되지 않을 경우를 대비하여 값을 내보내기 전의 함수로 통화를 이동했습니다.

만약 당신의 문제가 나의 문제와 같다면, 나는 한 구성 요소에서 필드를 터치한 것으로 표시한 다음 다른 구성 요소에서 응답하려고 했습니다.나는 접근 권한이 있었습니다.AbstractControl그 방면에.내가 그것을 피하는 방법은

field.markAsTouched();
(field.valueChanges as EventEmitter<any>).emit(field.value);

그런 다음 다른 구성 요소에서 valueChanges를 구독했습니다.주목할 점:field.valueChanges관찰할 수 있는 항목으로 내보내지만 런타임에EventEmitter이것을 덜 아름다운 해결책으로 만드는 것.이것의 또 다른 한계는 분명히 여러분이 단지 만진 상태 이상의 것을 구독하고 있다는 사실일 것입니다.

이 방법으로 해결했습니다.

this.control['_markAsTouched'] = this.control.markAsTouched;
this.control.markAsTouched = () => {
  this.control['_markAsTouched']();
  // your event handler
}

기본적으로 기본값을 덮어쓰고 있습니다.markAsTouched의 방법FormControl.

여기 제가 생각해 낸 util 기능이 있습니다, 그것은 또한 듣습니다.reset메서드 및 컨트롤을 그대로 유지합니다.

/**
 * Allows to listen the touched state change.
 * The util is needed until Angular allows to listen for such events.
 * Https://github.com/angular/angular/issues/10887.
 * @param control Control to listen for.
 */
export function listenControlTouched(
  control: AbstractControl,
): Observable<boolean> {
  return new Observable<boolean>(observer => {
    const originalMarkAsTouched = control.markAsTouched;
    const originalReset = control.reset;

    control.reset = (...args) => {
      observer.next(false);
      originalReset.call(control, ...args);
    };

    control.markAsTouched = (...args) => {
      observer.next(true);
      originalMarkAsTouched.call(control, ...args);
    };

    observer.next(control.touched);

    return () => {
      control.markAsTouched = originalMarkAsTouched;
      control.reset = originalReset;
    };
  });
}

언급URL : https://stackoverflow.com/questions/41337024/how-to-observe-touched-event-on-angular-2-ngform

반응형