2016-11-08 99 views
2

在我最近的Angular 2项目中,我尝试添加一个显示各种错误的组件。我可以在Chrome开发人员控制台中操作并显示错误,但实际上从它们生成输出时我失败了。如何在Angular 2的组件视图中显示错误?

为了达到这个目的,我添加了一个服务类,它扩展了Angular Core的ErrorHandler。它包含一个您可以订阅的主题,以获取新消息。

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

export interface IMiaErrorMessage { 
    exception: string, 
    stackTrace?: any, 
    reason?: string 
} 


@Injectable() 
export class MiaErrorHandlingService extends ErrorHandler { 

    public errors: Subject<IMiaErrorMessage> = new Subject<IMiaErrorMessage>(); 

    handleError(exception: any): void { 
     console.groupCollapsed('Fehler'); 
     console.error(exception); 
     console.groupEnd(); 
     let error: IMiaErrorMessage = { 
      "exception": ""+exception 
     } 
     console.log('error', error); 
     this.errors.next(error); 

    } 
} 

之后我添加了一个实际应该显示错误信息的组件。有一个subscribe -call,它增加了新的错误消息errors-阵列。这两个功能throwErroraddError用于测试。当我使用addError函数简单地添加例外文本时,一切正常,但不是当我实际上使用throwError引发错误时。两者的控制台输出相同。

import { Component, Input } from '@angular/core'; 
import { MiaErrorHandlingService, IMiaErrorMessage } from './../services/mia-error-handling.service'; 
import { Subject } from 'rxjs/Rx'; 

@Component({ 
    selector: 'mia-errors', 
    templateUrl: 'errors.component.html', 
    styleUrls: ['errors.component.scss'], 
    providers: [MiaErrorHandlingService] 

}) 
export class ErrorsComponent { 
    title = 'Es ist ein Fehler aufgetreten'; 

    private errors: Array<IMiaErrorMessage> = []; 

    constructor(private miaErrorHandlingService: MiaErrorHandlingService) { 

     // Observer of the connection status 
     this.miaErrorHandlingService.errors.subscribe(
      value => this.errors.push(value), 
      error => console.info('ERROR', error), 
      () => console.info('COMPLETE') 
     ); 

    } 

    private throwError() { 
     console.log('throwError'); 
     throw Error('Hello again'); 
    } 

    private addError() { 
     console.log('addError'); 
     this.miaErrorHandlingService.handleError('Foo'); 
    } 

} 

控制台输出

errors.component.ts:35 addError 
mia-error-handling.service.ts:18 Fehler 
mia-error-handling.service.ts:19 FooMiaErrorHandlingService.handleError @ mia-error-handling.service.ts:19 ErrorsComponent.addError @ errors.component.ts:36_View_ErrorsComponent0._handle_click_13_0 @ ErrorsComponent.ngfactory.js:164(anonymous function) @ view.js:404(anonymous function) @ dom_renderer.js:249(anonymous function) @ dom_events.js:26ZoneDelegate.invoke @ zone.js:203onInvoke @ ng_zone_impl.js:43ZoneDelegate.invoke @ zone.js:202Zone.runGuarded @ zone.js:110NgZoneImpl.runInnerGuarded @ ng_zone_impl.js:72NgZone.runGuarded @ ng_zone.js:236outsideHandler @ dom_events.js:26ZoneDelegate.invokeTask @ zone.js:236Zone.runTask @ zone.js:136ZoneTask.invoke @ zone.js:304 
mia-error-handling.service.ts:24 error Objectexception: "Foo"__proto__: Object 
errors.component.ts:30 throwError 
mia-error-handling.service.ts:18 Fehler 
mia-error-handling.service.ts:19 ViewWrappedError {_nativeError: Error: Error in ./ErrorsComponent class ErrorsComponent - inline template:10:8 caused by: Hello agai…, originalError: Error: Hello again 
    at ErrorsComponent.throwError (http://localhost:4200/main.bundle.js:67888:15)…, context: DebugContext}MiaErrorHandlingService.handleError @ mia-error-handling.service.ts:19next @ application_ref.js:273schedulerFn @ async.js:82SafeSubscriber.__tryOrUnsub @ Subscriber.js:223SafeSubscriber.next @ Subscriber.js:172Subscriber._next @ Subscriber.js:125Subscriber.next @ Subscriber.js:89Subject.next @ Subject.js:55EventEmitter.emit @ async.js:74onError @ ng_zone.js:120onHandleError @ ng_zone_impl.js:64ZoneDelegate.handleError @ zone.js:207Zone.runGuarded @ zone.js:113NgZoneImpl.runInnerGuarded @ ng_zone_impl.js:72NgZone.runGuarded @ ng_zone.js:236outsideHandler @ dom_events.js:26ZoneDelegate.invokeTask @ zone.js:236Zone.runTask @ zone.js:136ZoneTask.invoke @ zone.js:304 
mia-error-handling.service.ts:24 error Objectexception: "Error: Error in ./ErrorsComponent class ErrorsComponent - inline template:10:8 caused by: Hello again"__proto__: Object__defineGetter__: __defineGetter__()__defineSetter__: __defineSetter__()__lookupGetter__: __lookupGetter__()__lookupSetter__: __lookupSetter__()constructor: Object()hasOwnProperty: hasOwnProperty()isPrototypeOf: isPrototypeOf()propertyIsEnumerable: propertyIsEnumerable()toLocaleString: toLocaleString()toString: toString()valueOf: valueOf()get __proto__: __proto__()set __proto__: __proto__() 

为了完整起见,这里是我的看法

<dl *ngFor="let error of errors"> 
     <dt> 
      <app-icon>warning</app-icon> 
     </dt> 
     <dd>{{error.exception}}</dd> 
    </dl> 
<button (click)="throwError()">Do something wrong!</button> 
<button (click)="addError()">addError</button> 

我很感激每一个输入我可以得到的。

回答

1

科里Rylan在他的博客中大执行本: https://coryrylan.com/blog/angular-2-form-builder-and-validation-management

我使用他的方法在我的应用程序:

以下是错误组件:

import { Component, Input } from '@angular/core'; 
import { FormControl } from '@angular/forms'; 
import { ValidationService } from '../services/validation.service'; 

@Component({ 
    selector: 'kg-errorMessages', 
    template: `<div *ngIf="errorMessage !== null">{{errorMessage}}</div>` 
}) 
export class ErrorMessagesComponent { 
    @Input() control: FormControl; 
    @Input() name: string; 

    constructor() { } 

    get errorMessage() { 
    for (let propertyName in this.control.errors) { 
     if (this.control.errors.hasOwnProperty(propertyName) && this.control.touched) { 
     return ValidationService.getValidatorErrorMessage(propertyName, this.control.errors[propertyName]); 
     } 
    } 

    return null; 
    } 
} 

这里是验证服务:

//Original version created by Cory Rylan: https://coryrylan.com/blog/angular-2-form-builder-and-validation-management 
import { IsValidDate } from '../helpers/date.helper' 


export class ValidationService { 
    static getValidatorErrorMessage(validatorName: string, validatorValue?: any) { 
     let config = { 
      'required': 'Required', 
      'invalidNumberField': 'Only numbers allowed', 
      'invalidDateField': 'Not a valid date', 
      'invalidCreditCard': 'Is invalid credit card number', 
      'invalidEmailAddress': 'Invalid email address', 
      'invalidPassword': 'Invalid password. Password must be at least 6 characters long, and contain a number.', 
      'invalidPasswords': 'Invalid passwords. Passwords must match.', 
      'minlength': `Minimum length ${validatorValue.requiredLength}` 
     }; 

     // console.log(" config = " + JSON.stringify(config)); 
     // console.log(" validator name: " + validatorName); 
     // console.log(" config = req " + JSON.stringify(config["required"])); 
     // console.log(" config = nan " + JSON.stringify(config["invalidNumberField"])); 
     return config[validatorName]; 
    } 

    static numberFieldValidator(control) { 
     // if (control.value.match(/^([0-9]|[0-9][0-9]|[1-9][0-9][0-9])$/)) { 
     //  return null; 
     // } else { 
     //  return { 'invalidNumberField': true }; 
     // } 

     return null; 
    } 

    static dateFieldValidator(control) { 
     var e: boolean; 

     if (IsValidDate(control.value)) { 
      return null; 
     } else { 
      return { 'invalidDateField': true }; 
     } 
    } 

    static creditCardValidator(control) { 
     // Visa, MasterCard, American Express, Diners Club, Discover, JCB 
     if (control.value.match(/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/)) { 
      return null; 
     } else { 
      return { 'invalidCreditCard': true }; 
     } 
    } 

    static emailValidator(control) { 
     // RFC 2822 compliant regex 
     if (control.value.match(/[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/)) { 
      return null; 
     } else { 
      return { 'invalidEmailAddress': true }; 
     } 
    } 

    static passwordValidator(control) { 
     // {6,100}   - Assert password is between 6 and 100 characters 
     // (?=.*[0-9])  - Assert a string has at least one number 
     if (control.value.match(/^(?=.*[0-9])[[email protected]#$%^&*]{6,100}$/)) { 
      return null; 
     } else { 
      return { 'invalidPassword': true }; 
     } 
    } 

    static passwordCompareValidator(fg) { 
     if (fg.value.password === fg.value.confirmPassword) { 
      return null; 
     } else { 
      return { 'invalidPasswords': true }; 
     } 
    } 
}