У меня есть компонент для выбора периодов для некоторых графиков. Это могут быть абсолютные даты или короткие интервалы (последние 30 дней и т. Д.). Затем, если прошло менее 14 дней, вы получите данные с интервалом в 1 час по умолчанию. Если его больше 14 дней, вы получаете 1-дневный интервал (и не можете выбрать 1 час). Проблема в том, что когда я выбираю абсолютную дату с менее чем 14 днями - сначала я получаю данные за 1-часовой интервал - это нормально - но потом я хочу изменить данные на 1-дневный интервал - сначала я получаю их, но во-вторых, вызывается ngOnInitснова - и тогда, конечно, интервал по умолчанию установлен. Может кто-нибудь сказать мне, почему ngOnInit вызывается снова?
Я использую этот компонент в трех местах - и я хочу, чтобы они совместно использовали одни и те же данные - поэтому у меня есть и сервис для него, из которого я получаю данные вмои interval-chooser.component
родители и затем я получаю их на @Input()
- в ngOnChanges, только если данные отличаются. Я также попытался не использовать @Input
, но получить данные общего интервала из Observable для самого компонента (но это не решает мою проблему).
Моя проблема в том, что этот метод вызывается из ngOnInit с false
, поэтому мой интервал изменяется. Это нормально в первый раз, но не более ...
private setDefaultInterval(changeIntervalOnly: boolean) {
if (!changeIntervalOnly) {
if (this.disableIntervalSwitch || this.hideIntervalSwitch) {
this.interval = '1d';
} else {
this.interval = '1h';
}
}
}
Я думаю, что мне нужно поделиться целым кодом компонента. Прямо сейчас я устанавливаю переменные для своего шаблона с помощью @Input intervalData в ngOnChanges, но я также пытаюсь подписать его, как вы видите в комментарии:
import {Component, HostListener, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core';
import {IntervalChooserData, IntervalEnum, IntervalService, PeriodsInterval} from '../interval.service';
import {ElementService} from '../element.service';
import {Subscription} from 'rxjs/Subscription';
@Component({
selector: 'app-interval-chooser',
templateUrl: './interval-chooser.component.html',
styleUrls: ['./interval-chooser.component.less']
})
export class IntervalChooserComponent implements OnInit, OnChanges {
@Input() hideIntervalSwitch: boolean;
@Input() intervalData: IntervalChooserData;
mode = 'date';
intervalType: string;
selectedPeriod: PeriodsInterval;
periods: PeriodsInterval[] = [];
pickerMaxDate: Date;
dateFrom: Date;
dateTo: Date;
lastDateFrom: Date;
lastDateTo: Date;
setMessage: boolean;
timeZone: string;
intervals = ['1d', '1h'];
interval: string;
disableIntervalSwitch = false;
radioButtonClass = 'grouped fields';
subscription: Subscription;
dataSet = false;
@HostListener('window:resize') onResize() {
this.checkResize();
}
constructor(private intervalService: IntervalService, private elementService: ElementService) {
this.periods = this.intervalService.periods;
}
ngOnInit() {
console.log('NG OnInit CALLED !!!!!!!!!!!!!!!!!')
this.pickerMaxDate = new Date();
if (typeof this.timeZone === 'undefined') {
console.log('callled once with true', this.timeZone);
this.setVariablesFromSharedIntervalData(true);
}
// this.subscription = this.intervalService.getSharedIntervalDataObservable().subscribe(intervalData => {
// if (this.intervalService.isDifferentIntervalData(intervalData, this.intervalData)) {
// this.intervalData = intervalData;
// console.log('set variables', this.intervalData);
// this.setVariablesFromSharedIntervalData(false);
// // this.cdRef.detectChanges();
// }
// });
this.checkResize();
}
ngOnChanges(changes: SimpleChanges): void {
if (!changes.intervalData.previousValue || changes.intervalData &&
this.intervalService.isDifferentIntervalData(changes.intervalData.currentValue, changes.intervalData.previousValue)) {
console.log('set variables', this.intervalData);
this.setVariablesFromSharedIntervalData(false);
}
}
setVariablesFromSharedIntervalData(changeInterval: boolean) {
console.log('setVariablesFromSharedIntervalData with', changeInterval, this.intervalData.interval);
this.timeZone = this.intervalData.timeZone;
this.selectedPeriod = this.intervalService.getPeriodInterfaceByPeriodTypeId(this.intervalData.period);
if (this.intervalData.intervalEnum === IntervalEnum.Date
&& this.intervalData.period['dateFrom'] && this.intervalData.period['dateTo']) {
this.intervalType = '0';
this.dateFrom = this.intervalData.period['dateFrom'];
this.dateTo = this.intervalData.period['dateTo'];
if (changeInterval) {
const isDayInterval = this.intervalService.isDatesMoreThanXDays({dateFrom: this.dateFrom, dateTo: this.dateTo}, 14);
this.interval = isDayInterval ? '1d' : '1h';
console.log('CHANGE INTERVAL', this.interval);
} else {
this.interval = this.intervalData.interval;
}
} else if (this.intervalData.intervalEnum === IntervalEnum.Period) {
this.intervalType = '1';
this.interval = changeInterval ? this.selectedPeriod.default_interval : this.intervalData.interval;
}
this.dataSet = true;
}
onIntervalTypeChange() {
console.log('change interval type');
this.doChange(false);
}
onChangePeriod() {
console.log('change period');
this.doChange(false);
}
changeTimeZone(timeZone: string) {
console.log('change timezone');
this.timeZone = timeZone;
this.doChange(false);
}
onChangeDate() {
console.log('change date');
if (this.isDatesDifferent()) {
console.log('date is different');
this.doChange(false);
}
}
onChangeInterval() {
this.doChange(true);
}
isDatesDifferent(): boolean {
console.log('date from', this.dateFrom, this.lastDateFrom, 'date to', this.dateTo, this.lastDateTo);
if ((!this.lastDateFrom || !this.lastDateTo || !this.dateFrom || !this.dateTo)
|| (this.dateFrom.getTime() !== this.lastDateFrom.getTime() || this.dateTo.getTime() !== this.lastDateTo.getTime())) {
if (this.dateFrom && this.dateTo) {
this.lastDateFrom = new Date(this.dateFrom.getTime());
this.lastDateTo = new Date(this.dateTo.getTime());
console.log('SET date from', this.dateFrom, this.lastDateFrom, 'date to', this.dateTo, this.lastDateTo);
}
return true;
} else {
return false;
}
}
isDatesValid(): boolean {
if (this.dateFrom > this.dateTo) {
this.setMessage = true;
return false;
} else {
this.setMessage = false;
return !!(this.dateFrom && this.dateTo);
}
}
doChange(changeIntervalOnly: boolean) {
console.log('DO CHANGE', changeIntervalOnly);
if (this.intervalType === '0') {
if (this.isDatesValid()) {
this.disableIntervalSwitch = this.intervalService.isDatesMoreThanXDays({dateFrom: this.dateFrom, dateTo: this.dateTo}, 14);
this.setDefaultInterval(changeIntervalOnly);
const date = {'dateFrom': this.dateFrom, 'dateTo': this.dateTo};
this.intervalService.setSharedIntervalData({intervalEnum: IntervalEnum.Date, period: date,
timeZone: this.timeZone, interval: this.interval});
}
} else if (this.intervalType === '1') {
this.disableIntervalSwitch = this.intervalService.isPeriodMoreThan14Days(this.selectedPeriod.type);
this.setDefaultInterval(changeIntervalOnly);
this.intervalService.setSharedIntervalData({intervalEnum: IntervalEnum.Period, period: this.selectedPeriod.type_id,
timeZone: this.timeZone, interval: this.interval});
}
}
private setDefaultInterval(changeIntervalOnly: boolean) {
if (!changeIntervalOnly) {
console.log('SET DEFAULT interval!!!')
if (this.disableIntervalSwitch || this.hideIntervalSwitch) {
this.interval = '1d';
} else {
this.interval = '1h';
}
}
}
// format from: Wed Jun 27 2018 00:00:00 GMT+0200 (CEST)
formatDate(date: Date): string {
return date.toLocaleDateString('en-GB');
}
checkResize() {
this.radioButtonClass = this.elementService.isMobileSize() ? 'inline fields' : 'grouped fields';
}
// ngOnDestroy(): void {
// if (this.subscription) {
// this.subscription.unsubscribe();
// }
// }
}
И шаблон:
<div *ngIf="setMessage" class="ui attached warning message">
<i class="close icon" (click)="setMessage=false"></i>
<div class="header">Date Error</div>
<p>Date from cannot be greater than date to</p>
</div>
<div id="chooser" class="ui form attached" *ngIf="selectedPeriod">
<div id="interval_type_chooser" [ngClass]="radioButtonClass">
<div class="field">
<sui-radio-button value="0" [(ngModel)]="intervalType" (ngModelChange)=onIntervalTypeChange()>absolute</sui-radio-button>
</div>
<div class="field">
<sui-radio-button value="1" [(ngModel)]="intervalType" (ngModelChange)=onIntervalTypeChange()>quick</sui-radio-button>
</div>
</div>
<span id='interval_type' [ngSwitch]="intervalType">
<span *ngSwitchCase="0">
<button class="ui button"
suiDatepicker
[pickerMode]="mode"
[(ngModel)]="dateFrom"
[pickerMaxDate]="pickerMaxDate"
(ngModelChange)=onChangeDate()>From</button>
<button class="ui button"
suiDatepicker
[pickerMode]="mode"
[(ngModel)]="dateTo"
[pickerMaxDate]="pickerMaxDate"
(ngModelChange)=onChangeDate()>To</button>
<span *ngIf="dateFrom" class="date_desc">From: {{formatDate(dateFrom)}} </span>
<span *ngIf="dateTo" class="date_desc">To: {{formatDate(dateTo)}} </span>
</span>
<span *ngSwitchCase="1" class="field">
<sui-select class="selection"
id="periodSelector"
[(ngModel)]="selectedPeriod"
(ngModelChange)=onChangePeriod()
[options]="periods"
labelField="name"
placeholder="select period"
#selectPeriod>
<sui-select-option *ngFor="let option of selectPeriod.filteredOptions"
[value]="option">
</sui-select-option>
</sui-select>
</span>
</span>
<span id="time_zone">
<app-timezone (changeTimezone)="changeTimeZone($event)"></app-timezone>
</span>
<span id="interval" *ngIf="intervals && !hideIntervalSwitch">
<sui-select [(ngModel)]="interval"
[options]="intervals"
(ngModelChange)=onChangeInterval()
[isDisabled]="disableIntervalSwitch"
#selectInterval>
<sui-select-option *ngFor="let option of selectInterval.filteredOptions"
[value]="option">
</sui-select-option>
</sui-select>
</span>
</div>
Здесьэто шаблон, в котором я использую свой компонент:
<app-interval-chooser *ngIf="canSeeChart" [intervalData]="intervalData" [hideIntervalSwitch]="hideIntervalSwitch"></app-interval-chooser>
<div *ngIf="websites" [class.noCaption]="noCaption" id="chart_segment">
<div *ngIf="websites.length<=10||noCaption; else TooManySelected">
<p *ngIf="!noCaption">Showing data for: <app-more-websites [websites]="websites"></app-more-websites></p>
<div [ngClass]="showDimmer ? 'ui active dimmer' : 'inactive dimmer'">
<div class="ui medium text loader">Loading</div>
</div>
<app-plotly-chart *ngIf="showPlotly && plotlyData" [data]="plotlyData" [chartType]="chartType"></app-plotly-chart>
</div>
<ng-template #TooManySelected>
<app-info-segment [text]="'Only data for 10 or less selected websites can be shown for performance reasons. Try filtering the websites in the select boxes above.'"></app-info-segment>
</ng-template>
<div *ngIf="setNoDataMessage">
<app-info-segment [text]="'No data to show.'"></app-info-segment>
</div>
</div>
со следующим кодом компонента:
beforePost() {
this.postData();
}
, который расширяет этот мета-компонент следующим ngOninit:
this.canSeeChart = this.websites.length <= 10 || this.noCaption;
this.intervalDataSubscription = this.intervalService.getSharedIntervalDataObservable().subscribe((intervalData => {
this.intervalData = intervalData;
this.beforePost();
}));
this.chart = this.chartService.getChartTypeInterfaceByEnum(this.chartType);
this.fragmentSubscription = this.route.fragment.subscribe(fragment => {
this.showPlotly = this.chart.hash === fragment;
});