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

眉间皱痕 提交于 2019-12-12 03:41:41

问题


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?


回答1:


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);



回答2:


To add to the above response from jpenninkhof, I have a scenario where requestFailed events are being raised (maybe the event was stuck in event queue) even after oViewModel.update (in my case it's an update request) request was completed. So I have come out with a solution for that. Let me first explain the problem. I have a dialog box for editing a Sales Order with Save/Cancel button. On Save, oViewModel.update is called with Success and Error handler functions.

this.getOwnerComponent().getModel().detachRequestFailed(this.getOwnerComponent()._oErrorHandler._requestFailedHandler,this.getOwnerComponent()._oErrorHandler);
oViewModel.update(aObjectPath, aData, {
success: function(oData, oResponse) {
    MessageToast.show("Request created successfully");
    this.getOwnerComponent().getModel().attachRequestFailed(this.getOwnerComponent()._oErrorHandler._requestFailedHandler, this.getOwnerComponent()._oErrorHandler);
},
error: function(oData, oResponse) {
    MessageToast.show("Error updating Sales Order.");
    this.getOwnerComponent().getModel().attachRequestFailed(this.getOwnerComponent()._oErrorHandler._requestFailedHandler, this.getOwnerComponent()._oErrorHandler);
    }});

The ErrorHandler-->_requestFailedHandler is called AFTER the error function thus the generic error popup still appears. I tried ErrorHandler-->attachRequestFailed() in oViewModel.attachRequestCompleted() also but the requestFailed handler was still being called after completion of the oData request (maybe it's a bug/limitation).

So I created another Flag in ErrorHandler.js along with a Callback function. The flag prevents Service message popup (like ErrorHandler-->_bMessageOpen) and calls the Callback to let the caller know that _showServiceError() has been called.

_showServiceError: function(sDetails) {

        if (this._bServiceErrorOpen){
            this._fnCallback();
            return;
        }

        if (this._bMessageOpen) {
            return;
        }.....
}

Define 2 more function, one to set the flag & callback function and other to reset it.

setServiceErrorFlag: function(fnCallback){
        this._bServiceErrorOpen = true; 
        this._fnCallback = fnCallback;
    },

    resetServiceErrorFlag: function(){

        this._bServiceErrorOpen = false;
        this._fnCallback = undefined;
    }

Just before calling model update set this flag. Now the ServiceMessage will not be displayed, instead the anonymous callback function will be called which will wait for while condition to be false.

var that = this;
this._bErrorResponse = false;
this.getOwnerComponent()._oErrorHandler.setServiceErrorFlag(function()
{ 
    while (that._bErrorResponse === false){}
    that.getOwnerComponent()._oErrorHandler.resetServiceErrorFlag();
});

In the error handler of oViewModel.update(), set _bErrorResponse to true so that while loop gets exited and the ErrorHandler flag is reset. This is to make sure that ErrorHandler flag is reset only after Error callback is called.

error: function(oData, oResponse) {
    MessageToast.show("Error updating Sales Order.");
    that._bErrorResponse = true;
}

Thus, the ServiceError message is suppressed and instead you can give your own error message in Error function callback of oViewModel CRUD APIs.




回答3:


I know it's an older post but for those, who also got that problem, I solved it with a "quick and dirty way", a temporary flag variable "bCustomError":

this.oModel.attachRequestFailed(function(oControlEvent) {
        if (!that.bCustomError) {
            /generic error handler
        }
        that.bCustomError = false;
    });

and now with a specific handler:

        this.bCustomError = true;
        this.oModel.read("/XXX(sPath, {
            success : this.onSuccessMethod.bind(this),
            error : function(oError){ //custom error handling here }
        });


来源:https://stackoverflow.com/questions/38720790/stick-with-generic-errorhandler-js-while-allowing-custom-errormessage-handling-p

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!