Angular 2 form valueChanges fires continuously
Asked Answered
A

3

11

I am trying to update the value name of a form with a value I get from a service, once the location field is filled. I try to this by watching the valueChanges of the form object. It works, but it fires continuously, although the values don't change anymore. the debounceTime() and distinctUntilChanged() have no influence:

bookmarkForm: FormGroup;
ngOnInit(): void {

  this.bookmarkForm = this.formBuilder.group({
    name: ['', Validators.required],
    location: ['', Validators.required],
    description:'',
    shared: false
  });

  this.bookmarkForm.valueChanges
    //.debounceTime(800)
    //.distinctUntilChanged()
    .subscribe(formData => {
      if(formData.location){
        console.log('location changed', formData);
        this.bookmarkService.getBookmarkTitle(formData.location).subscribe(response => {
          console.log('Response: ', response);
          if(response){
            this.bookmarkForm.patchValue({name:response.title}, {emitEvent: false});
          }
        });
      }
    });
}    

The html template

<div class="container">
  <div class="col-md-8 col-md-offset-2">
    <form [formGroup]="bookmarkForm" novalidate (ngSubmit)="saveBookmark(bookmarkForm.value, bookmarkForm.valid)">
      <div class="form-group">
        <label for="location">Location*</label>
        <input type="text" class="form-control" id="location"
               required
               name="location"
               formControlName="location"
               placeholder="Usually an URL">
        <div [hidden]="bookmarkForm.controls.location.valid || (bookmarkForm.controls.location.pristine && !submitted)"
             class="alert alert-danger">
          Location is required
        </div>
      </div>
      <div class="form-group">
        <label for="name">Name*</label>
        <input type="text" class="form-control" id="name"
               required
               formControlName="name"
               placeholder="Name of the bookmark to recognize later">
        <div [hidden]="bookmarkForm.controls.name.valid || (bookmarkForm.controls.name.pristine && !submitted)"
             class="alert alert-danger">
          Name is required
        </div>
      </div>
      <div class="form-group">
        <label for="description">Notes...</label>
        <textarea class="form-control"
                  id="description"
                  formControlName="description"
                  placeholder="Make some notes to help you later by searching...">
        </textarea>
      </div>
      <div class="form-check">
        <label class="form-check-label">
          <input class="form-check-input" type="checkbox" value="true" formControlName="shared">
          <strong> Make this bookmark public so others can benefit from it </strong>
        </label>
      </div>
      <button type="submit" class="btn btn-default" [disabled]="!bookmarkForm.valid">Submit</button>
    </form>
  </div>
</div>

Any ideas? Thanks

Angus answered 27/1, 2017 at 6:11 Comment(1)
can you post Template?Pyorrhea
A
14

thank you for pointing me in the right direction. I had to execute the patchValue with the emitEvent flag on the FormControl. The patchValue on the FormGroup does not take this flag. So here is my solution:

this.bookmarkForm.valueChanges
  .debounceTime(800)
  .distinctUntilChanged()
  .subscribe(formData => {
    if(formData.location){
      console.log('location changed', formData);
      this.bookmarkService.getBookmarkTitle(formData.location).subscribe(response => {
        console.log('Respoonse: ', response);
        if(response){
          this.bookmarkForm.controls['name'].patchValue(response.title, {emitEvent : false});
        }
      });
    }
  });

Now the more elegant way is to listen for changes only in the location field and only then fill the title:

this.bookmarkForm.controls['location'].valueChanges
  .debounceTime(800)
  .distinctUntilChanged()
  .subscribe(location => {
    console.log('Location: ', location);
    this.bookmarkService.getBookmarkTitle(location).subscribe(response => {
      if(response){
        this.bookmarkForm.controls['name'].patchValue(response.title, {emitEvent : false});
      }
    });
  });
Angus answered 28/1, 2017 at 5:17 Comment(0)
D
20

You cat set emitEvent: false option to prevent form from triggering valueChanges:

form.patchValue({name:response.title}, {emitEvent: false})
Dogmatize answered 27/1, 2017 at 6:16 Comment(2)
Thanks for the answer Yuri... Somehow it still doesn't do it for me... I have updated the code in the question....Angus
Great! Works perfectlyApplejack
A
14

thank you for pointing me in the right direction. I had to execute the patchValue with the emitEvent flag on the FormControl. The patchValue on the FormGroup does not take this flag. So here is my solution:

this.bookmarkForm.valueChanges
  .debounceTime(800)
  .distinctUntilChanged()
  .subscribe(formData => {
    if(formData.location){
      console.log('location changed', formData);
      this.bookmarkService.getBookmarkTitle(formData.location).subscribe(response => {
        console.log('Respoonse: ', response);
        if(response){
          this.bookmarkForm.controls['name'].patchValue(response.title, {emitEvent : false});
        }
      });
    }
  });

Now the more elegant way is to listen for changes only in the location field and only then fill the title:

this.bookmarkForm.controls['location'].valueChanges
  .debounceTime(800)
  .distinctUntilChanged()
  .subscribe(location => {
    console.log('Location: ', location);
    this.bookmarkService.getBookmarkTitle(location).subscribe(response => {
      if(response){
        this.bookmarkForm.controls['name'].patchValue(response.title, {emitEvent : false});
      }
    });
  });
Angus answered 28/1, 2017 at 5:17 Comment(0)
P
1

But in this subscribe you are patching values why?

 this.bookmarkForm.valueChanges
    .subscribe(formData => {
      if(formData.location){
        console.log('location changed', formData);
        this.bookmarkService.getBookmarkTitle(formData.location).subscribe(response => {
          console.log('Response: ', response);
          if(response){
            this.bookmarkForm.patchValue({name:response.title});  <----- THIS HERE
          }
        });
      }
    });

You have problem because of this

 this.bookmarkForm.patchValue({name:response.title});
Pyorrhea answered 27/1, 2017 at 6:16 Comment(2)
Oh, I see... It's because I want the user to see the new value in the name field...Angus
@Adrian yes look on other answer Yury has posted how to fix it :)Pyorrhea

© 2022 - 2024 — McMap. All rights reserved.