Set custom warning message in business process flow
<p>I have a business process flow that has a "special" validation. At least one of 3 steps have to be set to "Yes" to be able to continue to the next stage.</p>

<p>Here's my handler on stage change.</p>

<pre><code>var subStageRequirements = new Array();
subStageRequirements.push({ stage: 0, fields: ['new_is_project_scope_defined_substage'] });
subStageRequirements.push({ stage: 1, fields: ['new_is_demo_1_substage', 'new_is_demo_2_substage', 'new_is_selection_srv_outlined_substage'] });
subStageRequirements.push({ stage: 2, fields: ['new_is_proposal_substage', 'new_is_negotiation_substage'] });


function onStageChange(context) {

    var stage = context.getEventArgs().getStage();
    var stageCategory = stage.getCategory().getValue();
    var direction = context.getEventArgs().getDirection();

    if (direction == "Next") {

        //validate requirements on previous field...
        var valid = false;
        var req = subStageRequirements[stageCategory - 1];

        for (var i = 0; i &lt;= req.fields.length - 1; i++) {
            if (Xrm.Page.getAttribute(req.fields[i]).getValue()) {
                valid = true;
                break;
            }
        }

        if (!valid) {

            Xrm.Page.data.process.movePrevious(function (result) {
                if (result != "success") {
                    alert('Error forcing back to previous step: ' + result + '. Have fun...');
                }

                var messageArea = $(window.parent.document).find('.processWarningBar');
                messageArea.css('display', 'block');

                var textArea = $(window.parent.document).find('.processWarningBar-Text');

                textArea.attr('title', 'At least one sales sub-stage has to be selected to move on to next sales stage.');
                textArea.text('At least one sales sub-stage has to be selected to move on to next sales stage.');

                setTimeout(function () {
                    var messageArea = $(window.parent.document).find('.processWarningBar');
                    messageArea.css('display', 'none');
                }, 5000);
            });


        }

    }
}
</code></pre>

<p>As you see, once the stage has changed, I check if the steps in the previous stage (current stage - 1, in position) at least have one <code>true</code> value.</p>

<p>If not, I move back a stage (<code>movePrevious</code>) and then engage in some jQuery trickery... Which has some downsides (both error and warning icon are showing in the error, I have to hide the error div myself, sometimes when the validation passes and I move on to the next stage, the custom error message will flicker and disappear).</p>

<p>I'm trying to get this part to show a custom message:</p>

<p><a href="https://i.stack.imgur.com/SYmsI.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/SYmsI.jpg" alt="enter image description here"></a></p>

<p>Any better way to do this ? I'm thinking of the functions CRM itself calls when showing its own default message. I tried to ferret them out, but they seem well hidden.</p>

<p><strong>EDIT</strong></p>

<p>I changed the validation code to this as proposed by answer below:</p>

<pre><code>if (!valid) {

    Xrm.Page.data.process.movePrevious(function (result) {
        if (result != "success") {
            alert('Error forcing back to previous step: ' + result + '. Have fun...');
        }

        Xrm.Page.ui.setFormNotification('At least one sales sub-stage has to be selected to move on to next sales stage.', 'ERROR', 'subStageMessage');


        setTimeout(function () {
            Xrm.Page.ui.clearFormNotification('subStageMessage');
        }, 5000);

    });

    return;
}
else
{
    Xrm.Page.ui.clearFormNotification('subStageMessage'); //trying to hide it once the previous stage has passed validation, but error message is still shown...
}
</code></pre>

<p>The issue now is that the message is shown even when moving to the next stage. When validation fails, the user is sent back to previous step, then the message is shown. When the user completes the missing steps and moves to the next stage, even though the code that shows the message isn't executed, the message is still shown for another 5 seconds (??)</p>

<p>I'm using CRM 2016, and this is for the Opportunity entity.</p>