Search code examples
sapui5sap-fiori

Stick with generic ErrorHandler.js while allowing custom errormessage handling per request and not have double message boxes


The generic ErrorHandler which is an extension and hooked onto every component's main model request is useful for unexpected errors. However, when I'm creating new entities I want to report with user friendly messages. These messages are composed in the gateway and passed in the RAISE clause. Currently this causes to seperate message boxes to popup, one from the ErrorHandler, one from my onErrorHanlder that I pass to oModel.create().

How can I keep the generic one, but not use it in this case?


Solution

  • To detach the error handler (temporarily) from your model, you would have to call the detachRequestFailed handler that is attached to your model. This handler is attached to your model in the constructor of the ErrorHandler.

    However, to detach this handler, you need the listener and the function. The handler function is an anonymous function though, that you can't easily reference when you want to remove the handler temporarily.

    The currently delivered ErrorHandler only shows the first error message. It does this by checking whether there is a message box open already and only showing a message box whenever there is no message box open yet. To suppress all message boxes, just make the ErrorHandler believe there's a message box open already: this.component._oErrorHandler._bMessageOpen = true;. And once you're done with the special service and custom handlers, and want to fall back on the default ErrorHandler, just make sure the ErrorHandler thinks there are not message boxes open anymore: this.component._oErrorHandler._bMessageOpen = false;

    The probably better alternative is to write your own ErrorHandler and make sure that the function handling the error is not anonymous. In that way you can easily detach and reattach the function to your model.

    The required change in ErrorHandler.js: change the constructor and add _metadataFailedHandler and _requestFailedHandler

    constructor : function (oComponent) {
        this._oResourceBundle = oComponent.getModel("i18n").getResourceBundle();
        this._oComponent = oComponent;
        this._oModel = oComponent.getModel();
        this._bMessageOpen = false;
        this._sErrorText = this._oResourceBundle.getText("errorText");
        this._oModel.attachMetadataFailed(this._metadataFailedHandler, this);
        this._oModel.attachRequestFailed(this._requestFailedHandler, this);
    },
    
    _metadataFailedHandler: function(oEvent) {
        var oParams = oEvent.getParameters();
        this._showMetadataError(oParams.response);
    },
    
    _requestFailedHandler: function(oEvent) {
        var oParams = oEvent.getParameters();
    
        // An entity that was not found in the service is also throwing a 404 error in oData.
        // We already cover this case with a notFound target so we skip it here.
        // A request that cannot be sent to the server is a technical error that we have to handle though
        if (oParams.response.statusCode !== "404" || (oParams.response.statusCode === 404 && oParams.response.responseText.indexOf("Cannot POST") === 0)) {
            this._showServiceError(oParams.response);
        }
    },
    

    To detach the errorhandler:

    this.getModel().detachRequestFailed(
        this.component._oErrorHandler._requestFailedHandler,
        this.component._oErrorHandler);
    

    And to re-attach the errorhandler after you're done with the custom request and custom handler:

    this.getModel().attachRequestFailed(
        this.component._oErrorHandler._requestFailedHandler,
        this.component._oErrorHandler);