user2870934
user2870934

Reputation: 709

Angular4 ngOnInit rxjs/Subject not working

I have Directive which has Subscription for resize chart

import {Directive, ElementRef, HostListener, Input, OnDestroy, OnInit} from '@angular/core';
import {Subscription} from 'rxjs/Subscription';
import echarts from 'echarts';
import 'echarts/theme/macarons';
import {ChartService} from '../service/chart/chart.service';

@Directive({selector: '[appECharts]'})
export class EChartsDirective implements OnInit, OnDestroy {
  element: ElementRef;
  subscription: Subscription;
  @Input() eChartsOptions: any;
  @Input() theme = 'macarons';
  private chart;

  constructor(element: ElementRef, private chartsService: ChartService) {
    this.element = element;
  }

  ngOnInit() {
    this.subscription = this.chartsService.chartChange.subscribe((str) => {
      this.resizeChart(str);
    });
    this.chart = echarts.init(this.element.nativeElement, this.theme);
    if (this.eChartsOptions) {
      this.chart.setOption(this.eChartsOptions);
    }
  }

  ngOnDestroy() {
    if (this.chart) {
      this.chart = null;
    }
    this.subscription.unsubscribe();
  }

  resizeChart(str: string) {
    console.log('resize from=' + str);
    setTimeout(() => {
      if (this.chart) {
        console.log('resize');
        this.chart.resize();
      }
    }, 500);
  }

  @HostListener('window:resize')
  onResize() {
    this.resizeChart('window');
  }
}

ChartService:

import {Injectable} from '@angular/core';
import {Subject} from 'rxjs/Subject';

@Injectable()
export class ChartService {
  chartChange = new Subject<string>();
  orderChartChanged = new Subject<any[]>();
  private orderCharts: any[];

  setChartData(orderCharts) {
    this.orderCharts = orderCharts;
    this.orderChartChanged.next(this.orderCharts);
  }

  updateCharts(srt: string) {
    console.log('from=' + srt);
    this.chartChange.next(srt);
  }
}

And Component where I calling updateCharts method

import {Component, ElementRef, OnDestroy, OnInit, ViewChild} from '@angular/core';
import {ChartHttpService} from '../../shared/service/chart/chart-http.service';
import {MdSnackBar} from '@angular/material';
import {Subscription} from 'rxjs/Subscription';
import {ChartService} from '../../shared/service/chart/chart.service';
import echarts from 'echarts';
import 'echarts/theme/macarons';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnDestroy, OnInit {
  chartSubscription: Subscription;
  @ViewChild('chart1') element: ElementRef;
  chart2;

  constructor(private chartService: ChartService,
              private chartHttpService: ChartHttpService,
              public snackBar: MdSnackBar) {
  }

  ngOnInit() {
    const chart = echarts.init(this.element.nativeElement, 'macarons');
    this.chartSubscription = this.chartService.orderChartChanged
      .subscribe(
        (response: any) => {
          const option = response.orderAmount;
          chart.setOption(option);
          setTimeout(() => {
            chart.resize();
          }, 500);
          this.chart2 = option;
          this.chartService.updateCharts('home');
        }
      );
    this.chartHttpService.orderCharts(this.snackBar);
  }

  ngOnDestroy() {
    this.chartSubscription.unsubscribe();
    this.chart2 = null;
  }

  onResize() {
    this.chartService.updateCharts('btn');
  }

}

ChartHttpService:

import {Injectable} from '@angular/core';
import {MdSnackBar} from '@angular/material';
import {HttpClient} from '@angular/common/http';

import {TranslateService} from '@ngx-translate/core';
import {Observable} from 'rxjs/Observable';
import 'rxjs/Rx';
import {SnackBarUtils} from '../snack-bar-utils';
import {environment} from '../../../../environments/environment';
import {ChartService} from './chart.service';

@Injectable()
export class ChartHttpService {
  private static orderCharts = 'json/chart/ordersChart';

  constructor(private http: HttpClient,
              private chartService: ChartService,
              private translate: TranslateService) {
  }

  orderCharts(snackBar: MdSnackBar) {
    const url = environment.apiUrl + ChartHttpService.orderCharts;
    this.http.get(url)
      .catch(error => {
        return Observable.throw(error);
      })
      .subscribe(
        response => this.chartService.setChartData(response),
        error => SnackBarUtils.showLocalizedSnackBar(this.translate, snackBar, 'msg.error')
      );
  }
}

And html component:

<div class="row">
  <div class="col-lg-6 col-md-6 col-xs-12 col-sm-6">
    <md-card>
      <div class="box-header">Base Line</div>
      <div #chart1 style="height: 300px;"></div>
    </md-card>
  </div>
  <div class="col-lg-6 col-md-6 col-xs-12 col-sm-6">
    <md-card>
      <div class="box-header">Stacked Line</div>
      <ng-container *ngIf="chart2">
        <div appECharts [eChartsOptions]="chart2" style="height: 300px;"></div>
      </ng-container>
    </md-card>
  </div>
  <button (click)="onResize()">Resize</button>
</div>

So the problem is when I press refresh in browser or f5, updateCharts method invokes in HomeComponent but chartChange Subject didn't work I guess, because in EChartsDirective subscription didn't invoke method resizeChart, and this problem is ONLY after refresh or f5. If i click on Resize btn, everything works fine.

So i don't know why, but subscription in EChartsDirective didn't invoke resizeChart after refresh or f5.

Any ideas why its happens?

UPDATE: And problem only with chart2, I add chart1, which i init manually(without Directive) in HomeComponent -> ngOnInit, and when i'm calling

setTimeout(() => {
            chart.resize();
          }, 500);

It works, but of course, problem only with Subscription, but still)

UPDATE2: Change to:

   ngOnInit() {
   this.chart = echarts.init(this.element.nativeElement, this.theme);
   if (this.eChartsOptions) {
     this.chart.setOption(this.eChartsOptions);
   }
   this.subscription = this.chartsService.chartChange.subscribe((str) => {
     this.resizeChart(str);
   });
 }

nothing changed

Log after browser refresh or F5

from=home-123

Log after click to Resize btn

from=xxx        chart.service.ts:16
resize from=xxx echarts.directive.ts:37 
resize          echarts.directive.ts:40 

Upvotes: 0

Views: 837

Answers (2)

user2870934
user2870934

Reputation: 709

ok so i add this.resizeChart(str); in ngOnInit method in EChartsDirective, and after each chart init, i have resize effect, so it's works for me

Upvotes: 0

pop
pop

Reputation: 3714

 ngOnInit() {
    this.subscription = this.chartsService.chartChange.subscribe((str) => {
      this.resizeChart(str);
    });
    this.chart = echarts.init(this.element.nativeElement, this.theme);
    if (this.eChartsOptions) {
      this.chart.setOption(this.eChartsOptions);
    }
  }

Here you set this.chart after you subscribe to Subject, while in resizeChart you check if this.chart is defined. It might fail just because it is still null at that point. Try to set this.chart before subscribing to Subject.

Upvotes: 1

Related Questions