Angular에서 양식 변경을 감시하는 방법


151

Angular에서는 다음과 같은 형식이있을 수 있습니다.

<ng-form>
    <label>First Name</label>
    <input type="text" ng-model="model.first_name">

    <label>Last Name</label>
    <input type="text" ng-model="model.last_name">
</ng-form>

해당 컨트롤러 내에서 다음과 같이 해당 양식의 내용이 변경되었는지 쉽게 확인할 수 있습니다.

function($scope) {

    $scope.model = {};

    $scope.$watch('model', () => {
        // Model has updated
    }, true);

}

다음은 JSFiddle 의 Angular 예제입니다 .

Angular에서 동일한 작업을 수행하는 방법을 알아내는 데 어려움을 겪고 있습니다. 분명히 더 이상 $scope$ rootScope 가 없습니다 . 분명히 같은 것을 성취 할 수있는 방법이 있습니까?

다음은 Plunker에 대한 Angular 예제입니다 .


컨트롤러에서 일부 데이터를 보는 대신 양식에서 이벤트 (예 : ng-change와 같은)를 시작해야한다고 생각합니다.
— Deblaton Jean-Philippe

btw, 범위를 제거하는 이유는 해당 감시자를 제거하기위한 것입니다. 앵귤러 2 어딘가에 숨겨진 시계가 있다고 생각하지 않습니다
— Deblaton Jean-Philippe

4
내가 당신을 올바르게 이해하고 있다면, 이것을 달성하기 위해 모든 양식 입력에 (ngModelChange)="onModelChange($event)"속성을 추가 할 것을 제안하고 있습니까?
— tambler

1
양식 인스턴스 자체가 일종의 변경 이벤트를 생성하지 않습니까? 그렇다면 어떻게 액세스합니까?
— tambler

무엇을해야할지 확신이 없다면 의견을 제시하는 대신 대답했을 것입니다. 나는 앵귤러 2.0을 아직 사용하지는 않았지만, 읽은 내용에서 시계는 이벤트 기반 프레임 워크를 갖기 위해 완전히 사라졌습니다 (각 다이제스트에서 딥 워치 대신 수행)
— Deblaton Jean-Philippe

답변:


189

UPD. 답변과 데모는 최신 Angular에 맞춰 업데이트됩니다.


양식을 나타내는 FormGroupvalueChanges 이 Observerable 인스턴스 인 속성을 제공 하기 때문에 전체 양식 변경을 구독 할 수 있습니다 .

this.form.valueChanges.subscribe(data => console.log('Form changes', data));

이 경우 FormBuilder를 사용하여 양식을 수동으로 생성해야합니다 . 이 같은:

export class App {
  constructor(private formBuilder: FormBuilder) {
    this.form = formBuilder.group({
      firstName: 'Thomas',
      lastName: 'Mann'
    })

    this.form.valueChanges.subscribe(data => {
      console.log('Form changes', data)
      this.output = data
    })
  }
}

valueChanges이 데모 에서 동작을 확인하십시오 : http://plnkr.co/edit/xOz5xaQyMlRzSrgtt7Wn?p=preview


2
이것은 마크에 매우 가깝습니다. 확인하기 위해- 양식이 템플릿 내에서만 정의 된 경우 양식의 이벤트 이미 터 를 구독 할 수 없다고 말하고 있습니까? 즉, 구성 요소의 생성자 내에서 FormBuilder의 도움이 아닌 해당 구성 요소의 템플릿 내에서만 정의 된 양식에 대한 참조를 얻을 수 없습니까? valueChanges
— tambler

이것이 정답입니다. 양식 작성기가없는 경우 템플릿 기반 양식을 수행하는 것입니다. 여전히 양식을 주입하지만 당신은 관찰 form.valueChanges을 원한다면 당신은 확실히 formBuilder를 사용하고 겨 모델을 포기해야 얻을 수있는 방법 아마이
— 각도 대학

2
@tambler,를 사용하여 NgForm에 대한 참조를 얻을 수 있습니다 @ViewChild(). 업데이트 된 답변을 참조하십시오.
— Mark Rajcok

1
파괴를 신청할 필요가 없습니까?
— Bazinga

1
@galvan 누출이 없을 것이라고 생각합니다. 폼은 컴포넌트의 일부이며 모든 필드와 이벤트 리스너와 함께 파기시 올바르게 처리됩니다.
— dfsq

107

를 사용하는 경우 FormBuilder@dfsq의 답변을 참조하십시오.

를 사용하지 않는 경우 FormBuilder변경 사항을 알리는 두 가지 방법이 있습니다.

방법 1

질문에 대한 의견에서 논의했듯이 각 입력 요소에 이벤트 바인딩 을 사용하십시오 . 템플릿에 추가하십시오.

<input type="text" class="form-control" required [ngModel]="model.first_name"
         (ngModelChange)="doSomething($event)">

그런 다음 구성 요소에서

doSomething(newValue) {
  model.first_name = newValue;
  console.log(newValue)
}

양식 페이지는 여기에 관련 ngModel에 대한 몇 가지 추가 정보가 있습니다 :

은 ngModelChange없는 <input>요소 이벤트입니다. 실제로 NgModel지시문 의 이벤트 속성입니다 . Angular는 형식의 바인딩 대상을 볼 때 지시문에 입력 속성과 출력 속성 이 [(x)]있을 것으로 예상합니다 .xxxChange

다른 이상한 점은 템플릿 표현식 model.name = $event입니다. 우리는 $eventDOM 이벤트에서 객체가 나오는 것을 보았습니다 . ngModelChange 속성은 DOM 이벤트를 생성하지 않습니다. EventEmitter실행시 입력 상자 값을 반환 하는 Angular 속성입니다.

우리는 거의 항상 선호합니다 [(ngModel)]. 디 바운스 나 키 스트로크 조절과 같은 이벤트 처리에서 특별한 작업을 수행해야하는 경우 바인딩을 분할 할 수 있습니다.

귀하의 경우, 나는 당신이 특별한 것을하고 싶다고 생각합니다.

방법 2

로컬 템플릿 변수를 정의하고로 설정하십시오 ngForm.
입력 요소에 ngControl을 사용하십시오.
@ViewChild를 사용하여 폼의 NgForm 지시문에 대한 참조를 얻은 다음 변경을 위해 NgForm의 ControlGroup에 가입하십시오.

<form #myForm="ngForm" (ngSubmit)="onSubmit()">
  ....
  <input type="text" ngControl="firstName" class="form-control" 
   required [(ngModel)]="model.first_name">
  ...
  <input type="text" ngControl="lastName" class="form-control" 
   required [(ngModel)]="model.last_name">

class MyForm {
  @ViewChild('myForm') form;
  ...
  ngAfterViewInit() {
    console.log(this.form)
    this.form.control.valueChanges
      .subscribe(values => this.doSomething(values));
  }
  doSomething(values) {
    console.log(values);
  }
}

plunker

방법 2에 대한 자세한 내용은 Savkin의 비디오를 참조하십시오 .

valueChanges옵저버 블로 수행 할 수있는 작업 (예 : 변경 처리 전 약간의 수신 거부 / 대기) 에 대한 자세한 내용은 @Thierry의 답변을 참조하십시오 .


61

이전의보다 훌륭한 답변을 완성하려면 양식이 관찰 가능 항목을 활용하여 값 변경을 감지하고 처리한다는 점을 알고 있어야합니다. 정말 중요하고 강력합니다. Mark와 dfsq는이 측면을 답으로 설명했습니다.

Observables는이 subscribe방법 ( then각도 1의 약속 방법 과 유사한 것) 을 사용할 수있게 해줍니다 . 업데이트 된 데이터에 대한 일부 처리 체인을 양식으로 구현해야하는 경우 더 나아갈 수 있습니다.

이 수준에서 debounceTime방법으로 디 바운스 시간을 지정할 수 있습니다 . 이를 통해 변경을 처리하기 전에 일정 시간 동안 기다렸다가 여러 입력을 올바르게 처리 할 수 ​​있습니다.

this.form.valueChanges
    .debounceTime(500)
    .subscribe(data => console.log('form changes', data));

값이 업데이트 될 때 트리거하려는 처리 (예 : 일부 비동기 처리)를 직접 연결할 수도 있습니다. 예를 들어 AJAX 요청을 기반으로 목록을 필터링하기 위해 텍스트 값을 처리하려는 경우 다음 switchMap방법을 활용할 수 있습니다 .

this.textValue.valueChanges
    .debounceTime(500)
    .switchMap(data => this.httpService.getListValues(data))
    .subscribe(data => console.log('new list values', data));

반환 된 옵저버 블을 구성 요소의 속성에 직접 연결하여 더 진행할 수도 있습니다.

this.list = this.textValue.valueChanges
    .debounceTime(500)
    .switchMap(data => this.httpService.getListValues(data))
    .subscribe(data => console.log('new list values', data));

async파이프를 사용하여 표시하십시오 .

<ul>
  <li *ngFor="#elt of (list | async)">{{elt.name}}</li>
</ul>

Angular2에서 양식을 다르게 처리하는 방법 (훨씬 더 강력한 방법 ;-))을 생각해야한다고 말하면됩니다.

티에리가 당신을 도울 수 있기를 바랍니다.


'string'유형에 'valueChanges'특성이 없습니다.
— Toolkit

확인 양식 변경 방법을 배치 해야하는 TS 파일에 붙어 있습니까? 우리가 그것을 ngAfterViewInit () {}에 저장하면, this.form.valueChanges는 항상 업데이트 된 데이터를 위해 처리 체인을 양식으로 구현해야 할 경우 항상 호출되는 것 같습니다.
— Tài Nguyễn

1

Mark의 제안을 확장하는 중 ...

방법 3

모델에서 "심층적"변경 감지를 구현하십시오. 장점은 주로 사용자 인터페이스 측면을 컴포넌트에 통합하지 않는 것입니다. 이것은 또한 모델에 대한 프로그래밍 방식의 변화를 포착합니다. 즉, 티에리에 의해 제안 디 바운싱 같은 것들을 구현하기 위해 추가 작업이 필요하고, 이것은 또한 잡을 것입니다 말했다 자신의 주의와 함께 사용하기 때문에, 프로그램 변경.

export class App implements DoCheck {
  person = { first: "Sally", last: "Jones" };
  oldPerson = { ...this.person }; // ES6 shallow clone. Use lodash or something for deep cloning

  ngDoCheck() {
    // Simple shallow property comparison - use fancy recursive deep comparison for more complex needs
    for (let prop in this.person) {
      if (this.oldPerson[prop] !==  this.person[prop]) {
        console.log(`person.${prop} changed: ${this.person[prop]}`);
        this.oldPerson[prop] = this.person[prop];
      }
    }
  }

플 런커에서 시도


1

각도 5+버전의 경우. 각도를 변경하면 많은 버전을 만들 때 버전을 넣는 데 도움이됩니다.

ngOnInit() {

 this.myForm = formBuilder.group({
      firstName: 'Thomas',
      lastName: 'Mann'
    })
this.formControlValueChanged() // Note if you are doing an edit/fetching data from an observer this must be called only after your form is properly initialized otherwise you will get error.
}

formControlValueChanged(): void {       
        this.myForm.valueChanges.subscribe(value => {
            console.log('value changed', value)
        })
}

0

(ngModelChange) 메소드 사용에 대해 생각한 다음 FormBuilder 메소드에 대해 생각하고 마지막으로 메소드 3의 변형을 결정했습니다. 이렇게하면 템플릿을 추가 속성으로 장식하고 모델 변경 사항을 자동으로 선택하여 무언가를 잊을 가능성을 줄입니다. 방법 1 또는 2로

방법 3 조금 단순화 ...

oldPerson = JSON.parse(JSON.stringify(this.person));

ngDoCheck(): void {
    if (JSON.stringify(this.person) !== JSON.stringify(this.oldPerson)) {
        this.doSomething();
        this.oldPerson = JSON.parse(JSON.stringify(this.person));
    }
}

디 바운스를 시뮬레이션하기 위해 x 밀리 초 후에 doSomething ()을 호출하는 시간 초과를 추가 할 수 있습니다.

oldPerson = JSON.parse(JSON.stringify(this.person));

ngDoCheck(): void {
    if (JSON.stringify(this.person) !== JSON.stringify(this.oldPerson)) {
        if (timeOut) clearTimeout(timeOut);
        let timeOut = setTimeout(this.doSomething(), 2000);
        this.oldPerson = JSON.parse(JSON.stringify(this.person));
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.