One of the most frequent questions that we come across is the one you can see, sort of, in the title of this article. Why do Error() rules fire seemingly without any connection to the interview experience? For example, you set up an Error() rule that is supposed to verify something in the third Screen of your interview, but you are stuck because you cannot get there – the Error is already firing.
The reality is that Error() rules use the concept of Scope, just like the rest of Oracle Intelligent Advisor. But the scope of the Error() rule is not a Screen or the Interview. It is the rule itself. So if the Error() rule can fire, it will. Irrespective of where you are in the Interview or what you are doing. Here is a simple example:
I have a project with three Screens. I collect one piece of data on each of the first two Screens and then I have a summary Screen. I want to display an Error on the Summary screen based on the value of a calculation involving the two pieces of data collected. So I start by building the Interview. Note three Screens and the final number which is the calculated attribute.
The rule looks something like this, for the demonstration. There is a calculation and an Error() rule:
Running the Interview in the Debugger, we can progress past the first Screen by entering a value. The second Screen allows us to enter a value as well, but if we enter a value that triggers the Error() we are stuck because we cannot progress to the summary Screen (where we wanted to show the Error) and if we go backwards, we will lose the value we entered, because it triggered the Error(). This is guaranteed to annoy the end user!
- Write a rule to display a label as an error message
So the above boolean attribute is now using the same logic, and the error rule we used originally is now commented out. Visually we are closer to our requirement – we can navigate to our Summary Screen and the error can be defined with a boolean attribute to control the visibility of the message (contained in a label) thus:
Note for simplicity in this example the label contains static text, which can be replaced by dynamic content. In addition, as per the original concept, the final number is a calculated attribute. So we will display it as read-only and the standard attribute options of Minimum or Maximum Value will not be of any use, since no value is entered by the user. The Screen is displayed accordingly:
The video above illustrates the new effect. Looks good – but the user can simply ignore the error since the message is just a label. There is nothing to stop the user from continuing. So we can gained the correct scope (our Screen) but lost the blocking effect of the Error() rule.
What can we do to solve that?
Here is a simple combination. We will implement an Input Extension for the final number. It will display the control in read-only, as before. We will catch the update key which will still fire if something happens in the interview which would cause the value to update. And we will also use the validate key to display an error message. Validate still fires even if the HTML control is read-only or disabled in an extension.
Notice how we switch between the control.setValue() and interview.getValue(). The interview.getValue() will give us the updated value, for example if the user changes one of the two inputs to our calculation, the underlying value of the final calculated attribute will change (interview.getValue() will get the updated value) whilst control.getValue() will get the old value. So we make sure that we update the extension display with the new value. Let’s have a look now – we will remove the label used previously so that we can see the outcome more clearly:
We are almost there. It responds well to keyboard input, triggering the error whenever we change the value in the two input boxes and removing it when we change to a value that totals greater than 10. The interview navigation buttons do the same thing, triggering the error where appropriate and forbidding the user from going forward. If there is no error, they can progress (in our case, to the end of the interview). The Validate has replaced the Error() rule.
But there is one final issue to overcome. When the user first lands on the Summary Screen, the error does not display in spite of the value being less than 10. That’s because the update / validate keys have not executed. Only the mount has executed. If we really want to go the whole 9 yards we can :
call this.validate() in the mount to see if the data we are about to display actually validated or not (it returns either true or the error message you provided in the validate key). Unfortunately this method does not return any DOM content – it simply tells you whether the data is validating or not.
Show a “fake” error message when we first display the Screen, if the data does not validate (the number is less than 10).
Remove the fake error message and let the extension take over on the next update, since it handles the validation properly. If you look very carefully you can just see that my CSS is not quite right – and the “fake” error is displayed slightly in the wrong position. It makes it easier to see the difference 🙂
This article is a follow-up to a discussion on the Forum which you can read here. I am well aware that this article goes above and beyond what we originally posted, not because we think this is a particularly good approach, simply to continue with our goal in mind “discuss and develop new and exciting, sometimes unprecedented concepts for Oracle Intelligent Advisor”. The example is purely for that purpose.
If you are interested in the Zip of the project, please leave a comment.
For more about Error() rules and validations and the like, have a look at these posts.