简体   繁体   English

Angular 2 - FormGroup ValueChanges 退订

[英]Angular 2 - FormGroup ValueChanges Unsubscribe

I have a FormGroup with ValueChanges event that is not being released from memory when the user moves from component's route to another component and then they return to the component.我有一个带有 ValueChanges 事件的 FormGroup,当用户从组件的路由移动到另一个组件然后他们返回到该组件时,该事件没有从内存中释放。

What this means is that if the user navigates away from component and then back to the component 5 times, the onFormChange method fires 5 times, but only 1 of those calls is for the current component.这意味着如果用户 5 次离开组件然后返回组件,onFormChange 方法会触发 5 次,但其中只有 1 次调用是针对当前组件的。

I figured that the problem was that I needed to unsubscribe from the the valueChanges event in the NgDestroy event, but there is no unsubscribe method available on the valueChanges event.我认为问题在于我需要取消订阅 NgDestroy 事件中的 valueChanges 事件,但 valueChanges 事件中没有可用的取消订阅方法。

I am sure I have to unsubscribe or release memory for something, but I'm not sure what.我确定我必须取消订阅或释放内存,但我不确定是什么。

import * as _ from 'lodash';
import {Observable} from 'rxjs/Rx';

import {Component, Input, Output, EventEmitter, OnInit, OnDestroy} from '@angular/core';
import {FormGroup} from '@angular/forms';

import {formConfig} from './toolbar.form-config';
import {JobToolbarVm} from '../view-model/job-toolbar.vm';
import {BroadcastService} from '../../../services/broadcast/broadcast.service';

@Component({
    selector: 'wk-job-toolbar',
    template: require('./toolbar.html'),
})
export class JobToolbarComponent implements OnInit, OnDestroy {

  protected form: FormGroup;

  @Input()
  toolbar: JobToolbarVm;

  @Output()
  toolbarChanged = new EventEmitter<JobToolbarVm>();

  @Output()
  refresh = new EventEmitter<string>();

  constructor(private broadcast: BroadcastService) {
  }

  ngOnInit() {

    this.form = formConfig;
    this.form.setValue(this.toolbar, {onlySelf: true});

    // This ALWAYS RUNS when the form loads, ie. on the job route
    console.log('FORM VALUE');
    console.log(JSON.stringify(this.form.value, null, 2));

    this.form.valueChanges
      .debounceTime(2000)
      .subscribe(
        this.onFormChange.bind(this)
      );
  }

  ngOnDestroy() {
    //this.form.valueChanges.unsubscribe();
    //this.onChanges.unsubscribe();
    //this.toolbarChanged.unsubscribe();
    //this.form = null;
  }

  onFormChange(data: any) {
    // This runs whenever I go to a different route and then come back to this route
    // There is also a memory leak, because this method fires multiple times based on how
    // often I navigate away and come back to this route.
    // e.g. Navigate away and then back 5 times, then I see this log statement 5 times 
    console.log('FORM VALUE2 - THIS KEEPS FIRING FOR EACH INSTANCE OF MY COMPOMENT');
    console.log(JSON.stringify(this.form.value, null, 2));

    JobToolbarVm.fromJsonIntoInstance(data, this.toolbar);

    this.onChanges('data-changed');
  }

  onChanges($event: any) {
    console.log('onChanges: ' + $event);
    // console.log(this.toolbar);

    // Send the toolbar object back out to the parent
    this.toolbarChanged.emit(this.toolbar);

    // Broadcast an event that will be listened to by the list component so that it knows when to refresh the list
    this.broadcast.broadcast('job-admin-toolbar-changed', this.toolbar);
  }
}

The subscribe() call returns a Subscription and this is what you use to unsubscribe: subscribe()调用返回一个Subscription ,这是您用来取消订阅的:

class JobToolbarComponent

  private subscr:Subscription;

  ngOnInit() {
    ...
    this.subscr = this.form.valueChanges ...
    ...
  }

  ngOnDestroy() {
    this.subscr.unsubscribe();
  }
}

I have created this following function我创建了以下功能

export function AutoUnsubscribe(exclude = []) {

    return function (constructor) {

        const original = constructor.prototype.ngOnDestroy;

        constructor.prototype.ngOnDestroy = function () {
            for (let prop in this) {
                const property = this[prop];
                if (!exclude.includes(prop)) {
                    if (property && (typeof property.unsubscribe === "function")) {
                        property.unsubscribe();
                    }
                }
            }
            original && typeof original === 'function' && original.apply(this, arguments);
        };
    }

}

which actually you can use to auto unsubscribe all the watchers but you have to store them in public properties so that this function can intercept it and invoke unsubscribe on that.实际上,您可以使用它来自动取消订阅所有观察者,但您必须将它们存储在公共属性中,以便该函数可以拦截它并对其调用取消订阅。 How you use it is mentioned below:-您如何使用它如下所述:-

@AutoUnsubscribe()
@Component({
    selector: 'account-login',
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {


    public submitWatcher: Subscription;

     submit() {
        this.submitWatcher = this.authService.login(this.loginForm.getRawValue())
            .subscribe(res => {
                if (this.returnUrl) {
                    this.router.navigate([this.returnUrl]);
                }
                else {
                    this.router.navigate(['/special']);
                }
            }, (error) => {
                alert(JSON.stringify(error.data));
            });
    }

}

For more info on how to use decorator please read this blog that's where I have taken the idea from and it is pretty cool有关如何使用装饰器的更多信息,请阅读这个博客,这是我从中获得这个想法的地方,它非常酷

Blog 博客

You could do the following:您可以执行以下操作:

// private variable to hold all your subscriptions for the component
private subscriptions: Subscription[] = [];

// when you subscribe to an observable,
// you can push all subscription this.subscriptions

this.subscriptions.push(
       this.form.valueChanges.pipe(
            .debounceTime(2000)) 
            .subscribe(val => this.onFormChange.bind(this)),

       this.observe2$.subscribe(val => this.somemethod(val))
    );

// in ngondestroy
    ngOnDestroy(): void {
        if (this.subscriptions && this.subscriptions.length > 0) {
            this.subscriptions.forEach(s => s.unsubscribe());
        }
    }

I am not sure if this is a good idea but this is very simple to implement and it works well for my school project.我不确定这是否是一个好主意,但这很容易实现,并且适用于我的学校项目。

var sub = this.items.subscribe(snapshots => {
    console.log(snapshots);
    sub.unsubscribe();
});

Source: https://github.com/angular/angularfire2/issues/377来源: https ://github.com/angular/angularfire2/issues/377

The easiest to put together the subscriptions is to use the add method : subscription.add( anotherSubscription ) so now you just have to unsubscribe from only one subscription.将订阅组合在一起的最简单方法是使用 add 方法:subscription.add( anotherSubscription ) 所以现在您只需取消订阅一个订阅。

You can find the following example from the official doc : https://rxjs.dev/guide/subscription您可以从官方文档中找到以下示例: https ://rxjs.dev/guide/subscription

import { interval } from 'rxjs';
 
const observable1 = interval(400);
const observable2 = interval(300);
 
const subscription = observable1.subscribe(x => console.log('first: ' + x));
const childSubscription = observable2.subscribe(x => console.log('second: ' + x));
 
subscription.add(childSubscription);
 
setTimeout(() => {
  // Unsubscribes BOTH subscription and childSubscription
  subscription.unsubscribe();
}, 1000); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Angular2取消订阅formGroup上的valueChanges - Angular2 unsubscribe valueChanges on formGroup 取消订阅 Angular valueChanges - Unsubscribe Angular valueChanges Angular FormGroup valueChanges将属性转换为数组 - Angular FormGroup valueChanges converts properties to arrays 是否有必要退订可观察的Angular Form statusChanges / valueChanges? - Is it necessary to unsubscribe Angular Form statusChanges/valueChanges observable? patchValue 和 { emitEvent: false } 触发 Angular 4 表单组上的 valueChanges - patchValue with { emitEvent: false } triggers valueChanges on Angular 4 formgroup 如何取消订阅 Angular 4 反应形式的 valueChanges? - How to unsubscribe from valueChanges in Angular 4 reactive forms? Angular2 FormGroup - 如何确定哪个控件触发值更改 - Angular2 FormGroup - How to determine which control triggered valuechanges Angular 2 - 订阅 FormControl 的 valueChanges 是否需要取消订阅? - Angular 2 - Does subscribing to FormControl's valueChanges need an unsubscribe? 如何在angular 7 FormGroup valueChanges中删除多个订阅列表中的特定订阅? - how to remove specific subscribe in multiple subscribes list in angular 7 FormGroup valueChanges? Angular 10:我应该取消订阅 ngOnDestroy 中 valueChanges Observable 的订阅吗? - Angular 10 : Should I unsubscribe form subscription to valueChanges Observable in ngOnDestroy?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM