Angular2:在数据更改时查看更新,但不是使用 ngif
Angular2: View updates when data changes, but not with ngif
我正在使用 Angular2 构建一个简单的日历。使用此代码一切正常(并且按预期):
app.component.ts
import { Component, OnInit } from '@angular/core';
import { Calendar } from '@npm/calendar';
export class CalendarWeek {
days: Array<any>;
data?: string; // reserved for further use
}
@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html',
styleUrls: ['app/app.component.css']
})
export class AppComponent implements OnInit {
title = 'Calendar';
weeks:CalendarWeek[];
months:string[] = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
weekDays:string[] = [
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday'
];
monthString:string;
month:number;
year:number;
prevMonth:Boolean;
nextMonth:Boolean;
thisMonth:Boolean;
showMonth:Boolean;
getWeeks(): void {
let cal = new Calendar(1); // start with Monday
let mdc = cal.monthDates(this.year, this.month);
this.weeks = [];
this.monthString = this.months[this.month];
this.prevMonth = this.nextMonth = this.thisMonth = false;
for (let i=0; i<mdc.length; i++) {
this.weeks.push({ days: mdc[i] });
}
}
getThisMonth(): void {
this.month = new Date().getMonth();
this.year = new Date().getFullYear();
this.getWeeks();
}
getPreviousMonth(): void {
this.getMonth(-1);
}
getNextMonth(): void {
this.getMonth(+1);
}
getMonth(direction): void {
if ( this.month == 11 && direction > 0 ) {
this.year++;
this.month = 0;
} else if (this.month == 0 && direction < 0) {
this.year--;
this.month = 11;
} else {
this.month = this.month + direction;
}
this.getWeeks();
}
ngOnInit(): void {
this.getThisMonth();
}
}
app.component.html
<h1>{{title}}</h1>
<div class="period">
<a (click)="getPreviousMonth()" class="monthPager"><</a>
<a (click)="getThisMonth()" class="monthPager">now</a>
<a (click)="getNextMonth()" class="monthPager">></a>
<span class="now">{{monthString}}, {{year}}</span>
</div>
<div class="week">
<div *ngFor="let day of weekDays" class="week-day">
<span>{{day}}</span>
</div>
</div>
<div *ngFor="let week of weeks" class="week">
<div *ngFor="let day of week.days" class="day">
<span class="day-date">{{day | date:'d'}}</span>
</div>
</div>
正如我所说,一切正常,我可以来回翻阅几个月。 npm/calendar
模块给出了一个简单的日期对象数组,用于一个月中的每一周,从周一到周日。问题是第一周和最后一周也可以包括上个月或下个月的日期,所以我想检查这些情况并一次显示月份的名称。所以我会 October 31, November 1, 2, 3, [...], 30, December 1, 2, 3, 4
.
为了进行这项检查,我在 app.component.html 中添加了一行,所以它看起来像这样:
<div *ngFor="let week of weeks" class="week">
<div *ngFor="let day of week.days" class="day">
<span *ngIf="checkMonth(day)" class="day-month">{{day | date:'MMM'}}</span>
<span class="day-date">{{day | date:'d'}}</span>
</div>
</div>
并将此方法添加到 app.component.ts:
checkMonth(day): Boolean {
let mo = day.getMonth();
this.showMonth = false;
if ( mo < this.month && !this.prevMonth) {
this.prevMonth = true;
this.showMonth = true;
}
if ( mo > this.month && !this.nextMonth) {
this.nextMonth = true;
this.showMonth = true;
}
if ( mo == this.month && !this.thisMonth) {
this.thisMonth = true;
this.showMonth = true;
}
return this.showMonth;
}
现在我遇到了一次错误
Subscriber.ts:238 EXCEPTION: Error in app/app.component.html:17:14 caused by: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'.
而且我不能再翻阅几个月了。仍在评估点击次数并生成新数组,但视图不会更新。哦,奇怪的是,checkMonth 似乎也按预期评估日期,它仍然不显示月份的名称 - 我只是得到纯日期,没有月份名称。
什么可能导致这里的问题?
谢谢。
UPD:这是 Plunker:https://plnkr.co/edit/HrIlOG9fsGhIS3w12bV0?p=preview
将以下两行添加到您的 main.ts
:
import {enableProdMode} from '@angular/core';
enableProdMode();
如果 Angular2 不在生产模式下,它会检查每个变更检测两次..
如果两次检查不同则抛出此错误..
我已经对你的 plunkr 进行了更新:https://plnkr.co/edit/TCVkfJUDvLH68ybFJXqA?p=preview
问题
您收到消息的原因是因为
- 您检查 属性 的值(如
this.thisMonth
)
- 你更新 属性 的值,从而改变它。
- Angular 在开发模式下会 运行 每次检查两次,以帮助您过滤掉可能的错误。 (这在你的情况下失败了。由于你在 class 上更新了 属性,如果你 运行 两次
checkMonth()
函数,它将产生两个不同的结果,一个是true
,第二个将是 false
,因为您已经更新了 运行 检查的值。
为了避免后者,你应该更多地分离逻辑(虽然我认为你写的代码很有意义,并且应该可以用于生产,但那不是 Angular2 看起来的样子它)。
因此,您可以编写一个函数,而不是检查和设置属性 "back and forth",returns 相同的值,仅基于输入参数。
可能的解决方案
getShowableDays(weeks: Array): Array {
let showableDays: Array<any> = [];
let shownMonths: Array<number> = [];
weeks.forEach((week) => {
for(let day of week.days) {
if(shownMonths.indexOf(day.getMonth()) === -1) {
showableDays.push(day);
shownMonths.push(day.getMonth());
}
}
});
return showableDays;
}
checkMonth(day): Boolean {
let showableDays: Array<any> = this.getShowableDays(this.weeks);
for(let showableDay of showableDays) {
if(showableDay === day)
return true;
}
return false;
}
这将花费您当前的几周时间,并检查每个月的第一个事件是什么。基于此,无论您 运行 这段代码多少次,结果总是相同的,因为它将 运行 独立于应用程序的其余部分或应用程序的状态。
我正在使用 Angular2 构建一个简单的日历。使用此代码一切正常(并且按预期):
app.component.ts
import { Component, OnInit } from '@angular/core';
import { Calendar } from '@npm/calendar';
export class CalendarWeek {
days: Array<any>;
data?: string; // reserved for further use
}
@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html',
styleUrls: ['app/app.component.css']
})
export class AppComponent implements OnInit {
title = 'Calendar';
weeks:CalendarWeek[];
months:string[] = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
weekDays:string[] = [
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday'
];
monthString:string;
month:number;
year:number;
prevMonth:Boolean;
nextMonth:Boolean;
thisMonth:Boolean;
showMonth:Boolean;
getWeeks(): void {
let cal = new Calendar(1); // start with Monday
let mdc = cal.monthDates(this.year, this.month);
this.weeks = [];
this.monthString = this.months[this.month];
this.prevMonth = this.nextMonth = this.thisMonth = false;
for (let i=0; i<mdc.length; i++) {
this.weeks.push({ days: mdc[i] });
}
}
getThisMonth(): void {
this.month = new Date().getMonth();
this.year = new Date().getFullYear();
this.getWeeks();
}
getPreviousMonth(): void {
this.getMonth(-1);
}
getNextMonth(): void {
this.getMonth(+1);
}
getMonth(direction): void {
if ( this.month == 11 && direction > 0 ) {
this.year++;
this.month = 0;
} else if (this.month == 0 && direction < 0) {
this.year--;
this.month = 11;
} else {
this.month = this.month + direction;
}
this.getWeeks();
}
ngOnInit(): void {
this.getThisMonth();
}
}
app.component.html
<h1>{{title}}</h1>
<div class="period">
<a (click)="getPreviousMonth()" class="monthPager"><</a>
<a (click)="getThisMonth()" class="monthPager">now</a>
<a (click)="getNextMonth()" class="monthPager">></a>
<span class="now">{{monthString}}, {{year}}</span>
</div>
<div class="week">
<div *ngFor="let day of weekDays" class="week-day">
<span>{{day}}</span>
</div>
</div>
<div *ngFor="let week of weeks" class="week">
<div *ngFor="let day of week.days" class="day">
<span class="day-date">{{day | date:'d'}}</span>
</div>
</div>
正如我所说,一切正常,我可以来回翻阅几个月。 npm/calendar
模块给出了一个简单的日期对象数组,用于一个月中的每一周,从周一到周日。问题是第一周和最后一周也可以包括上个月或下个月的日期,所以我想检查这些情况并一次显示月份的名称。所以我会 October 31, November 1, 2, 3, [...], 30, December 1, 2, 3, 4
.
为了进行这项检查,我在 app.component.html 中添加了一行,所以它看起来像这样:
<div *ngFor="let week of weeks" class="week">
<div *ngFor="let day of week.days" class="day">
<span *ngIf="checkMonth(day)" class="day-month">{{day | date:'MMM'}}</span>
<span class="day-date">{{day | date:'d'}}</span>
</div>
</div>
并将此方法添加到 app.component.ts:
checkMonth(day): Boolean {
let mo = day.getMonth();
this.showMonth = false;
if ( mo < this.month && !this.prevMonth) {
this.prevMonth = true;
this.showMonth = true;
}
if ( mo > this.month && !this.nextMonth) {
this.nextMonth = true;
this.showMonth = true;
}
if ( mo == this.month && !this.thisMonth) {
this.thisMonth = true;
this.showMonth = true;
}
return this.showMonth;
}
现在我遇到了一次错误
Subscriber.ts:238 EXCEPTION: Error in app/app.component.html:17:14 caused by: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'.
而且我不能再翻阅几个月了。仍在评估点击次数并生成新数组,但视图不会更新。哦,奇怪的是,checkMonth 似乎也按预期评估日期,它仍然不显示月份的名称 - 我只是得到纯日期,没有月份名称。
什么可能导致这里的问题? 谢谢。
UPD:这是 Plunker:https://plnkr.co/edit/HrIlOG9fsGhIS3w12bV0?p=preview
将以下两行添加到您的 main.ts
:
import {enableProdMode} from '@angular/core';
enableProdMode();
如果 Angular2 不在生产模式下,它会检查每个变更检测两次.. 如果两次检查不同则抛出此错误..
我已经对你的 plunkr 进行了更新:https://plnkr.co/edit/TCVkfJUDvLH68ybFJXqA?p=preview
问题
您收到消息的原因是因为
- 您检查 属性 的值(如
this.thisMonth
) - 你更新 属性 的值,从而改变它。
- Angular 在开发模式下会 运行 每次检查两次,以帮助您过滤掉可能的错误。 (这在你的情况下失败了。由于你在 class 上更新了 属性,如果你 运行 两次
checkMonth()
函数,它将产生两个不同的结果,一个是true
,第二个将是false
,因为您已经更新了 运行 检查的值。
为了避免后者,你应该更多地分离逻辑(虽然我认为你写的代码很有意义,并且应该可以用于生产,但那不是 Angular2 看起来的样子它)。
因此,您可以编写一个函数,而不是检查和设置属性 "back and forth",returns 相同的值,仅基于输入参数。
可能的解决方案
getShowableDays(weeks: Array): Array {
let showableDays: Array<any> = [];
let shownMonths: Array<number> = [];
weeks.forEach((week) => {
for(let day of week.days) {
if(shownMonths.indexOf(day.getMonth()) === -1) {
showableDays.push(day);
shownMonths.push(day.getMonth());
}
}
});
return showableDays;
}
checkMonth(day): Boolean {
let showableDays: Array<any> = this.getShowableDays(this.weeks);
for(let showableDay of showableDays) {
if(showableDay === day)
return true;
}
return false;
}
这将花费您当前的几周时间,并检查每个月的第一个事件是什么。基于此,无论您 运行 这段代码多少次,结果总是相同的,因为它将 运行 独立于应用程序的其余部分或应用程序的状态。