Skip to main content

APEX & custom warning messages

D

Did you ever wanted to customize user messages? To make them intuitive? Green as success, red as error, yellow as warning? Oh yes, lets add a third message type. Not everything can fit into success or error.



To achieve this, I am passing a JSON object as a message and catching this message on page before showing it to users. This allows me to pass the message type or even a unique color, icon and other things (like a DA name to fire after the message). You can modify it however you need.

To simplify this and make it more readable, I have created 3 JavaScript functions:

  • show_success
  • show_warning
  • show_error
const show_success = function(msg) {
    apex.message.showPageSuccess(JSON.stringify(get_message(msg, 'SUCCESS')));
};
//
const show_warning = function(msg) {
    apex.message.clearErrors();
    apex.message.showErrors([{
        type:       apex.message.TYPE.ERROR,    // sadly no warning supported
        location:   ['page'],
        message:    JSON.stringify(get_message(msg, 'WARNING')),
        unsafe:     false
    }]);
};
//
const show_error = function(msg) {
    apex.message.clearErrors();
    apex.message.showErrors([{
        type:       apex.message.TYPE.ERROR,
        location:   ['page'],
        message:    JSON.stringify(get_message(msg, 'ERROR')),
        unsafe:     false
    }]);
};
//
const show_message = function(msg) {
    if (!!msg.message) {
        if (msg.status == 'SUCCESS') {
            show_success(msg);
        }
        else if (msg.status == 'WARNING') {
            show_warning(msg);
        }
        else {
            show_error(msg);
        }
    }
};


Then I have a get_message functions which parse the JSON object.

const get_message = function(payload, status, action) {
    var msg = {
        'message'   : payload,
        'status'    : status,
        'action'    : action
    };
    if (typeof payload == 'object') {
        msg.message = (!!payload.message ? payload.message : msg.message);
        msg.status  = (!!payload.status  ? payload.status  : msg.status);
        msg.action  = (!!payload.action  ? payload.action  : msg.action);
    }
    else if (typeof payload == 'string' && payload.substring(0, 1) === '{' && payload.trim().slice(-1) === '}') {
        try {
            const obj = JSON.parse(payload);
            //
            msg.message = (!!obj.message ? obj.message : msg.message);
            msg.status  = (!!obj.status  ? obj.status  : msg.status);
            msg.action  = (!!obj.action  ? obj.action  : msg.action);
        }
        catch(err) {
            console.error('JSON_PARSE_FAILED', payload, err);
        }
    }
    return msg;
};


And finally the hooks to catch message before showing it to users. Note also the auto hide for success messages.

function() {
    const autohide_after = 2300;

    // autohide success messages
    // this actually dont work together with the following setThemeHooks
    apex.theme42.util.configAPEXMsgs({
        autoDismiss : true,
        duration    : autohide_after
    });

    // catch message event
    apex.message.setThemeHooks({
        beforeShow: function(pMsgType, pElement$) {
            // error messages
            if (pMsgType === apex.message.TYPE.ERROR) {
                var msg = get_message(pElement$.find('ul.a-Notification-list li').html());
                console.log('MESSAGE.ERROR:', msg);

                // switch error to warning
                if (msg.status == 'WARNING') {
                    pElement$.find('.t-Alert--warning').addClass('t-Alert--yellow');
                }

                // change message
                pElement$.find('.a-Notification-item').first().html(msg.message);
            }

            // success messages
            if (pMsgType === apex.message.TYPE.SUCCESS) {
                var msg = get_message($('#APEX_SUCCESS_MESSAGE h2.t-Alert-title').html());
                console.log('MESSAGE.SUCCESS:', msg);

                // change message
                $('#APEX_SUCCESS_MESSAGE h2.t-Alert-title').text(msg.message);

                // auto hide success message
                // this message can be from AJAX call (AJAX_PING process) and then it wont be autoclosed
                clearTimeout(last_scheduler);
                last_scheduler = setTimeout(() => {
                    apex.message.hidePageSuccess();
                }, autohide_after);
            }

            // execute action if requested
            if (!!msg.action) {
                console.log('TRIGGER_ACTION', msg.action);
                $.event.trigger(msg.action);
            }
        },
        beforeHide: function(pMsgType, pElement$) {
        }
    });
};


Enjoy. Source with other things...


Comments

  1. Great idea - and how do you include your "last" function in APEX?

    ReplyDelete
    Replies
    1. I have this in master_app.js file, referenced in User Interface - JavaScript as:
      #WORKSPACE_FILES#master_app#MIN#.js?version=#APP_VERSION#
      Source:
      https://github.com/jkvetina/MASTER/blob/main/database/apex/workspace_files/master_app.js

      Delete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Jan, great for easily color-coding and displaying types of messages. But what if I need to dispay a set of error messages AND warning messages, amd maybe an Info message as well? All at the same time. That is, for a particular transaction, some messages are Errors (and processing should stop) and some are Warnings - need to be displayed once, but do not block continued processing. Thoughts? I am currently using notfications for this - avoiding use of APEX errors. Which means I take on the downstream processing conditions.

    ReplyDelete
    Replies
    1. Dear Karen, I am not a big fan of stacking messages, I believe it is confusing for the users, it requires more time for them to read it. Hence these intuitive colors. I would chose blue for info messages, violet for system messages (like outages), but if you have too many colors, then it would not be intuitive anymore. So the question is how/when do you want to raise the info message to the user. Maybe the notification is not the best way, maybe it would be better somewhere on the page. But if you do them blue and auto hide them, it might be fine. It depends on your app, your users and your opinion.
      For the stacking, when you are passing the JSON object, there is nothing preventing you to pass multiple messages in this one object. You can modify the JS function to handle more of them, but I would not do that. I would show the user just one simple message.
      If I saw somewhere on the page green AND red AND yellow AND blue boxes with some messages at the same time, I would run away. Keep it simple.

      Delete
  4. Jan, ah, I hear you on hte multiple messages - but in this use case we definitely need both Errors and Warnings. Two notifications, one that lists all Errors, one that lists all Warnings. I agree, more than that, it twould be too confusing. But consider, it is annoying to have ot make multiple passes because hte interface did not tell you everyhting in one pass. i.e. to get all Errors in one pass, then be given all Warnings in the next pass, etc etc. Our use case is such that users are entering a bunch of values, and need to be informed of all errors and warnings that pertain to their entires in one pass. Thus my comment. I will check out your code to see about stacking them. I do have a working option now, but always open to simpler. Thank you!

    ReplyDelete
    Replies
    1. I would show red bubble with multiple lines (probably as a list) for errors. No warning if you have errors. When you fix all those errors as a user, you might get a yellow list with warnings. But at that point you probably submitted the page and it would disappear quickly or you need to throw a confirm dialog to stop.
      For you it is probably easier to stick with what you have...

      Delete
  5. You are catching on ... I show Errors as a list, and at the same time, separate bubble, Warnings as a list. Warnings only show once then drop to an indicator icon on the page. Yup, by doing this, I manage all downstream conditions on errors. It is not ideal, but works for this use case. If I was one of these users I would be annoyed to not be told about all the problems at once. In case of our Warnings, they could be intentional things, or they could be simple typos. It works ... and stays w/in the APEX sandbox pretty much for maintainability. Relly nice to see your solution!

    ReplyDelete
    Replies
    1. It would help to see the app and how you handle other users interactions. I would try to show them warnings before the errors. When they submit, I would stack the red bubble and yellow below that in a similar fashion as on the image at this article, just with much smaller spacing in between.

      Delete

Post a Comment