我严格遵循如何实施推送和敬酒通知服务的教程。我遇到了这个错误,我似乎没有为什么错误不断出现。下面是角度2
中的错误和简单通知堆栈的代码错误
` Uncaught (in promise): Error: Error in :0:0 caused by: this.item is undefined
BaseError@http://localhost:4200/vendor.bundle.js:31569:9 [angular]
WrappedError@http://localhost:4200/vendor.bundle.js:31634:9 [angular]
ViewWrappedError@http://localhost:4200/vendor.bundle.js:62968:9 [angular]
DebugAppView.prototype._rethrowWithContext@http://localhost:4200/vendor.bundle.js:87491:23 [angular]
DebugAppView.prototype.detectChanges@http://localhost:4200/vendor.bundle.js:87464:13 [angular]
ViewRef_.prototype.detectChanges@http://localhost:4200/vendor.bundle.js:63895:9 [angular]
RouterOutlet.prototype.activate@http://localhost:4200/vendor.bundle.js:69403:9 [angular]
ActivateRoutes.prototype.placeComponentIntoOutlet@http://localhost:4200/vendor.bundle.js:26433:9 [angular]
ActivateRoutes.prototype.activateRoutes@http://localhost:4200/vendor.bundle.js:26400:21 [angular]
ActivateRoutes.prototype.activateChildRoutes/<@http://localhost:4200/vendor.bundle.js:26336:52 [angular]
ActivateRoutes.[…]`
Notification.Component.ts
import {Component, OnInit, OnDestroy, Input, ViewEncapsulation, NgZone,
trigger, state, style, transition, animate
} from '@angular/core';
import {DomSanitizer, SafeHtml} from '@angular/platform-browser';
import {Notification} from '../interfaces/notification.type';
import {NotificationsService} from '../services/notifications.service';
@Component({
selector: 'simple-notification',
encapsulation: ViewEncapsulation.None,
animations: [
trigger('enterLeave', [
// Enter from right
state('fromRight', style({opacity: 1, transform: 'translateX(0)'})),
transition('* => fromRight', [
style({opacity: 0, transform: 'translateX(5%)'}),
animate('400ms ease-in-out')
]),
state('fromRightOut', style({opacity: 0, transform: 'translateX(-5%)'})),
transition('fromRight => fromRightOut', [
style({opacity: 1, transform: 'translateX(0)'}),
animate('300ms ease-in-out')
]),
// Enter from left
state('fromLeft', style({opacity: 1, transform: 'translateX(0)'})),
transition('* => fromLeft', [
style({opacity: 0, transform: 'translateX(-5%)'}),
animate('400ms ease-in-out')
]),
state('fromLeftOut', style({opacity: 0, transform: 'translateX(5%)'})),
transition('fromLeft => fromLeftOut', [
style({opacity: 1, transform: 'translateX(0)'}),
animate('300ms ease-in-out')
]),
// Rotate
state('scale', style({opacity: 1, transform: 'scale(1)'})),
transition('* => scale', [
style({opacity: 0, transform: 'scale(0)'}),
animate('400ms ease-in-out')
]),
state('scaleOut', style({opacity: 0, transform: 'scale(0)'})),
transition('scale => scaleOut', [
style({opacity: 1, transform: 'scale(1)'}),
animate('400ms ease-in-out')
]),
// Scale
state('rotate', style({opacity: 1, transform: 'rotate(0deg)'})),
transition('* => rotate', [
style({opacity: 0, transform: 'rotate(5deg)'}),
animate('400ms ease-in-out')
]),
state('rotateOut', style({opacity: 0, transform: 'rotate(-5deg)'})),
transition('rotate => rotateOut', [
style({opacity: 1, transform: 'rotate(0deg)'}),
animate('400ms ease-in-out')
])
])
],
template: `
<div class="simple-notification"
[@enterLeave]="item.state"
(click)="onClick($event)"
[class]="theClass"
[ngClass]="{
'alert': item.type === 'alert',
'error': item.type === 'error',
'success': item.type === 'success',
'info': item.type === 'info',
'bare': item.type === 'bare',
'rtl-mode': rtl
}"
(mouseenter)="onEnter()"
(mouseleave)="onLeave()">
<div *ngIf="!item.html">
<div class="sn-title">{{item.title}}</div>
<div class="sn-content">{{item.content | max:maxLength}}</div>
<div class="icon" *ngIf="item.icon !== 'bare'" [innerHTML]="safeSvg"></div>
</div>
<div *ngIf="item.html" [innerHTML]="item.html"></div>
<div class="sn-progress-loader" *ngIf="showProgressBar">
<span [ngStyle]="{'width': progressWidth + '%'}"></span>
</div>
</div>
`,
providers: [NotificationsService]
})
export class NotificationComponent implements OnInit, OnDestroy {
@Input() public timeOut: number;
@Input() public showProgressBar: boolean;
@Input() public pauseOnHover: boolean;
@Input() public clickToClose: boolean;
@Input() public maxLength: number;
@Input() public theClass: string;
@Input() public rtl: boolean;
@Input() public animate: string;
@Input() public position: number;
@Input() public item: Notification;
// Progress bar variables
public progressWidth = 0;
private stopTime = false;
private timer: any;
private steps: number;
private speed: number;
private count = 0;
private start: any;
private diff: any;
private icon: string;
private safeSvg: SafeHtml;
constructor(
private notificationService: NotificationsService,
private domSanitizer: DomSanitizer,
private zone: NgZone
) {}
ngOnInit(): void {
if (this.animate) {
this.item.state = this.animate;
}
if (this.item.override) {
this.attachOverrides();
}
if (this.timeOut !== 0) {
this.startTimeOut();
}
this.safeSvg = this.domSanitizer.bypassSecurityTrustHtml(this.icon || this.item.icon);
}
startTimeOut(): void {
this.steps = this.timeOut / 10;
this.speed = this.timeOut / this.steps;
this.start = new Date().getTime();
this.zone.runOutsideAngular(() => this.timer = setTimeout(this.instance, this.speed));
}
onEnter(): void {
if (this.pauseOnHover) {
this.stopTime = true;
}
}
onLeave(): void {
if (this.pauseOnHover) {
this.stopTime = false;
setTimeout(this.instance, (this.speed - this.diff));
}
}
setPosition(): number {
return this.position !== 0 ? this.position * 90 : 0;
}
onClick($e: MouseEvent): void {
this.item.click!.emit($e);
if (this.clickToClose) {
this.remove();
}
}
// Attach all the overrides
attachOverrides(): void {
Object.keys(this.item.override).forEach(a => {
if (this.hasOwnProperty(a)) {
(<any>this)[a] = this.item.override[a];
}
});
}
ngOnDestroy(): void {
clearTimeout(this.timer);
}
private instance = () => {
this.zone.runOutsideAngular(() => {
this.zone.run(() => this.diff = (new Date().getTime() - this.start) - (this.count * this.speed));
if (this.count++ === this.steps) this.zone.run(() => this.remove());
else if (!this.stopTime) {
if (this.showProgressBar) this.zone.run(() => this.progressWidth += 100 / this.steps);
this.timer = setTimeout(this.instance, (this.speed - this.diff));
}
})
};
private remove() {
if (this.animate) {
this.item.state = this.animate + 'Out';
this.zone.runOutsideAngular(() => {
setTimeout(() => {
this.zone.run(() => this.notificationService.set(this.item, false))
}, 310);
})
} else {
this.notificationService.set(this.item, false);
}
}
}
简单nofitication
@Component({
selector: 'simple-notifications',
encapsulation: ViewEncapsulation.None,
template: `
<div class="simple-notification-wrapper" [ngClass]="position">
<simple-notification
*ngFor="let a of notifications; let i = index"
[item]="a"
[timeOut]="timeOut"
[clickToClose]="clickToClose"
[maxLength]="maxLength"
[showProgressBar]="showProgressBar"
[pauseOnHover]="pauseOnHover"
[theClass]="theClass"
[rtl]="rtl"
[animate]="animate"
[position]="i"
>
</simple-notification>
</div>
`,
`],
providers: [NotificationsService]
})
export class SimpleNotificationsComponent implements OnInit, OnDestroy {
@Input() set options(opt: Options) {
this.attachChanges(opt);
}
@Output() onCreate = new EventEmitter();
@Output() onDestroy = new EventEmitter();
public notifications: Notification[] = [];
public position: ['top' | 'bottom', 'right' | 'left'] = ['bottom', 'right'];
private lastNotificationCreated: Notification;
private listener: Subscription;
// Received values
private lastOnBottom = true;
private maxStack = 8;
private preventLastDuplicates: any = false;
private preventDuplicates = false;
// Sent values
public timeOut = 0;
public maxLength = 0;
public clickToClose = true;
public showProgressBar = true;
public pauseOnHover = true;
public theClass = '';
public rtl = false;
public animate: 'fromRight' | 'fromLeft' | 'rotate' | 'scale' = 'fromRight';
constructor(private _service: NotificationsService) {}
ngOnInit(): void {
// Listen for changes in the service
this.listener = this._service.getChangeEmitter()
.subscribe(item => {
switch (item.command) {
case 'cleanAll':
this.notifications = [];
break;
case 'clean':
this.cleanSingle(item.id!);
break;
case 'set':
if (item.add) this.add(item.notification!);
else this.defaultBehavior(item);
break;
default:
this.defaultBehavior(item);
break;
}
});
}
// Default behavior on event
defaultBehavior(value: any): void {
this.notifications.splice(this.notifications.indexOf(value.notification), 1);
this.onDestroy.emit(this.buildEmit(value.notification, false));
}
// Add the new notification to the notification array
add(item: Notification): void {
item.createdOn = new Date();
let toBlock: boolean = this.preventLastDuplicates || this.preventDuplicates ? this.block(item) : false;
// Save this as the last created notification
this.lastNotificationCreated = item;
if (!toBlock) {
// Check if the notification should be added at the start or the end of the array
if (this.lastOnBottom) {
if (this.notifications.length >= this.maxStack) this.notifications.splice(0, 1);
this.notifications.push(item);
} else {
if (this.notifications.length >= this.maxStack) this.notifications.splice(this.notifications.length - 1, 1);
this.notifications.splice(0, 0, item);
}
this.onCreate.emit(this.buildEmit(item, true));
}
}
// Check if notifications should be prevented
block(item: Notification): boolean {
let toCheck = item.html ? this.checkHtml : this.checkStandard;
if (this.preventDuplicates && this.notifications.length > 0) {
for (let i = 0; i < this.notifications.length; i++) {
if (toCheck(this.notifications[i], item)) {
return true;
}
}
}
if (this.preventLastDuplicates) {
let comp: Notification;
if (this.preventLastDuplicates === 'visible' && this.notifications.length > 0) {
if (this.lastOnBottom) {
comp = this.notifications[this.notifications.length - 1];
} else {
comp = this.notifications[0];
}
} else if (this.preventLastDuplicates === 'all' && this.lastNotificationCreated) {
comp = this.lastNotificationCreated;
} else {
return false;
}
return toCheck(comp, item);
}
return false;
}
checkStandard(checker: Notification, item: Notification): boolean {
return checker.type === item.type && checker.title === item.title && checker.content === item.content;
}
checkHtml(checker: Notification, item: Notification): boolean {
return checker.html ? checker.type === item.type && checker.title === item.title && checker.content === item.content && checker.html === item.html : false;
}
// Attach all the changes received in the options object
attachChanges(options: any): void {
Object.keys(options).forEach(a => {
if (this.hasOwnProperty(a)) {
(<any>this)[a] = options[a];
}
});
}
buildEmit(notification: Notification, to: boolean) {
let toEmit: Notification = {
createdOn: notification.createdOn,
type: notification.type,
icon: notification.icon,
id: notification.id
};
if (notification.html) {
toEmit.html = notification.html;
} else {
toEmit.title = notification.title;
toEmit.content = notification.content;
}
if (!to) {
toEmit.destroyedOn = new Date();
}
return toEmit;
}
cleanSingle(id: string): void {
let indexOfDelete = 0;
let doDelete = false;
this.notifications.forEach((notification, idx) => {
if (notification.id === id) {
indexOfDelete = idx;
doDelete = true;
}
});
if (doDelete) {
this.notifications.splice(indexOfDelete, 1);
}
}
ngOnDestroy(): void {
if (this.listener) {
this.listener.unsubscribe();
}
}