Following-up on this question, I'm using the now attempting to implement a review screen, which will re-evaluate the off-ramp.
The code works this way:
What's happening now is that if the user, on the review screen, chooses the "not supported" feature from the screen at item 1 above, they still go back to the review screen, but with the "not supported" selection as a variable (not the desired behavior).
One idea is to simply stop showing that selection if it has been chosen previous (i.e. if the user has previously been told that option is not currently supported) per this question. That's only a partial solution, though, because if the user hasn't chosen the unsupported option at some point, that option can still be selected from the review screen. I'm running into a small problem here, though in that I'm setting a "flag" variable in my code (see below) to remove the option using 'show if': not not_supported_shown_flag
, which actually works great, except that hitting "review" from a review screen unsets it -- QUESTION 1: is there a way to prevent that from happening (i.e. to "review-proof" certain variables?).
For the larger issue, I thought there was probably a solution by including the code with a initial
specifier (or another logic control specifier). Eg:
mandatory: True
depends on: var
code: |
if var == "not_supported":
not_supported_shown_flag = True # the "offramp taken flag" variable, meant to remove the non-supported option from future visits to that screen by the user
not_supported_event_screen # the "off ramp"
The problems I'm running into now is that, following the top answer on this question are that:
not_supported_event_screen
not_supported_event_screen
, and (b) when the user clicks "revisit" again, they are taken to not_supported_event_screen
, where the "Exit" and "Exit and clear answers" buttons don't work as expected.QUESTION 2: wondering if there's a best-practice / accepted method for solving for this sort of situation? Initial
and reconsider
seem unnecessarily process-heavy because they'd call the code block (if I understand correctly) every time the screen changes (not that I expect process-intensity to make a noticeable difference here). mandatory: True
appears necessary, or the code block doesn't run on the first pass (only when recalculating).
Ideas I have had include:
not_supported_shown_flag
and the not_supported_event_screen
into two separate code blocks, to use two separate logic control modifierscode
on the actual question / specific answers to the question (I'm not sure if that's possible, because the question has been created in the format shown here).I'm just really not sure what the solve is - it seems like going "back" doesn't constitute a refresh sufficient to trigger a "refresh," and review pages work to some degree similarly as "events."
It would be necessary to see your YAML to answer these questions.
Which question is shown when the screen loads is a function of the interview logic. When the screen loads, Docassemble evaluates the initial
or mandatory
blocks in order from the top of the YAML to the bottom, and it skips any mandatory
blocks that have been fully executed already. If any undefined variable is encountered, Docassemble looks for a block in the YAML that will define that variable, and it will try to execute that block.
If your review
screen is not accessed through an "action," then you can divert the user away from the review screen it by having a mandatory
or initial
block that is evaluated every time the screen loads, which sends the user down a different path if var == "not_supported"
. It does not take much processing power for Python to make a comparison like this, so there is no problem having this in the code that gets executed every time the screen loads. My typical approach to the interview logic is to have a single long mandatory
code
block that contains many variable references and if
/else
statements containing references to particular variables, or calls to .gather()
. This block is like the "to do" list that docassemble follows every time the screen loads. This ensures that if the user makes any changes to variables that impact the logic, then the next time the screen loads, that logic will respond appropriately to the changed circumstances. This approach simplifies the specification of the interview logic. In my own interviews, I don't need to set "flag" variables like not_supported_shown_flag
.
The depends on
modifier is typically used on questions that are non-mandatory
. In your example, depends on
means that if var
changes, the not_supported_shown_flag
variable is invalidated. Whether the invalidation of not_supported_shown_flag
causes the interview logic to do anything differently depends on whether the interview logic uses not_supported_shown_flag
in the code that runs when the screen loads. Note that if your mandatory
cod
block has already been executed, the depends on
feature does not cause the block to re-enter the interview logic flow.
There is a function forget_result_of()
that can be used to "reset" a mandatory
block that has already been executed to completion. This function can be used to bring an already-executed mandatory
block back into the interview logic that runs when the screen loads. I don't think I have ever had to use forget_result_of()
, though. I have always found simpler ways to specify the interview logic and adjust for changes that the user makes.
There is a similar feature to depends on
called on change
that can be used to cause particular code to run when a variable changes, so if you wanted the variable not_supported_shown_flag
to be defined a certain way whenever the value of var
changes, you could use on change
to accomplish that. (Note that on change
is only intended for running code and adjusting interview answers, not for showing particular screens.)
If your review
screen is triggered by an "action," you might need to make adjustments to account for how actions work. Before your interview logic is evaluated, the process_action()
function is called, and this function causes the action to execute. Actions can be stacked; i.e., an action can trigger another action, which can trigger another action. Once the third action in the stack is completed, process_action()
will continue to work on the second action, and when that is completed, process_action()
will continue to work on the first action. For example, the first action might be the showing of the review screen, and the second action might be the editing of a certain variable. When the user edits the variable, docassemble goes back to the first action, namely the review
screen. Only when the user moves on from the review
screen does the interview logic get evaluated.
It is not necessary that process_action()
is called prior to your interview logic. You could call process_action()
at a particular point in your interview logic, so that if the screen loads, and var
is now equal to "not_supported"
, the user is diverted to a kick-out screen. So if you don't want the user to be sent back to the review
screen after changing var
to "not_supported"
, you could put the logic of the kick-out in an initial
code
block, and call process_action()
from that code
block.