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);

}

다음은 JSFiddleAngular 예제입니다 .

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.