如何处理模板中的异步布尔值

时间:2019-10-17 15:12:46

标签: angular primeng

我正在尝试在我的angular应用程序中实现一个简单的异常处理程序,但是在最后一步遇到了问题,我想在该步骤中通过primeng对话框向用户显示消息。 为了测试目的,我有一个控制器端点,在这里我只是抛出一个异常。这会遇到我的http拦截器,然后进入异常处理程序,在这里我调用通知服务的showError()方法,该方法的Subjects发出displayModal true和消息字符串。在错误模式组件中,我订阅了这些主题。在控制台从应用程序中注销后,似乎在我将true分配给对话框组件showDialog变量后,不运行可见性检查,因此仅在页面上发生其他事件后,对话框窗口才可见。这是代码。

拦截器:

@Injectable()
export class ServerErrorInterceptor implements HttpInterceptor {

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    return next.handle(request).pipe(
        // retry the HTTP call once
        retry(1),
      catchError((error: HttpErrorResponse) => {
        //check statuses if you want
        if (error.status === 418) {
            // do whatever you want
            } else {
              return throwError(error);
            }
        })
      );    
    }
}

ErrorHandler:

@Injectable()
export class GlobalErrorHandler implements ErrorHandler {

    constructor(private injector: Injector) { }

    handleError(error: Error | HttpErrorResponse) {
        const errorService = this.injector.get(ErrorService);
        const logger = this.injector.get(LoggingService);
        const notifier = this.injector.get(NotificationService);

        let message;
        let stackTrace;

        if (error instanceof HttpErrorResponse) {
            message = errorService.getServerMessage(error);
            console.log(error.error.message);
            stackTrace = errorService.getServerStack(error);
            notifier.showError(message);
        } else {
            message = errorService.getClientMessage(error);
            stackTrace = errorService.getClientStack(error);
            notifier.showError(message);
        }

        logger.logError(message, stackTrace);

        console.error(error);
    }
}

NotificationService:

@Injectable({
    providedIn: 'root'
})
export class NotificationService {

    // TODO: implement a proper NotificationService!

    //displayModal: Subject<boolean> = new Subject();
    displayModal: Subject<boolean> = new Subject();
    message: Subject<string> = new Subject();

    constructor() { }

    showSuccess(message: string): void {
        alert(message);
    }

    public showError(message: string): void {
        this.message.next(message);
        this.displayModal.next(true);
    }
}

ErrorModalComponent:

@Component({
  selector: 'app-error-modal',
  templateUrl: './error-modal.component.html',
  styleUrls: ['./error-modal.component.css']
})
export class ErrorModalComponent implements OnInit {

    constructor(private notificationService: NotificationService) {}

    displayModalSubcription: Subscription;
    messageSub: Subscription;
    displayModal: boolean = false;
    message: string;

    ngOnInit() {
    this.messageSub = this.notificationService.message.subscribe(message => {
      this.message = message;
    });

    this.displayModalSubcription = this.notificationService.displayModal
        .subscribe(displayModal => {
          this.displayModal = displayModal;
    });
  }
}

对话框模板:

<p-dialog [contentStyle]="{'overflow':'visible'}" modal="true" header="Error occured" [(visible)]="displayModal" >
    {{message}}
</p-dialog>

如果我省去了http调用,而只是将notificationService.showError()绑定到按钮上,它就可以工作,这就是为什么我认为它必须与http调用的异步行为有关,但是我不确定,因为事实上我已经出错了,这意味着我已经响应了http调用...我对angular非常陌生,所以仍然有一些模糊的字段。

非常感谢您的帮助!

2 个答案:

答案 0 :(得分:0)

您的通知服务已标记为private,并且您在视图中引用了该服务。那应该给你一个错误。

ErrorModalComponent必须一直处于当前视图中(无论您所处的路线如何)。

尝试一下:

NotificationService:

@Injectable({
    providedIn: 'root'
})
export class NotificationService {

    // TODO: implement a proper NotificationService!

    displayModal = new BehaviorSubject<boolean>(false);
    message = new BehaviorSubject<string>();

    constructor() { }

    showSuccess(message: string): void {
        alert(message);
    }

    public showError(message: string): void {
        this.message.next(message);
        this.displayModal.next(true);
    }

    public hideError(): void {
        this.displayModal.next(false);
    }
}

ErrorModalComponent:

@Component({
  selector: 'app-error-modal',
  templateUrl: './error-modal.component.html',
  styleUrls: ['./error-modal.component.css']
})
export class ErrorModalComponent implements OnInit {

    showModal: boolean;
    message: string;

    constructor(private notificationService: NotificationService) {}

    ngOnInit() {
        this.notificationService.displayModal.subscribe(v => this.showModal = v);
        this.notificationService.message.subscribe(m => this.message = m);
    }
}

查看:

<p-dialog [contentStyle]="{'overflow':'visible'}" 
    modal="true" 
    header="Error occured" 
    [(visible)]="showModal" >
    {{message}}
</p-dialog>

您的情态需要一些东西来关闭它。将该按钮绑定到组件中的本地closeModal函数,然后从那里调用hideModal的{​​{1}}函数。

希望对您有帮助。

答案 1 :(得分:0)

这可能是一种解决方法,但至少可以。在将displayModal和message设置为true之后,我用ChangeDetectorRef强制进行更改检测:

@Component({
  selector: 'app-error-modal',
  templateUrl: './error-modal.component.html',
  styleUrls: ['./error-modal.component.css']
})
export class ErrorModalComponent implements OnInit, OnDestroy {

  displayModalSubcription: Subscription;
  messageSub: Subscription;
  displayModal: boolean = false;
  message: string;

  constructor(private notificationService: NotificationService, private cdRef: ChangeDetectorRef) {}

  ngOnInit() {
    this.messageSub = this.notificationService.message.subscribe(message => {
      this.message = message;
      this.cdRef.detectChanges();
    });

    this.displayModalSubcription = this.notificationService.displayModal.subscribe(displayModal => {
      this.displayModal = displayModal;
      this.cdRef.detectChanges();
    });
  }

  ngOnDestroy() {
    this.displayModalSubcription.unsubscribe();
  }
}