angular4 ObjectUnsubscribedError

时间:2017-08-21 21:37:32

标签: angular reactjs rxjs angular2-routing angular2-services

我正在实施angular4客户端应用程序 我添加了一些服务,它们从后端发出一些http请求 然后,它开始抛出 ObjectUnsubscribedError 以下是截图:enter image description here

经过一些研究后,我发现了来自here

的以下警告"An error thrown when an action is invalid because the object has been unsubscribed."

我猜是ReactJs rxjs/Subject属性引起的问题。我想,我可能会取消订阅,但我的取消订阅代码是 ngOnDestroy() 方法,这是代码的退出。
所以,我找不到合适的解决方案或问题的确切原因 有任何建议或帮助吗? 感谢

我的代码的一部分:

import {Component, Inject, OnDestroy, OnInit} from '@angular/core';
import {Subject} from "rxjs/Subject";

import {APP_CONFIG} from "../../../config/app.config";
import {IAppConfig} from "../../../config/iapp.config";

import {HomelandsService} from "../../../shared/services/homelands.service";
import {SearchService} from "../../../shared/services/search.service";

import {Kelime} from "../../../shared/models/Kelime";
import {City} from "../../../shared/models/homeland/City";
import {County} from "../../../shared/models/homeland/County";
import {Area} from "../../../shared/models/homeland/Area";
import {Neighborhood} from "../../../shared/models/homeland/Neighborhood";
import {HomelandSearchInfo} from "../../../shared/models/HomelandSearchInfo";

@Component({
  selector: 'app-homeland-search-field',
  templateUrl: './homeland-search-field.component.html',
  styleUrls: ['./homeland-search-field.component.css'],
  providers: []
})
export class HomelandSearchFieldComponent implements OnInit, OnDestroy {

  //citiesChanges = new Subject<City[]>();
  countiesChanges = new Subject<County[]>();
  areasChanges = new Subject<Area[]>();
  neighborhoodsChanges = new Subject<Neighborhood[]>();

  cities: City[] = this.appConfig.cities;
  counties: County[];
  areas: Area[];
  neighborhoods: Neighborhood[];

  homelandSearchInfo: HomelandSearchInfo = {
    cityId: null,
    countyId: null,
    areaId: null,
    neighborhoodId: null
  };
  kelimeler: Kelime[];

  constructor(private homelandsService: HomelandsService,
              private searchService: SearchService,
              @Inject(APP_CONFIG) private appConfig: IAppConfig) { }



  ngOnInit() {

    this.countiesChanges = this.homelandsService.countiesChanges;
    this.areasChanges = this.homelandsService.areasChanges;
    this.neighborhoodsChanges = this.homelandsService.neighborhoodsChanges;
    this.countiesChanges.subscribe(
      (counties: County[]) => {
        this.counties = counties;
      }
    );
    this.areasChanges.subscribe(
      (areas: Area[]) => {
        this.areas = areas;
      }
    );
    this.neighborhoodsChanges.subscribe(
      (neighborhoods: Neighborhood[]) => {
        this.neighborhoods = neighborhoods;
      }
    );
    /*this.citiesChanges = this.homelandsService.citiesChanges;
    this.citiesChanges.subscribe(
      (cities: City[]) => {
        this.cities = cities;
        // Loads the cities of Turkey=223
        this.cities = this.homelandsService.getCities().filter((item)=> item.countryId == 223);
      }
    );*/
  }
  ngOnDestroy(){
    this.countiesChanges.unsubscribe();
    this.areasChanges.unsubscribe();
    this.neighborhoodsChanges.unsubscribe();
  }

  // ############################## HOMELAND EVENTs & HELPERs ##############################
  onSelectCity(cityId: number){
    this.homelandSearchInfo.cityId = cityId;
    this.homelandSearchInfo.countyId = null;
    this.homelandSearchInfo.areaId = null;
    this.homelandSearchInfo.neighborhoodId = null;
    //this.counties = this.homelandsService.getCounties().filter((item)=> item.cityId == cityId);
    //this.homelandsService.httpGetCountiesByCityId(cityId);
    this.areas = [];
    this.neighborhoods = [];

  }
  onSelectCounty(countyId: number){
    this.homelandSearchInfo.countyId = countyId;
    this.homelandSearchInfo.areaId = null;
    this.homelandSearchInfo.neighborhoodId = null;
    //this.areas = this.homelandsService.getAreas().filter((item)=> item.countyId == countyId );
    //this.homelandsService.httpGetAreasByCountyId(countyId);
    this.neighborhoods = [];

  }
  onSelectArea(areaId: number){
    this.homelandSearchInfo.areaId = areaId;
    this.homelandSearchInfo.neighborhoodId = null;
    console.log(areaId);
    //this.neighborhoods = this.homelandsService.getNeighborhoods().filter((item)=> item.areaId == areaId );
    //this.homelandsService.httpGetNeighborhoodsByAreaId(areaId);
  }
  onSelectNeighborhood(neighborhoodId: number){
    //this.homelandSearchInfo.neighborhoodId = neighborhoodId;
  }

  onSearch(){
    console.log(this.homelandSearchInfo);

    //1.search servise ilgili bilgileri gönderip sonuçları kelimelerde listelemek.
    this.searchService.searchHomeland(this.homelandSearchInfo);


  }}

====================

import {Inject, Injectable} from '@angular/core';
import {Http} from "@angular/http";
import {Subject} from "rxjs/Subject";

import {APP_CONFIG} from "../../config/app.config";
import {IAppConfig} from "../../config/iapp.config";

import {City} from "../models/homeland/City";
import {County} from "../models/homeland/County";
import {Area} from "../models/homeland/Area";
import {Neighborhood} from "../models/homeland/Neighborhood";
import {Observable} from "rxjs/Observable";
import "rxjs/add/operator/catch";

@Injectable()
export class HomelandsService {

  citiesChanges = new Subject<City[]>();
  countiesChanges = new Subject<County[]>();
  areasChanges = new Subject<Area[]>();
  neighborhoodsChanges = new Subject<Neighborhood[]>();

  cities: City[] = this.appConfig.cities;
  counties: County[] = [];
  areas: Area[] = [];
  neighborhoods: Neighborhood[] = [];

  constructor(private http: Http,
              @Inject(APP_CONFIG) private appConfig: IAppConfig) {
    //this.httpGetCities();
    //this.httpGetCounties();
    //this.httpGetAreas();
    //this.httpGetNeighborhoods();
  }

  getCities(){
    return this.cities.slice();
  }
  getCounties(){
    return this.counties.slice();
  }
  getAreas(){
    return this.areas.slice();
  }
  getNeighborhoods(){
    return this.neighborhoods.slice();
  }


  httpGetCities(){
    let url: string = this.appConfig.backendURL + 'cities/countryId=' + 223;
    this.http.get(url)
      .map(
        (response) => {
          const backendResponse = response.json();
          if(backendResponse.success){
            const cities: City[] = backendResponse.item;
            console.log(cities);
            return cities;
          }else{
            console.error(backendResponse.msg);
            return Observable.throw(backendResponse.msg)
          }
        }
      )
      .catch(
        (error: Response) => {
          console.error(error);
          return Observable.throw(error);
        }
      )
      .subscribe(
        (cities: City[]) => {
          this.cities = cities;
          this.citiesChanges.next(this.cities.slice());
        },
        (error: Error) => {
          console.error(error);
        }
      )
  }

  httpGetCounties(){
    let url: string = this.appConfig.backendURL + 'counties/';
    this.http.get(url)
      .map(
        (response) => {
          const backendResponse = response.json();
          if(backendResponse.success){
            const counties: County[] = backendResponse.item;
            console.log(counties);
            return counties;
          }else{
            console.error(backendResponse.msg);
            return Observable.throw(backendResponse.msg)
          }
        }
      )
      .catch(
        (error: Response) => {
          console.error(error);
          return Observable.throw(error);
        }
      )
      .subscribe(
        (counties: County[]) => {
          this.counties = counties;
          this.countiesChanges.next(this.counties.slice());
        },
        (error: Error) => {
          console.error(error);
        }
      )
  }
  httpGetCountiesByCityId(cityId: number){
    let url: string = this.appConfig.backendURL + 'counties/cityId=' + cityId;
    this.http.get(url)
      .map(
        (response) => {
          const backendResponse = response.json();
          if(backendResponse.success){
            const counties: County[] = backendResponse.item;
            console.log(counties);
            return counties;
          }else{
            console.error(backendResponse.msg);
            return Observable.throw(backendResponse.msg)
          }
        }
      )
      .catch(
        (error: Response) => {
          console.error(error);
          return Observable.throw(error);
        }
      )
      .subscribe(
        (counties: County[]) => {
          this.counties = counties;
          this.countiesChanges.next(this.counties.slice());
        },
        (error: Error) => {
          console.error(error);
        }
      )
  }

  httpGetAreas(){
    let url: string = this.appConfig.backendURL + 'areas/';
    this.http.get(url)
      .map(
        (response) => {
          const backendResponse = response.json();
          if(backendResponse.success){
            const areas: Area[] = backendResponse.item;
            console.log(areas);
            return areas;
          }else{
            console.error(backendResponse.msg);
            return Observable.throw(backendResponse.msg)
          }
        }
      )
      .catch(
        (error: Response) => {
          console.error(error);
          return Observable.throw(error);
        }
      )
      .subscribe(
        (areas: Area[]) => {
          this.areas = areas;
          this.areasChanges.next(this.areas.slice());
        },
        (error: Error) => {
          console.error(error);
        }
      )
  }
  httpGetAreasByCountyId(countyId: number){
    let url: string = this.appConfig.backendURL + 'areas/countyId=' + countyId;
    this.http.get(url)
      .map(
        (response) => {
          const backendResponse = response.json();
          if(backendResponse.success){
            const areas: Area[] = backendResponse.item;
            console.log(areas);
            return areas;
          }else{
            console.error(backendResponse.msg);
            return Observable.throw(backendResponse.msg)
          }
        }
      )
      .catch(
        (error: Response) => {
          console.error(error);
          return Observable.throw(error);
        }
      )
      .subscribe(
        (areas: Area[]) => {
          this.areas = areas;
          this.areasChanges.next(this.areas.slice());
        },
        (error: Error) => {
          console.error(error);
        }
      )
  }

  httpGetNeighborhoods(){
    let url: string = this.appConfig.backendURL + 'neighborhoods/';
    this.http.get(url)
      .map(
        (response) => {
          const backendResponse = response.json();
          if(backendResponse.success){
            const neighborhoods: Neighborhood[] = backendResponse.item;
            console.log(neighborhoods);
            return neighborhoods;
          }else{
            console.error(backendResponse.msg);
            return Observable.throw(backendResponse.msg)
          }
        }
      )
      .catch(
        (error: Response) => {
          console.error(error);
          return Observable.throw(error);
        }
      )
      .subscribe(
        (neighborhoods: Neighborhood[]) => {
          this.neighborhoods = neighborhoods;
          this.neighborhoodsChanges.next(this.neighborhoods.slice());
        },
        (error: Error) => {
          console.error(error);
        }
      )
  }
  httpGetNeighborhoodsByAreaId(areaId: number){
    let url: string = this.appConfig.backendURL + 'neighborhoods/areaId=' + areaId;
    this.http.get(url)
      .map(
        (response) => {
          const backendResponse = response.json();
          if(backendResponse.success){
            const neighborhoods: Neighborhood[] = backendResponse.item;
            console.log(neighborhoods);
            return neighborhoods;
          }else{
            console.error(backendResponse.msg);
            return Observable.throw(backendResponse.msg)
          }
        }
      )
      .catch(
        (error: Response) => {
          console.error(error);
          return Observable.throw(error);
        }
      )
      .subscribe(
        (neighborhoods: Neighborhood[]) => {
          this.neighborhoods = neighborhoods;
          this.neighborhoodsChanges.next(this.neighborhoods.slice());
        },
        (error: Error) => {
          console.error(error);
        }
      )
  }

}

更新
我已经删除了ngOnDestroy()方法中的取消订阅代码,错误消失了。但是,必须在代码中的某处取消订阅主题。所以,问题实际上并未解决。有什么建议???

1 个答案:

答案 0 :(得分:0)

创建Subscription并取消订阅,而不是退出主题本身。取消订阅主题或行为主题将关闭可观察对象。试试这个:

import { Subject, Subscription } from 'rxjs';

为订阅创建属性并将其分配给订阅。

countiesChangesSubscription: Subscription;

this.countiesChangesSubscription = this.countiesChanges.subscribe(...)

然后仅取消订阅订阅,而不是观察到的订阅。

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

对您不想在销毁时关闭的所有订阅执行此操作。