angular - Angular 5 ngOnInit 多次调用
问题描述
我有为某些图表选择周期的组件。它可以是一些绝对日期或一些快速间隔(过去 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';
}
}
}
我想我需要分享整个组件代码。现在我通过 ngOnChanges 中的@Input intervalData 为我的模板设置变量,但我也尝试订阅它,如您在评论中看到的那样:
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;
});
解决方案
推荐阅读
- visual-studio - Visual Studio:编译依赖项以进行发布时在调试中构建
- php - 在一个小型社交网络网站上向我的项目添加“编辑个人资料”页面需要帮助
- wordpress - 如何在我的 wordpress 主题中限制 wordpress 标题长度?
- php - 将 mysqli_query 从函数添加到数组
- c++ - 如何在 cplex 调用中表示一个变量属于一个集合?
- .net-core - DynamoDB 读取单位计数
- content-management-system - 如何在 sanity.io 中让孩子看起来像亲戚?
- jquery - 如何在居中之前从屏幕外向左滑动文本以附加到现有的居中句子
- google-cloud-pubsub - 关于主题名称的最佳做法是什么
- android - Android okHttp - 如何识别响应是针对哪个请求?