Search code examples
angulartypescriptrxjscircular-reference

Converting circular structure to JSON starting at object with constructor 'Subscriber'


I'm getting the following error when trying to subscribe to my observable. I'm not quite certain why because I'm not using any type of Stringify (to my knowledge) in the code. It's just getting a JSON array from an api.

 ERROR TypeError: Converting circular structure to JSON
        --> starting at object with constructor 'Subscriber'
        |     property '_subscriptions' -> object with constructor 'Array'
        |     index 0 -> object with constructor 'MapSubscriber'
        --- property '_parentOrParents' closes the circle
        at JSON.stringify (<anonymous>)
        at JsonPipe.transform (common.js:4752)
        at Module.ɵɵpipeBind1 (core.js:25782)
        at TicketlistComponent_Template (ticketlist.component.html:4)
        at executeTemplate (core.js:9600)
        at refreshView (core.js:9466)
        at refreshComponent (core.js:10637)
        at refreshChildComponents (core.js:9263)
        at refreshView (core.js:9516)
        at refreshEmbeddedViews (core.js:10591)

It seems to occur right after the observable is returned from the Service

AppModule

import { NgModule, ViewChild } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu';
import { MatButtonModule } from '@angular/material/button';
import { MenuComponent } from './menu/menu.component';
import { MatDividerModule } from '@angular/material/divider';
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
import { HomeComponent } from './home/home.component';
import { TicketlistComponent } from './ticketlist/ticketlist.component';
import { TicketdetailComponent } from './ticketdetail/ticketdetail.component';
import { TicketcenterComponent } from './ticketcenter/ticketcenter.component';
import { HttpClientModule } from '@angular/common/http';


@NgModule({
  declarations: [
    AppComponent,
    MenuComponent, 
    HomeComponent, TicketlistComponent, TicketdetailComponent, TicketcenterComponent
  ],
  imports: [
    BrowserModule, 
    BrowserAnimationsModule, 
    AppRoutingModule, 
    MatMenuModule, 
    MatButtonModule, 
    MatDividerModule, 
    NgbNavModule, 
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {

 }

AppComponent

import { Component, OnInit } from '@angular/core';
import { HomeComponent } from '../app/home/home.component';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit{
  title = 'Charity';

  ngOnInit(home = HomeComponent){
    
  }
  
}

App-Routing-Module

import { Component, NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { TicketlistComponent } from './ticketlist/ticketlist.component';

const routes: Routes = [
  { path: "ticketList", component: TicketlistComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

connections service

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { ITicketList } from '../interfaces/i-ticket-list';

@Injectable({
  providedIn: 'root'
})
export class ConnectionsService {

  constructor(private http : HttpClient) { }

  myServer: string = "https://localhost:5001/"

  getTicketList(): Observable<ITicketList[]>
  {
    console.log('getTicketList()')
    return this.http.get<ITicketList[]>(this.myServer + "Tickets/getTickets")
  } 
}

ticketlist component

import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { ITicketList } from '../interfaces/i-ticket-list';
import { ConnectionsService } from '../services/connections.service';

@Component({
  selector: 'app-ticketlist',
  templateUrl: './ticketlist.component.html',
  styleUrls: ['./ticketlist.component.scss']
})
export class TicketlistComponent implements OnInit {

  constructor(private connService : ConnectionsService) { }

  getTickets$ : Observable<ITicketList[]> | any;

  getTickets()
  {
    console.log('getTickets')
    this.getTickets$ = this.connService.getTicketList().subscribe();
  }

  ngOnInit(): void {

    console.log('ngOnInit')
    this.getTickets();

  }

}

ticketlist html

<p>ticketlist works!</p>

<!-- <div *ngIf="getTickets$ | async as getTickets; else loading"> -->
    {{ getTickets$ | json }}
<!-- </div> -->

<!-- <ng-template #loading>
    loading...
</ng-template> -->

ITicketList (Interface)

export interface ITicketList {

    ticketId : string, 
    customerId: string, 
    createdOn: Date, 
    statusId: number, 
    statusDesc: string

}

Sample Payload

[{"ticketId":"b4d8e061-1bd9-eb11-8f59-9408532f1cc6","customerId":"b3d8e061-1bd9-eb11-8f59-9408532f1cc6","createdOn":"2021-06-29T16:48:40.44","statusId":1,"statusDesc":"Open"}]

Solution

  • From reading the error call stack, I think it's this line:

    {{ getTickets$ | json }}
    

    You can't json pipe an Observable stream.

    It should instead be something like this:

    <div *ngIf="getTickets$ | async as getTickets; else loading">
        {{ getTickets | json }}
    </div>