This section discusses blocks that will typically appear at the beginning of the YAML of your interview.
If you are new to docassemble, you probably will not need to use “initial blocks” until you attempt something more advanced, so you can skip this section and proceed to the section on questions.
Interview title and other metadata
A metadata
block contains information about the interview, such as
the name of the author. It must be a YAML dictionary, but each the
dictionary items can contain any arbitrary YAML structure.
If a title
is defined, it will be displayed in
the main navigation bar in the web app.
If a short title
is provided, it will be
displayed in place of the title
when the size of the screen is
small. It is important to specify a short title
if your title
is
more than a few words long, because otherwise the navigation bar may
not look good on small screens.
If a logo
is defined, it will be displayed in the
navigation bar in the web app in place of the title
and short
title
. The content of the logo
should be raw HTML. The HTML
will be placed inside of a <span>
element, so make sure you only use
“inline” HTML elements that are compatible with being placed inside of
a <span>
. You can provide CSS to the interview and reference
CSS classes in your logo
. If you include an image, you should
size it to be about 20 pixels in height. If the logo is too tall, the
navigation bar will expand to fit, and you will need to adjust the
CSS to specify different values for .da-pad-for-navbar
and
.da-top-for-navbar
. If you include a logo
that is much wider than
100 pixels, you should also specify a short logo
that is not as
wide, so your navigation bar will look good on small screens. Make
sure that your raw HTML does not contain any errors, or else the
formatting of the page will become corrupted.
If a short logo
is defined, it will be used
in place of the logo
on small screens. Although you may develop and
test your interview on a monitor, many of your users will likely use
your interviews on a smartphone, so it is important that you keep the
needs of smartphone users in mind. Smartphone users want to use the
interview you developed and they don’t want your logo taking up half
of their screen.
If navigation bar html
is
provided, the contents will be inserted into the main navigation bar.
It will be inserted into a <ul class="nav navbar-nav">
element, so
for best results, the HTML should consist of one or more items in a
form like <li class="nav-item"><a class="nav-link"
href="/some_link">Label</a></li>
. For more information about how
these CSS classes work, see the documentation for the Bootstrap
Navbar. On small screens, the HTML is shown in the menu when the user
clicks the toggler icon. You may wish to use d-none d-md-block
classes to hide the HTML when the screen is small. Make sure your HTML
does not contain any errors, or else the HTML of the entire screen
could be affected.
If a tab title
is provided, it will be
displayed as the title of the browser tab. Otherwise, the title
will be used.
If a subtitle
is provided, it will be
displayed as the subtitle of the interview in the “Interviews” list
available to a logged-in user at /interviews
.
If a title url
is provided, clicking on the
title will open the given URL. Otherwise, the default behavior is
that clicking the title does nothing except that when the user is on a
help screen, clicking the title takes the user back to the question.
If you provide a title
url
and you do not want the URL to open in another browser window or
tab, set title url opens in other window
to False
. The default is
that the link does open another window or tab.
If a date format
is provided, this will be
used as the default date format when the format_date()
function is
called, or the .format_date()
method of the DADateTime
object
is called (which is used when DADateTime
objects are reduced to
text).
If a datetime format
is provided, this
will be used as the default date/time format when the
format_datetime()
function is called, or the
.format_datetime()
method of the DADateTime
object is called.
If a time format
is provided, this will be
used as the default time format when the format_time()
function is
called, or the .format_time()
method of the DADateTime
object
is called.
These values can be overridden using the set_parts()
function.
The metadata
block and the set_parts()
function can be used to
modify other aspects of the main navigation bar.
If an exit link
is provided, the behavior of
the “Exit” link can be modified. (The “Exit” menu option is displayed
when the show login
configuration directive is set to False
or
the show login
metadata specifier in an interview is set to
False
.) The value can be either exit
, leave,
or logout
. If
it is exit
, then when the user clicks the link, their interview
answers will be deleted from the server, and the user will be
redirected to the exit url
(see below). If exit link
is leave
,
the user will be redirected to the exit url
, and their interview
answers will remain intact. (It can be important to keep the interview
answers on the server if background tasks are still running.) If
exit link
is logout
, then if the user is logged in, the user will
be logged out and then redirected to the exit url
, but if the user
is not logged in, this will have the same effect as leave
. If exit
link
is exit_logout
, the user’s interview answers will be deleted,
they will be logged out if they are logged in, and they will be
redirected to the exit url
.
If an exit url
is provided, the user will be
redirected to the given URL when they click the “Exit” link. If no
exit url
is provided, the user will be directed to the exitpage
.
The exit url
also functions as an interview-level default value in
place of the system-wide exitpage
, which is used by the
command()
function and used on special pages that show buttons
or choices
that allows users to exit
or leave
.
If exit label
is provided, the given text
will be used in place of the word “Exit” on the “Exit” menu option.
If you set unlisted: True
for an interview
that has an entry in the dispatch
list in your configuration,
the interview will be exempted from display in the list of interviews
available at /list
. For more information about this, see the
documentation for the dispatch
configuration directive.
If you set hidden: True
, then interview
sessions for this interview will be omitted from the “My Interviews”
listing of sessions. (They will still be deleted by the “Delete All”
button, though.)
You can set tags
to a list of one or more “tags”
as a way of categorizing the interview.
The list of available interviews at /list
and the list of interview
sessions at /interviews
make use of the metadata tags
for
filtering purposes. Note that the metadata
of an interview are
static, while the tags of a particular session of an interview are
dynamic, and can be changed with session_tags()
.
If you set sessions are unique
to
True
, then docassemble will resume an existing session for the
user, if the user already has an existing session. This requires that
the user be logged in, so the user will be redirected to the login
screen if they try to access an interview for which sessions are
unique
is set to True
. You can also set sessions are unique
to a
list of roles, in which case uniqueness will be enforced only if the
user has one of the listed roles.
If you set temporary session
to to
True
, then docassemble will delete any existing sessions that the
user already has and start a new session.
If you set required privileges
to
a list of one or more privileges, then a user will only be able to use
the interview if they have one of the given privileges. If
anonymous
is included as one of the required privileges, then users
who are not logged in will be able to use the interview. However,
note that anonymous
is not actually a privilege in
docassemble’s privilege management system; only logged-in users
actually have privileges. If no required privileges
are listed,
then the default is that the interview can be used by anybody.
If there are multiple metadata
blocks in the YAML of an
interview that set required privileges
, the required privileges
settings of later metadata
blocks will override the required
privileges
settings of earlier metadata
blocks. Setting
required privileges: []
will ensure that the interview can be used,
notwithstanding the required privileges
settings of any earlier
metadata
blocks.
The required privileges
for listing
metadata specifier is like required privileges
, except
it only controls whether the interview will be shown in the list of
interviews available at /list
. The required privileges
metadata
specifier also controls whether the interview will be listed. For
more information about the /list
page, see the documentation for the
dispatch
configuration directive.
The required
privileges for initiating
metadata specifier controls whether the
user is allowed to initiate a new session. If you set required
privileges for initiating: admin
, then only users with the admin
privilege will be able to start a new session by visiting the URL for
the interview. You may want to use this if you use the API to
initiate sessions and you want the API to be the exclusive means of
initiating a new session. If you set required privileges for
initiating: None
, then not even the administrator will be able to
initiate a session of the interview (except by using the API).
If you set require login
to True
, then
a non-logged-in user will be denied access to the interview. However,
if anonymous
is one of the required privileges
, a non-logged-in
user will be able to access the interview regardless of this setting.
You can set an error action
if you want
your interview to do something substantive in the event that your
interview encounters an error that it would otherwise show to the
user.
A simple application of error action
would be to replace the error
screen with a question
:
When the interview encounters an error, the interview will run the
action given by error action
. In this case, error action
is
on_error
, and calling this action shows a question
to the
user. If you would like to use the error message in the action, you
can access it by calling action_argument('error_message')
. The “How
question came to be asked” explanation can be obtained by calling
action_argument('error_history')
. The result will be None
if the
server is not a development server, or if the history is unavailable
for some reason. The error trace can be obtained by calling
action_argument('error_trace')
.
An action can also run code that changes the interview logic. For
example, an error action
could skip through the remainder of the
questions and present a final screen:
If the attempt to run the error action also results in an error, the latter error is shown on the screen in the usual fashion.
See error help
and verbose error messages
for other ways to
customize error messages.
The
metadata
block also accepts specifiers for default content to be
inserted into various parts of the screen.
You can provide different values for different languages by setting each directive to a dictionary in which the keys are languages and the values are content.
In this example, the text indicated by "*"
will be used as the
post
screen part with question
blocks that have no language
. The
text indicated by "es"
will will be used as the post
screen part
with question
blocks that are modified with language: es
.
For information about other ways to set defaults for different parts of the screens during interviews, see the screen parts section.
The metadata
block also accepts the specifier
error help
. This is Markdown-formatted text that will be included
on any error screen that appears to the user during the interview.
You can also provide this text on a server-wide basis using the
error help
directive in the Configuration.
To support multiple languages, you can set error help
to a
dictionary where the keys are language codes and the values are the
error text to be shown:
This will not always be reliable, because an error might happen before the user’s language is known.
The metadata
block also accepts the specifier
show login
, which can be true
or false
. This controls whether
the user sees a “Sign in or sign up to save answers” link in the upper
right-hand corner during the interview. If show login
is not
specified in the metadata
, the Configuration directive show
login
determines whether this link is available.
By default, all of the functions
and classes of docassemble.base.util
are imported into the
namespace of a docassemble interview. If you want to load names
manually using a modules
block, you can set suppress loading
util
to True
:
If suppress loading util
is True
, the only name that will be
imported into your interview is process_action
.
You can control the meta tags returned by an
interview by setting social
.
This results in the following HTML inside of the <head>
tag:
In this example, the docassemble server is
https://demo.docassemble.org
, the version of the docassemble.demo
package is 1.1.5, the brandname
of the server is docassemble
,
and the locale
of the server is en_US.utf8
.
The image
references are special because if you set them to a
reference to a static file, they will be replaced with a full URL to
that file. Alternatively, you can provide a full URL. The example
contains references to a file within the same package (court.png
), a
file in a different package
(docassemble.demo:data/static/crown.png
), and an external URL
(https://docassemble.org/img/docassemble-logo-sq-125.jpg
).
Note that the itemprop="name"
, twitter: title
, and og:title
are
all set to the title
of the page. This can be overridden by setting
the top-level name
, title
under twitter
, and title
under og
.
By default, twitter:card
is set to summary
, og:url
is set to the
URL for the interview, og:site_name
is set to the value of
brandname
, og:locale
is determined from the locale
, and
og:type
is set to website
. These defaults can be specifically
overridden.
Server-wide default values for meta tags can be set using the
social
Configuration directive.
Note that by default, the docassemble server disallows web
crawling by returning a restrictive /robots.txt
file. That means
that as a practical matter, sites will not be able to consume your
meta tags. The /robots.txt
file can be customized using the
allow robots
directive so that your meta tags are accessible.
If you look at
example interviews that are used in the documentation, you will see
example start
and example end
in the metadata
. These indicate
the YAML blocks that should be excerpted and included in the
documentation. There is a script in the GitHub repository called
make-screenshots.sh
, which calls get_yaml_from_example.py
, which
scans the YAML files in a directory and outputs YAML containing
the excerpts, which is then processed by the Jekyll documentation
site that is hosted on GitHub Pages.
If you are using the translation
files system for translating an interview into multiple languages,
you should specify a default language
in the metadata
. If you
wrote the question
blocks in English and your translation files
translate questions from English into other languages, set default
language: en
in the metadata
. The default language
block will
override the default language
in the metadata
, and the language
modifier will override the default language
block. If you don’t
specify a default language
in the metadata
, docassemble will
assume the default language is the language indicated by the
language
directive in the Configuration. Setting a default
language
in the metadata
ensures that your interview can be
installed on a server that uses a different system-wide default
language.
It is important to put your metadata
directive at the top of your
interview YAML (i.e. before question
blocks and include
directives). The default language
in the metadata
is only
effective for blocks that follow the metadata
directive. This means
that another default language
directive can change the default
language of your interview. For example, if your interview starts out
with a metadata
block that sets the default language
to de
, but
then you have an include
block that brings in a YAML file containing
a metadata
block that sets the default language
to es
, then all
blocks processed afterward will be considered to be written in Spanish
(assuming no default language
block or language
modifier is
used). Although this may be what you want, in general, the best way to
indicate the default language of a YAML file is the default
language
block, rather than metadata
; the purpose of the
metadata
is to specify an interview-wide default.
If you have more than one e-mail configuration
under mail
, you can specify an email config
to use in the interview.
This will affect the functioning of the attachment
block’s e-mail
feature, as well as the send_email()
function.
Effect of multiple metadata
blocks
An interview can contain multiple metadata blocks. Values in later
blocks override earlier blocks. The values over later metadata
blocks are effectively superimposed on top of earlier metadata
blocks.
If you write YAML files to be include
d into other interviews, it
is a best practice not to include metadata
in YAML files that
will be included into other interviews.
Creating objects
An objects
block creates objects that may be referenced in your
interview. See objects for more information about objects in
docassemble.
If your interview references the variable spouse
, docassemble
will find the above objects
block and process it. It will define
spouse
as an instance of the object class Individual
and define
user.case
as an instance of the object class Case
.
The use of objects in docassemble interviews is highly encouraged.
However, the objects you use as variables need to inherit from the
class DAObject
. Otherwise, docassemble might not be able to
find the appopriate code
blocks or questions necessary to define
them. This is because of the way docassemble keeps track of the
names of variables.
A code block like this would effectively do the same thing as the
objects
block above:
This code is more complicated than normal Python code for object
initialization because the full name of the variable needs to be
supplied to the function that creates and initializes the object. The
base class DAObject
keeps track of variable names.
In some situations, running spouse = Individual()
will correctly
detect the variable name spouse
, but in other situations, the name
cannot be detected. Running spouse = Individual('spouse')
will
always set the name correctly.
Whenever possible, you should use objects
blocks rather than code to
initialize your objects because objects
blocks are clean and
readable.
You can also use objects
blocks to initialize attributes of the
objects you create. For information on how to do this, see the
documentation for the using()
method.
Importing objects from file
An objects from file
block imports objects or other data elements
that you define in a separate YAML or JSON data file located in
the sources folder of the current package. If the interview file
containing the objects from file
block is
data/questions/manage_claims.yml
, docassemble will expect the
data file to be located at data/sources/claim_list.yml
.
For more information about how this works, and about how to format the
data file, see the documentation for the
objects_from_file()
function. The example above is equivalent to
running claims = objects_from_file('claim_list.yml', name='claims')
.
If you set use objects
to True
, then the use_objects
keyword
parameter of the objects_from_file()
function will be used.
This is equivalent to running
claims = objects_from_file('claim_list.yml', name='claims', use_objects=True)
.
Incorporation by reference: include
The include
block incorporates the questions in another YAML
file, almost as if the contents of the other YAML file appeared in
place of the include
block. When the include
d file is parsed,
files referenced within it will be assumed to be located in the
include
d file’s package.
When a filename is provided without a package name, docassemble
will look first in the data/questions
directory of the current
package (i.e., the package within which the YAML file being read is
located), and then in the data/questions
directory of
docassemble.base
.
You can include question files from other packages by explicitly
referring to their package names. E.g.,
docassemble.helloworld:questions.yml
refers to the file
questions.yml
in the docassemble/helloworld/data/questions
directory of that package.
The include
block is a special type of block that is only evaluated
when the YAML is initially compiled. Modifiers like if
and
mandatory
have no effect on the include
block. It is not possible
to conditionally include a YAML file because include
is a
“compile-time” block, not a “runtime” block. If you want the blocks
inside of the included YAML file to be conditionally applicable, you
need to use if
or mandatory
modifiers on those blocks.
See the section on combining multiple interviews into one for
strategies about how to use include
effectively.
Images
With attribution: image sets
An image sets
block defines the names of icons that you can use to
decorate your questions.
The file names refer to files located in the data/static
directory
of the package in which the YAML file is located.
Since most free icons available on the internet require attribution,
the image sets
block allows you to specify what attribution text
to use for particular icons. The web app shows the appropriate
attribution text at the bottom of any page that uses one of the
icons. The example above is for a collection of icons obtained from
the web site Freepik, which offers free icons under an
attribution-only license.
The image sets
block must be in the form of a YAML dictionary, where
the names are the names of collections of icons. The collection
itself is also a dictionary containing terms images
and (optionally)
an attribution
. The images
collection is a dictionary that
assigns names to icon files, so that you can refer to icons by a name
of your choosing rather than by the name of the image file.
For information on how to use the icons you have defined in an image
sets
block, see decoration
in the question modifiers section, buttons
in the setting variables section, and “Inserting inline icons” in
the markup section.
Without attribution: images
An images
block is just like an image sets
block, except that it
does not set any attribution information. It is simpler because you
do not need to give a name to a “set” of images.
The above images
block is essentially equivalent to writing:
Python modules
Importing the module itself: imports
imports
loads a Python module name into the namespace in which your
code and question templates are evaluated. The example above is
equivalent to running the following Python code:
Note that using third-party modules in code
blocks could
potentially lead to errors relating to the Python pickle
module. Variables that are defined in your interview YAML are part of
the “interview answers” that persist in the database. Most objects
that are created by third-party Python modules are meant to live in
the memory of a Python process and are not amenable to being
“serialized” by pickle
or any other mechanism.
The “interview answers” are a Python dict
. This dict
is the
context in which Python in your YAML is executed or evaluated. This
dict
is also stored to the SQL database using pickle
after each
screen in the interview process.
Before pickling this dictionary, docassemble removes any top-level
names that refer to modules, functions, and classes, because these
variables cannot be pickled. Whenever the screen loads,
docassemble restores the dictionary from SQL and then imports
names from docassemble.base.util
, loads the names of any modules
listed in imports
blocks, and imports names from the modules listed
in modules
blocks.
Importing all names in a module: modules
Like imports
, modules
loads Python modules into the namespace in
which your code and question templates are evaluated, except that it
imports all of the names that the module exports. The example above
is equivalent to running the following Python code:
If you have a module file in the same package as the YAML file, you can import the names from the module file using Python’s syntax for a relative module reference:
Note that if you use modules
to import names from a module of your
own, you should make sure to define __all__
in the module to limit
which names are imported.
While a modules
block can import names of functions, classes, and
modules, you should not use modules
to import other types of
variables. If a name brought in by modules
does not refer to a
function, class, or module, you will get an error if the name refers
to an object that is not pickleable. Even if the object is pickleable,
it is not a good idea to bring it into the interview answers, because
that would be like doing:
If you have a module that contains constants, it would be better to bring in the name of the module and access constants from the module name:
Storing structured data
in a variable
The data
block allows you to specify a data structure in YAML in a
block and have it available as a Python data structure.
For example, in this interview we create a Python list and then re-use it in two questions to offer a multiple-choice list.
In Python, the variable fruits
is this:
You can also use the data
block to create more complex data
structures. You can also use Mako in the data structure.
data
blocks do not work the same way as template
blocks. The
Mako templating in a data
block is evaluated at the time the
variable indicted by variable name
is defined. The text stored in
the data structure is the result of processing the Mako templating.
The Mako templating is not re-evaluated automatically each time a
question
is shown.
You can also import data from YAML files using the
objects_from_file()
function.
Structured data in object form
If you set use objects: True
in a data
block, then lists in your
YAML will become DAList
s in the resulting data structure, and
dictionaries in your YAML will become DADict
s. The .gathered
attribute of these objects will be set to True
.
In addition, when use objects: True
is enabled, any dictionaries in
the data structure will be transformed into a DAContext
object if
the keys of the dictionary are a subset of question
, document
,
docx
, pdf
, and pandoc
that has at least two elements.
This is a useful shorthand for creating DAContext
objects. For
example:
If you set use objects: objects
, then the data structure under
data
will be evaluated as though it were a file imported by the
objects_from_file()
function.
By default, if objects created with use objects: True
or use
objects: objects
contain DAList
or DADict
objects, these
objects will have their .gathered
attributes set to True
. If you
want to leave .gathered
undefined, set gathered: False
. In the
following interview, gathered: False
is set so that the user can be
asked to fill in missing items.
Storing structured data
in a variable using code
The data from code
block works just like the data
block, except
that Python code is used instead of text or Mako markup.
Structured data from code in object form
The use objects
modifier can also be used with data from code
.
The data from code
block also supports use objects: objects
.
The gathered: False
modifier is also supported when use objects
is
set to True
or set to objects
.
Keeping variables fresh: reset
The reset
block will cause variables to be undefined every time a
screen loads.
This can be helpful in a situation where a variable is set by a
code
block and the value of the variable ought to be considered
afresh based on the user’s latest input.
Effectively, this causes variables to act like functions.
Another way to use this feature is to set the reconsider
modifier
on a code
block. This will have the same effect as reset
, but
it will apply automatically to all of the variables that are capable
of being assigned by the code
block.
The reset
block and the reconsider
modifier are computationally
inefficient because they cause extra code to be run every time a new
screen loads. For a more computationally efficient alternative, see
the reconsider()
function
Running code when a variable changes: on change
If you allow users to go back and change their answers, you may
find situations where using depends on
is not sufficient to
invalidate variables that depend on a variable that has been altered.
In this situation, you can write a block of Python code in an on
change
block that will be executed when a variable is changed.
If the user finishes this interview and then changes his mind about
whether he is married (indicated by the variable married
), this will
invalidate the answers to the questions about income. If he had said
at the outset that he was married, the questions would have asked
about the income of both himself and his spouse.
Tagging the income[i].amount
question with depends on: married
would not work because in the context of a change to married
, the
variable i
is not defined.
The on change
block states explicitly what should be done if the
variable married
changes: the .amount
attributes should be
invalidated and the income
list should be reopened for gathering.
Calling income.reset_gathered()
with mark_incomplete=True
will
undefine the .complete
attributes on each of the income items. This
is important because otherwise the existing items would still be
considered “complete,” and thus the .amount
attributes would not be
re-defined by the interview logic.
The on change
specifier needs to point to a YAML dictionary in
which the keys are variable names and the values are Python code
that will be run when the given variable changes value.
The on change
code is run not only when the variable is changed, but
when the variable is initialized. This is in contrast to depends
on
, which does not invalidate dependent variables when a variable is
initialized, but only when it is changed.
It is important that you write on change
code so that it will always
run to completion without encountering any undefined variables. This
code runs during a different part of the screen loading process than
other code. on change
code runs before modules
and imports
blocks have loaded (although the standard docassemble functions
from docassemble.base.util
, such as undefine()
and
invalidate()
, are available). If you need to refer to names from
custom modules, bring them into the namespace manually with a line
like from docassemble.missouri import MyObject
.
You can have more than one on change
block in your interview. If
more than one block refers to the same variable, all of the code
blocks will be run. The code blocks will be run in the order in which
the blocks appear in the YAML file.
Changing order of precedence
As explained in how docassemble finds questions for variables,
if there is more than one question
or code
block that offers
to define a particular variable, blocks that are later in the YAML
file will be tried first.
If you would like to specify the order of precedence of blocks in a
more explicit way, so that you can order the blocks in the YAML file
in whatever way you want, you can tag two or more blocks with id
s
and insert an order
block indicating the order of precedence of the
blocks.
For example, suppose you have an interview with two blocks that could
define the variable favorite_fruit
. Normally, docassemble will
try the the second block first because it appears later in the YAML
file; the second block will “override” the first.
However, if you actually want the first block to be tried first, you can manually specify the order in which the blocks will be tried:
Another way to override the order in which blocks will be tried is by
using the id
and supersedes
question modifiers.
Vocabulary terms
and auto terms
Sometimes you will use vocabulary terms that the user may or may not know. Instead of interrupting the flow of your questions to define every term, you can define certain vocabulary words, and docassemble will turn them into hyperlinks wherever they appear in curly brackets. When the user clicks on the hyperlink, a popup appears with the word’s definition.
If you want the terms to be highlighted every time they are used,
whether in curly brackets or not, use auto terms
.
Using auto terms
can lead to ambiguities, so it is generally better
to use terms
if you can. If you have two terms, green apple
and
apple
, then auto terms
will try to make a term within a term,
which will lead to unpredictable behavior.
If you want to refer to a term but you want the text of the hyperlink
to be different from the name of the term, you can use the pipe
character |
and write the alternate text after the |
.
Alternatively, in your definition of the terms, you can specify that
multiple phrases should be associated with a single definition. You
write your terms as a list of dictionaries, and if a dictionary has
two keys, phrases
and definition
, where phrases
refers to a list
of terms and definition
refers to a definition, that definition will
be used for each of the phrases:
You can also use terms
and auto terms
as question modifiers, in
which case the terms will apply only to the question, not to the
interview as a whole. When you use terms
and auto terms
as
initial blocks, you cannot use Mako templating in the definitions,
but when you use them as question modifiers, you can use Mako
templating.
If you want to define terms using Python code, you can use the
update_terms()
function.
The template
block
The word “template” has a number of different meanings. If you are interested in how to insert variables into the text of your questions or documents using the Mako templating syntax, see markup. If you are interested in document assembly based on forms or document templates, see the Documents section.
A template
block allows you to assign text to a variable and then
re-use the text by referring to a variable.
The content
of a template
may contain Mako and Markdown.
The name after template:
is a variable name that you can refer to
elsewhere. The variable gets defined as a special type of object
known as a DALazyTemplate
.
The template
block, like question
and code
blocks, offers to
define a variable. So when docassemble needs to know the
definition of disclaimer
and finds that disclaimer
is not defined,
it will look for a question
, code
, or template
block that offers
to define disclaimer
. If it finds the template
block above, it
will define the disclaimer
variable.
Optionally, a template
can have a subject
:
You can refer to the two parts of the template by writing, e.g.,
disclaimer.subject
and disclaimer.content
.
Note that writing ${ disclaimer }
has the same effect as writing ${
disclaimer.content }
. You can also write ${ disclaimer.show() }
(for interchangability with images).
To convert the subject and the content to HTML, you can write
disclaimer.subject_as_html()
and disclaimer.content_as_html()
.
These methods take the optional keyword argument trim
. If True
,
the resulting HTML will not be in a <p>
element. (The default is
False
.)
template
objects are also useful for defining the content of e-mails. See
send_email()
for more information on using templates with e-mails.
You might prefer to write text in Markdown files, rather than in
Markdown embedded within YAML. To facilitate this,
docassemble allows you to create a template
that references a
separate Markdown file.
The file disclaimer.md
is a simple Markdown file containing the
disclaimer from the previous example.
The content file
is assumed to refer to a file in the “templates”
folder of the same package as the interview source, unless a specific
package name is indicated. (e.g., content file:
docassemble.demo:data/templates/hello_template.md
)
In the example above, the sample interview is in the file
docassemble.base:data/questions/examples/template-file.yml
, while
the Markdown file is located at
docassemble.base:data/templates/disclaimer.md
.
If the content file
specifier refers to a dictionary in which the
only key is code
, the code
will be evaluated as Python code, and
the result will be used as the file.
In this example, the code
evaluated to the name of a file in the
templates folder. The code
may also evaluate to a URL, DAFile
,
DAFileList
, DAFileCollection
, or DAStaticFile
.
For more information about this use of template
s, see the section on
Inserting multi-line or formatted text into a single field in a DOCX
file.
The table
block
The table
works in much the same way as a template
, except its
content is a table that will be formatted appropriately whether it is
included in a question or in a document.
This block should be used when each row of your table represents an item in a group; that is, you do not know how many rows the table will contain, because the information is in a list, dictionary, or set. If you just want to format some text in a table format, see the documentation about tables in the markup section.
In the following example, the variable fruit
is a DAList
of
objects of type Thing
, each of which represents a fruit. Each row
in the resulting table will describe one of the fruits.
The table: fruit_table
line indicates the name of the variable that
will hold the template for table. The question
block includes the
table simply by referring to the variable fruit_table
.
The rows: fruit
line indicates the variable containing the group
of items that represent rows in the table. The fruit
variable is a
DAList
that gets populated during the interview.
Next, columns
describes the header of each column and what should be
printed in each cell under that header. Like a fields
list within
a question
, columns
must contain a YAML list where each item
is a key/value pair (a one-item dictionary) where the key is the
header of the column and the value is a Python expression
representing the contents of the cell for that column, for a given row.
In the example above, the header of the first column is “Fruit Name”
and the Python expression that produces the name of the fruit is
row_item.name
.
There are two special variables available to these Python expressions:
row_item
: this is the item in the group corresponding to the current row.row_index
: this is0
for the first row,1
for the second row,2
for the third row, etc.
You can pretend that the Python expressions are evaluated in a context like this:
In this example, the first column will show name of the fruit
(row_item.name
) and the second column will show the number of seeds
(row_item.seeds
).
The header of each column is plain text (not a Python expression). The header can include Mako and Markdown.
If you have a complicated header, you can use the special keys
header
and cell
to describe the header and the cell separately.
(This is similar to using label
and field
within a fields
list.)
You can use Python to create cells with content that is computed from the items of a group.
The above example prints the name of the fruit as a plural noun, and inflates the number of seeds.
Remember that the Python code here is an expression, not a block of code. If you want to use if/then/else logic in a cell, you will need to use Python’s one-line form of if/then/else:
When fruit_table
is inserted into the question
, the result will
be a Markdown-formatted table.
This:
will have the effect of this:
For more information about Markdown-formatted tables, see the documentation about tables in the markup section.
Instead of using a table
block, you could construct your own
Markdown tables manually using a Mako “for” loop. For example:
The advantages of using the table
block are:
- The
table
block describes the content of a table in a conceptual rather than visual way. In Markdown, simple tables look simple, but complicated tables can look messy. Thetable
block allows you to map out your ideas in outline form rather than squeezing everything into a single line that has a lot of punctuation marks. - The
table
block will attempt to set the relative table widths in a sensible way based on the actual contents of the table. If you create your own tables in Markdown, and the text in any cell wraps, the relative table widths of the columns will be decided based on the relative widths of the cells in the divider row (----|---------
). You might not know in advance what the relative sizes of the text will be in each column.
The table
block acts like a template
block in that the variable it
sets will be a docassemble object. The .content
attribute will
be set to the text of the table in Markdown format.
If the variable indicated by rows
is empty, the table will display
with only the headers. To suppress this, you can add show if empty:
False
to the table
block. The resulting .content
will be the
empty string, ""
.
If you would like a message to display in place of the table in the
event that there are no rows
to display, you can set show if empty
to this message. Mako and Markdown can be used. The message will
become the .content
of the resulting object.
If you include a table in the content of an attachment
, you might
find that the table is too wide, or not wide enough. Pandoc breaks
lines, determines the relative width of columns, and determines the
final width of a table based on the characters in the divider row
(----|---------
).
By default, docassemble will construct a divider row that is no longer than 65 characters. This should work for standard applications (12 point font, letter size paper).
You can change the number of characters from 65 to something else by
setting value of table width
in a features
block.
You can also use table
blocks with DADict
objects:
When rows
refers to a DADict
, then in the columns
, row_index
represents the “key” and row_item
represents the “value” of each
item in the dictionary.
By default, the display of a table
will require that the table is gathered. If you want to display a
table with the items in a group that have been completely gathered so
far, you can set require gathered: False
in the table definition.
When displaying a table using require
gathered: False
, an item will not be shown unless it has been
completely gathered. If you want to show unfinished items, set show
incomplete: True
.
By default, a column for which
information is not known will be displayed as “n/a.” You can
customize this by setting not available label
. In this example, the
label is set to a blank value:
Exporting tables to Excel and other formats
You can call the export()
method on a table
to get a DAFile
representation of the table.
For example, this interview provides a Microsoft Excel .xlsx file representation of a table:
This function uses the pandas
module to export to various formats.
The export()
method takes a filename, which is parsed to determine
the file format you want to use. This can also be provided as the
filename
keyword parameter. If you omit the filename, you can
indicate the file format using the file_format
keyword parameter.
The default file format is 'xlsx'
. The valid file formats include
csv
, xlsx
, and json
.
The title
keyword parameter indicates the name of the data set.
This is used as the name of the Microsoft Excel sheet.
When the xlsx
format is used, you can set the freeze_panes
keyword
parameter to False
to turn off the Microsoft Excel “freeze panes”
feature.
Here are some examples of usage:
fruit_table.export('fruit.xlsx')
: returns a Microsoft Excel file calledfruit.xlsx
.fruit_table.export('fruit.xlsx', title='Fruits')
: returns a Microsoft Excel file calledfruit.xlsx
where the sheet is named “Fruits”.fruit_table.export('fruit.xlsx', title='Fruits', freeze_panes=False)
: returns a Microsoft Excel file calledfruit.xlsx
where the sheet is named “Fruits” and the “freeze panes” feature is turned off.fruit_table.export('fruit.csv')
: returns a comma-separated values file calledfruit.csv
.fruit_table.export(file_format='csv')
: returns a comma-separated values file calledfile.csv
.fruit_table.export()
: returns a Microsoft Excel file calledfile.xlsx
.
The optional keyword parameter output_to
can be used to specify a
DAFile
to which the output of .export()
should be
written. If omitted, DAFile
with a random instance name will be
returned.
Converting tables to a pandas dataframe
If you want to work with your table as a pandas
dataframe, you can
call fruit_table.as_df()
to obtain the information for the table as
a pandas
dataframe object. However, note that objects from the
pandas
package cannot necessarily be “pickled” by Python, so it is
best if you call this method from functions in Python modules, or in
such a way that the results do not get saved to variables in the
interview.
Using tables to edit groups
You can use a table
to provide the user with an interface for
editing an already-gathered DAList
or DADict
.
For more information about this feature, see the section on editing an already-gathered list in the section on groups.
Sorting and filtering items in a table
If you have a DAList
or a DADict
and you want to display a table
of some of the items, or display the items sorted in a different way,
you can specify sort key
and filter
options.
In a table
definition where rows
refers to a DAList
, sort key
refers to a function that takes a single parameter as input, namely an
item in the list, and returns a value that should be used for
sorting the list. When Python sorts the list, it will call this
function on each item in the list. The sort key
is passed to the
key
parameter of the Python sorted
function.
Any function name can be used. For example, writing sort key: str
will use the str()
function to convert each item in the list to
text, and then alphabetize the rows based on that textual
representation of each item.
In most cases, though, you will want to write a lambda
function. For example:
This example uses
The last_eaten
attribute is defined by a datatype: date
field, so
the rows will be presented to the user in date order.
A lambda
function is just like a Python function, except it
doesn’t have a name. Equivalently, you could load a .py
module file
that defines the following function:
and then you could write sort key: get_last_eaten
. However, it is
easier to just write lambda y: y.last_eaten
.
Note that the use of the variable name y
is arbitrary. You could use
any variable name you want (as long as it isn’t a reserved Python
keyword).
In a table
definition, sort reverse
indicates whether the rows will be sorted in reverse order. In the
above example, sort reverse: True
is used, which means the table
will present the items in reverse chronological order. sort reverse
can refer to True
, False
, or any Python expression. If sort
reverse
is omitted or it evaluates to a false value, the rows are
sorted in forward order.
If you want the table
to present a filtered
list of the items, you can set filter
to a Python expression that
should be evaluated to determine if the item should be included or
not. In the above example, the expression is row_item.seeds >
0
. That means that the table
will omit any items in the fruit
list where the seeds
attribute is zero. Like an item in the
columns
, the filter
expression uses the special variables
row_item
and row_index
. The expression is evaluated for each item
in the list, and if the expression evaluates to a true value, the item
is included in the table.
If your table
is editable, it is important to perform sorting and
filtering using sort key
, sort reverse
, and filter
, rather than
by passing an expression to rows
that returns an altered version of
the underlying list. If you give rows
an altered version of a
DAList
object, some of the editing features might not work
correctly.
Note that these sorting and filtering features do not alter the
underlying DAList
in any way; they only affect the way the table
representation is displayed.
Sorting and filtering dictionaries
The sort key
, sort reverse
, and filter
features also work if the
rows
refers to a DADict
object. The main difference is that the
sort key
function is given a Python tuple
with two items, the
dictionary key and the dictionary value. If you want to sort on the
key of a dictionary item, access the first item; if you want to sort
on the value of a dictionary item, access the second item.
In this example, the sort key
expression is:
Here, y[1]
refers to the value of the dictionary item (a
DAObject
). The income items that are not received are listed as
though their amount
was zero, and then the other items are listed in
amount
order.
Defining the sections for the navigation bar
You can add use the navigation bar
feature or the
nav.show_sections()
function to show your users the “sections” of
the interview and what the current section of the interview is.
Here is a complete example.
Subsections are supported, but only one level of nesting is allowed.
If your interview uses multiple languages, you can specify more than
one sections
block and modify each one with a language
modifier:
If no language is specified, the fallback language *
is used.
Section headings are not processed as Mako. As a result, the
translations
system cannot be used to translate section
headings. Thus the translation method described above, using the
language
modifier, must be used to support section headings in
multiple languages. (Alternatively, you could use code
blocks and
the nav.set_sections()
to define the sections using template
blocks reduced to text.)
In the example above, the section
modifier referred to sections
using the same text that is displayed to the user. However, in some
circumstances, you might want to use a shorthand to refer to a
section, and update the actual section names displayed to the user
without having to make changes in numerous places in your interview.
You can do this by using key/value pairs in your sections
block, and
using the special key subsections
to indicate subsections:
The keywords for section names need to be valid Python names. When choosing keywords, make sure not to use the names of variables that already exist in your interview.
This is because the keywords can be used to make the left-hand navigation bar clickable. If a keyword for a section is a variable that exists in the interview, clicking on the section will cause an action to be launched that seeks a definition of that variable.
The recommended way to use this feature is to set up review
blocks
that have event
set to the keyword of each section that you want
to be clickable.
Note that if you use review
blocks in an interview with sections,
every question should have a section
defined. Otherwise, when your
users jump around the interview, their section may not be appropriate
for the question they are currently answering. Alternatively, you
could use code
blocks and the nav.set_section()
function to
make sure that the section is set appropriately.
By default, users are only able to click on sections that they have
visited. If you want users to be able to click on any section at any
time, set progressive
to False
:
By default, subsections are not shown until the user has entered one
of the subsections. If you want subsections to be opened by default,
set auto open
to True
.
Note that docassemble’s logic system is very different from that
of SurveyMonkey or TypeForm, where defining a sequence of questions
and dividing those questions into sections is straightforward. In
docassemble, the question that is asked at any given time is based
on the interview logic. The interview logic is evaluated and if a
necessary piece of information is undefined, docassemble will ask
a question (or run a code
block) to get a definition of that piece
of information. This is convenient when working toward an end goal,
because the interview developer can focus on specifying correct rules,
without worrying about the complexities of designing an interview
process. The downside is that the sequence of questions might be
different from one interview to another, and the sequence might not be
easy to fit into well-defined sections. Once variables are defined,
the sequence of questions that led to those variables being defined is
lost and cannot be repeated. Nor should the original interview process
be repeated, necessarily, because if the user makes changes that
impact the logic, the sequence should be different.
Given the way that docassemble’s interview logic works, if you
want to let the user revisit a section they have already completed,
you need to specify a process for that. Clicking on a section heading
and going to a special review
screen is one of the ways you can
specify a process.
The idea of a review
screen for a section is that you can give the
user an overview of the information they already entered. If users can
see their information from a summary perspective, it helps them notice
what might be incorrect or inconsistent. The review
screen can be
divided into subsections with headings indicated in Markdown. You can
embed Mako logic in the text and explain to the user the significance
of what they have entered.
A review
screen should ideally not have one button per variable, but
rather have one button for a sequence of one or more screens that the
user might want to revisit, after which they are returned to the
review
screen and they can see what has changed. If the user has
entered information into groups, you can show the user a table
of
the information they entered and let them add, edit, or delete items.
Assisting users with interview help
An interview help
block adds text to the “Help” page of every
question in the interview. If the question has help
text of its
own, the interview help
will appear after the question-specific
help.
You can also add audio to your interview help:
You can also add video to help text using the video
specifier.
See the question modifiers section for an explanation of how audio and video file references work.
You can also provide a label
as part of the interview help
. This
label will be used instead of the word “Help” in the main navigation
bar as a label for the “Help” tab.
Note that if you provide question-specific help
, and you include a
label
as part of that help, that label will override the default
label provided in the interview help
(except if question help
button
is enabled).
Mako functions: def
A def
block allows you to define Mako “def” functions that you
can re-use later in your question or document templates. You can use
the above function by doing:
Due to the way docassemble parses interviews, the def
block
needs to be defined before it is used.
Note the \
marks at the end of the lines in the mako
definition.
Without these marks, there would be an extra newline inserted. You
may or may not want this extra newline.
Setting the default role
If your interview uses the roles feature for multi-user interviews,
the default role
specifier will define what role or roles will be
required for any question that does not contain an explicit role
specifier.
When you use the roles feature, you need to have some way of telling your interview logic what the role of the interviewee is.
If you include code
within the same block as your default role
specifier, that code will be executed every time the interview logic
is processed, as if it was marked as initial
. For this reason, any
default role
specifier that contains code should be placed earlier
in the interview file than any mandatory
questions or code
blocks.
In the example above, the interview has two roles: “client” and
“advocate”. The special variable role
is set in the code
block,
which is executed every time the interview logic is processed.
In addition, the set_info()
function is called. This lets the
linguistic functions know who the user
is, so that questions can ask
“What is your date of birth?” or “What is John Smith’s date of birth”
depending on whether the current user is John Smith or not.
Setting the default language
This sets the language to use for all of the remaining questions in
the file for which the language
modifier is not specified. The
purpose of this is to save typing; otherwise you would have to set the
language
modifier for each question. Note that this does not extend to
questions in include
d files.
If your interview only uses one language, it is not necessary to (and
probably not a good idea to) set a default language
.
See language support for more information about how to create
multi-lingual interviews. See question modifiers for information
about the language
setting of a question.
Translation files
One way that docassemble supports multi-lingual interviews is
through the language
modifier on a question
and the default
language
block, which sets a default value for the language
modifier. Your interview can contain question
s in English that
don’t have a language
modifier, and question
s in French that
have the language: fr
modifier set. If the current language in an
interview (as determined by the set_language()
function) is French
(fr
), then when docassemble seeks a block to set a given
variable, it will search the French blocks first.
This method of creating multi-lingual interviews is good if the person who translates text from English to French is someone who understands how docassemble YAML files work.
There is another method of creating multi-lingual interviews that
may be preferable if the translator is someone who does not understand
how docassemble YAML files work. This second method extracts
the phrases from an interview (specifically, everywhere in the YAML
where Mako templating is allowed) and lists them all in an Excel
spreadsheet. The spreadsheet can then be given to a French
translator, and the translator fills out a column in the spreadsheet
with the translation of each phrase. Then the completed spreadsheet
can be stored in the sources folder of a package and referenced in
an interview using the translations
block:
Then, if the current language in an interview is French, the interview will use the French version of each phrase.
This allows you to support multi-lingual interviews while having a code base that is all in one language.
To obtain such a spreadsheet for a given interview, visit the Utilities.
The translations
block is only capable of defining translations for
blocks that come after the translations
block. Therefore, it is a
good practice to make sure that the translations
block is placed as
one of the very first blocks in your interview YAML file.
Since the translations
block only translates phrases in which Mako
templating is allowed, there are some parts of the YAML that are not
translatable through a translations
block. For example, sections
blocks do not use Mako and thus do not use the translations
system.
For more information about using translation files, read the section
Download an interview phrase translation file. See language
support for more information about how to create multi-lingual
interviews. See question modifiers for information about the
language
setting of a question. See also the default language
block and the default language
specifier under
metadata
.
Default screen parts
The default screen parts
allows you to write Mako and Markdown
to create text that will appear by default in parts of the screen on
every page.
When using this, make sure you do not cause your interview to go into
an infinite loop. If any of your screen parts require information
from the user, your interview will need to pose a question
to the
user to gather that information, but in order to pose the
question
, it will need the information. To avoid this, you can
use the defined()
function, the showifdef()
function, or other
methods.
In a multi-lingual interview, you can use multiple default screen
parts
blocks with different language
modifiers. If you are using
a translations
block, the screen parts in a default screen
parts
block can be translated through the XLSX or XLIFF files that
your translations
block references.
For information about other ways to set defaults for different parts of the screens during interviews, see the screen parts section.
Custom validation messages
The docassemble user interface uses the jQuery Validation Plugin to pop up messages when the user does not enter information for a required field, or if a number does not meet a minimum, or if an e-mail address is not valid, and other circumstances.
The messages that are displayed can be customized in a number of ways.
On a server-wide level, the messages can be customized the same way
other built-in phrases in docassemble can be customized: using the
words
directive in the Configuration to make a “translation
table” between the built-in text to the values you want to be used in
their place.
On an interview-wide level, the messages can be customized using a
default validation messages
block:
Within an individual field in a question
, you can use the
validation messages
field modifier to define what validation
messages should be used. These will override the default validation
messages
.
Each validation message has a code. In the above example, the codes
used were required
and max
. The complete list of codes is:
required
forThis field is required.
There is a default text transformation for languageen
that translates this to “You need to fill this in.” This is the standard message that users see when they fail to complete a required field.multiple choice required
forYou need to select one.
This is shown for multiple-choice fields.combobox required
forYou need to select one or type in a new value.
This is shown forcombobox
fields.checkboxes required
forCheck at least one option, or check "%s"
This is shown forcheckboxes
fields with a “None of the above” option. It is also used foryesno
fields withuncheck others
set, which is shown when the user does not check any of theyesno
fields.%s
is a code that is replaced with the label of the “None of the above” choice.minlength
forYou must type at least %s characters.
This is shown when there is aminlength
field modifier.maxlength
forYou cannot type more than %s characters.
This is shown when there is amaxlength
field modifier.checkbox minmaxlength
forPlease select exactly %s.
This is shown when there is acheckboxes
field with aminlength
field modifier that is the same as themaxlength
field modifier.checkbox minlength
forPlease select at least %s.
This is shown when there is acheckboxes
field with aminlength
field modifier set to something other than1
.checkbox maxlength
forPlease select no more than %s.
This is shown when there is acheckboxes
field with amaxlength
field modifier.multiselect minmaxlength
forPlease select exactly %s.
This is shown when there is amultiselect
field with aminlength
field modifier that is the same as themaxlength
field modifier.multiselect minlength
forPlease select at least %s.
This is shown when there is amultiselect
field with aminlength
field modifier set to something other than1
.multiselect maxlength
forPlease select no more than %s.
This is shown when there is amultiselect
field with amaxlength
field modifier.date
forYou need to enter a valid date.
This is shown fordate
fields when the text entered is not an actual date.date minmax
forYou need to enter a date between %s and %s.
This is shown fordate
fields withmin
andmax
set.date min
forYou need to enter a date on or after %s.
This is shown fordate
fields withmin
set.date max
forYou need to enter a date on or before %s.
This is shown fordate
fields withmax
set.time
forYou need to enter a valid time.
This is shown fortime
fields.datetime
forYou need to enter a valid date and time.
This is shown fordatetime
fields.email
forYou need to enter a complete e-mail address.
This is shown foremail
fields.number
forYou need to enter a number.
This is shown for numeric fields (number
,currency
,float
, andinteger
) when the input is not valid.min
forYou need to enter a number that is at least %s.
This is shown for numeric fields with amin
field modifier.max
forYou need to enter a number that is at most %s.
This is shown for numeric fields with amax
field modifier.file
forYou must provide a file.
This is shown for file upload fields.accept
forPlease upload a file with a valid file format.
This is shown for file upload fields with anaccept
field modifier.
Machine learning training data
If you use machine learning in your interviews, then by default, docassemble will use training data associated with the particular interview in the particular package in which the interview resides.
If you would like your interview to share training data with another
interview, you can use the machine learning storage
specifier to
point to the training data of another interview.
For example, suppose you have developed an interview called
child_custody.yml
that uses machine learning, and you have built
rich training sets for variables within this interview. Then you
decide to develop another interview, in the same package, called
child_support.yml
, which uses many of the same variables. It would
be a lot of work to maintain two identical training sets in two
places.
In this scenario, you can add the following block to the
child_support.yml
interview:
ml-child_custody.json
is the name of a file in the data/sources
directory of the package. This file contains the training data for
the child-custody.yml
interview. The naming convention for these
data files is to start with the name of the interview YAML file, add
ml-
to the beginning, and replace .yml
with .json
.
Now, both the child-custody.yml
and child-support.yml
interviews
will use ml-child_custody.json
as “storage” area for training data.
In the Training interface, you will find this data set under the
name child_custody
.
If you had run the child-support.yml
interview before adding
machine learning storage
, you may still see a data set called
child-support
in the Training interface. If you are using the
Playground, you may see a file called ml-child-support.json
in the
Sources folder. To get rid of this, go into the Playground and
delete the ml-child-support.json
file from the Sources folder.
Then go into the Training interface and delete any “items” that
exist within the child-support
interview.
If you want, you can set machine learning storage
to a name that
does not correspond with an actual interview. For example, you could
include machine learning storage: ml-family-law.json
in both the
child-custody.yml
and child-support.yml
interviews. Even though
there is no interview called family-law.yml
, this will still work.
If you are using the Playground, a file called ml-family-law.json
will automatically be created in the Sources folder
.
You can also share “storage” areas across packages. Suppose you are
working within a package called docassemble.missourifamilylaw
, but
you want to take advantage of training sets in a package called
docassemble.generalfamilylaw
. You can write:
For more information about managing training data, see the machine learning section on packaging your training sets
Optional features
The features
block sets some optional features of the interview.
Whether debugging features are available
If the debug
directive in the Configuration is True
, then by
default, the main navigation bar will contain a “Source” link that
shows information about how the interview arrived at the question
being shown. If the debug
directive is False
, then this will
not be shown.
This can be overridden in the features
by setting debug
to True
or False
depending on the behavior you want.
The following example demonstrates turning the debug
feature off.
On the server that hosts the demonstration interviews, the debug
directive is True
, so the “Source” link is normally shown. Setting
debug: False
makes the “Source” link disappear.
Note that if you are running an interview in the Playground, the
“Source” link is always shown, because the Playground is a
development and testing environment. You will need to install your
package to see the effect of the debug
feature.
Whether interview is centered
If you do not want your interview questions to be centered on the
screen, set centered
to False
.
Widening the screen when right
is used
If you want the effect of centered: False
when there is text in the
right
screen part, set wide side by side
to True
.
Progress bar
The progress bar
feature controls whether a progress bar is shown
during the interview. You can use the progress
modifier or the
set_progress()
function to indicate the setting of the progress
bar.
If you want the progress bar to display the percentage, include show
progress bar percentage: True
:
By default, if you do not set the progress
modifier on a
question
, then each time the user takes a step, the progress bar
will advance 5% of the way toward the end.
The 5% figure is known as the progress bar multiplier
and it is
configurable:
The default is 0.05.
If you set progress bar method: stepped
, the progress bar advances a
different way when there is no progress
modifier.
Instead of advancing toward 100%, it advances toward the next greatest
progress
value that is defined on a question
in the interview.
(Note that docassemble cannot predict the future, so whether the
question
with the next highest progress
value will actually be
reached is unknown; docassemble just looks at all the
question
s in the interview that have progress
values defined.)
The amount by which it advances is determined by progress bar
multiplier
.
To use the default method for advancing the progress bar, omit
progress bar method
, or set it to default
.
By default, the progress bar will not regress if the progress
specifier of the current question
has a lower value than the current
progress value. You can turn off this limit by setting progress can
go backwards
to True
:
Navigation bar
The navigation
feature controls whether a secondary navigation bar
is shown during the interview to show users the sections of the
interview. You can use the sections
initial block or the
nav.set_sections()
function to define the sections of your
interview. The section
modifier or the nav.set_section()
function can be used to change the current section.
If you want the secondary navigation bar to be horizontal across the
top of the page, set navigation
to horizontal
:
On small screens, it is not possible for the vertical navigation bar to display, so it is hidden, and the horizontal navigation bar is shown in its place.
The horizontal navigation bar functions differently than the vertical navigation. Subsections are shown if the user is inside a subsection, but otherwise they are not visible. There is no caret symbol for opening and closing subsections.
On smaller screens, the horizontal navigation bar uses less padding and a smaller font. This works well if there are only a few sections, but if there are too many sections, it may be impossible to fit them on the screen.
If you want the navigation bar to be hidden on small screens, set
small screen navigation: False
in your features
:
If you want the navigation bar to be converted into a dropdown on
small screens, set small screen navigation: dropdown
in your
features
:
The dropdown version shows all of the sections, including subsections that are not active.
Back button style
By default, there is a “Back” button located in the upper-left corner
of the page. (However, the “Back” button is not present when the user
is on the first page of an interview, or the prevent_going_back()
function has been used, or the prevent going back
modifier is in
use.)
Whether this back button is present can be controlled using the
navigation back button
feature. This will hide the “Back” button:
You can also place a “Back” button inside the body of a question, next
to the other buttons on the screen, by setting the question back button
feature to True
(the default is False
).
You can also place a “Back” button inside the body of a question on
some questions but not others, using the back button
modifier.
Help tab style
When interview help
is available, or the help
modifier is
present on a question, the “Help” tab will be present in the
navigation bar. When the help
modifier is present, the “Help” tab
is highlighted yellow and marked with a yellow star. When the user
presses the help tab, the help screen will be shown.
If you set the question help button
to True
, users will be able to
access the help screen by pressing a “Help” button located within the
body of the question, to the right of the other buttons on the page.
When question help button
is True
, the “Help” tab will not be
highlighted yellow.
Here is an interview in which the question help button
is not
enabled (which is the default).
Here is the same interview, with the question help button
feature
enabled:
Note that when question help button
is enabled, the label for the
help tab in the navigation bar always defaults to “Help” or to the
label
of the interview help
, and it is not highlighted yellow
when question-specific help is available.
Positioning labels above fields
By default, the docassemble user interface uses Bootstrap’s
horizontal form style. If you want your interview to use the
Bootstrap’s standard style, set labels above fields
to True
:
Floating labels
By default, the docassemble user interface uses Bootstrap’s
horizontal form style. If you want your interview to use the
Bootstrap’s floating labels style, set floating labels
to True
:
If floating labels are used, then the hint
field modifier and the
help
field modifier are unavailable.
Suppress autofill
By default, web browsers try to be helpful by presenting you with a
drop-down menu of past values you have used when you filled in a form
field. Luckily, it is possible to tell the browser not to autofill
form fields. If you want to tell the browser not to autofill, set
suppress autofill
to True
.
Hiding the standard menu items
By default, the menu in the corner provides logged-in users with the
ability to edit their “Profile” and the ability to go to “My
Interviews,” which is a list of interview sessions they have started.
If you want to disable these links, you can use the hide standard
menu
specifier:
If you want to add any of these links manually, or add them with
different names, you can do so with the
menu_items
special variable and the url_of()
function.
Hiding the menu and login interface entirely
The interface in the upper-right corner lets the user log in, or shows
a menu, shows the exit button, and/or shows the navigation bar
html
. This interface can be removed by setting hide corner
interface
to True
.
Javascript and CSS files
If you are a web developer and you know how to write HTML, JavaScript, and CSS, you can embed HTML in your interview text. You can also bring JavaScript and CSS files into the user’s browser.
For example, the following interview brings in a JavaScript file,
my-functions.js
, and a CSS file, my-styles.css
, into the
user’s browser. These files are located in the data/static
folder
of the same package in which the interview is located.
The contents of my-functions.js
are:
The contents of my-styles.css
are:
You can write whatever you want in these files; they will simply be loaded by the user’s browser. Note that your JavaScript files will be loaded after jQuery is loaded, so your code can use jQuery, as this example does.
If you have JavaScript code that you want to run after each screen of
the interview is loaded, attach a jQuery event handler to document
for the event daPageLoad
, which is a docassemble-specific event
that is triggered after each screen loads. (Since docassemble
uses Ajax to load each new screen, if you attach code using
jQuery’s ready()
method, the code will run when the browser
first loads, but not every time the user sees a new screen.) The
example above demonstrates this; every time the page loads, the code
will replace the contents of any element with the class groovy
.
This example demonstrates bringing in CSS and JavaScript files that
are located in the data/static
directory of the same package as the
interview. You can also refer to files in other packages:
or on the internet at a URL:
Also, if you want to bring in multiple files, specify them with a YAML list:
If you want to include CSS or JavaScript code in a specific
question, rather than in all questions of your interview you can use
the script
and css
modifiers.
The HTML of the screen showing a
question
contains a number of placeholder CSS classes that are
not used for formatting, but that are available to facilitate
customization:
- If a
question
is tagged with anid
, the<body>
will be given a class beginning withquestion-
followed by theid
, except that theid
will be transformed into lowercase and non-alphanumeric characters will be converted into hyphens. For example, if theid
isIntro screen
, the class name will bequestion-intro-screen
. <fieldset>
s are tagged with classes likefield-yesno
andfield-buttons
.<div>
s that contain fields are tagged with classes likefield-container
,field-container-datatype-area
,field-container-inputtype-combobox
, and other classes.
For more information, use the DOM inspector in your web browser to see what the class names are and which elements have the class names.
Example use of JavaScript: charting
Here is an example interview that uses a javascript
feature and a
script
modifier to draw a doughnut chart using chart.js.
Here is an example interview that draws a pie chart using Google Charts.
Disable analytics
By default, if your Configuration enables a segment id
, your
interviews will send information to Segment, and if it enables an
analytics id
in the google
configuration, it will send
information to Google Analytics. To turn this off for a particular
interview, set disable analytics
to True
in the features
block.
Bootstrap theme
Using the bootstrap theme
feature, you can change the look and feel
of your interview’s web interface by instructing your interview to use
a non-standard CSS file in place of the standard CSS file used by
Bootstrap.
The file can be referenced in a number of ways:
lumen.min.css
: the filelumen.min.css
in the “static” folder of the current package.docassemble.demo:lumen.min.css
: the filelumen.min.css
in the “static” folder (data/static/
) of thedocassemble.demo
package.docassemble.demo:data/static/lumen.min.css
: the same.https://bootswatch.com/lumen/bootstrap.min.css
: a file on the internet.
For more information about using custom Bootstrap themes, and for
information about applying themes on a global level, see the
documentation for the bootstrap theme
configuration directive.
Inverted Bootstrap navbar
By default, docassemble uses Bootstrap’s “dark” (formerly known
as “inverted”) style of navigation bar so that the navigation bar
stands out from the white background. If you do not want to use the
inverted navbar, set the inverse navbar
feature to False
.
To make this change at a global level, see the
inverse navbar
configuration directive.
Hiding the navbar
By default, docassemble shows a navigation bar at the top of the
screen. To make it disappear, you can set hide navbar: True
.
Width of tables in attachments
As explained more fully in the tables section, if you include a
table in an attachment
and the table is too wide, or not wide
enough, you can change the default character width of tables from 65
to some other value using the table width
specifier within the
features
block.
Disabling document caching
By default, docassemble caches assembled documents for performance
reasons. To disable the document caching feature for a given
interview, set cache documents
to False
.
Using pdftk to fill in PDF form fields
If you want the PDF files filled in by pdf template file
in your
interview to be produced by pdftk instead of pikepdf, set pdftk
to True
.
The setting can also be made on a per-attachment basis by setting the
pdftk
attachment setting.
Producing PDF/A files
If you want the PDF files produced by your interview to be in PDF/A format, you can set this as a default:
The default is determined by the pdf/a
configuration directive.
The setting can also be made on a per-attachment basis by setting the
pdf/a
attachment setting.
When using docx template file
, you also
have the option of creating a “tagged PDF,” which is similar to
PDF/A. You can set this as an interview-wide default:
The default is determined by the tagged pdf
configuration directive.
This setting can also be made on a per-attachment basis by setting the
tagged pdf
attachment setting.
Limiting size of uploaded images
If your users upload digital photos into your interviews, the uploads
may take a long time. Images can be reduced in size before they are
uploaded. To require by default for all uploads in your interview,
set maximum image size
in the features
block of your interview.
In this example, images will be reduced in size so that they are no taller than 100 pixels and no wider than 100 pixels.
Note that the image file type of the uploaded file may be changed to PNG during the conversion process. Different browsers behave differently.
This is just a default value; you can override it by setting the
maximum image size
in a field definition.
If you have an interview-wide default, but you want to override it for
a particular field to allow full-resolution camera uploads, you can
set the maximum image size
field modifier to None
.
If you want to use a site-side default value, set the
maximum image size
in the configuration.
Converting the format of uploaded images
If you are using maximum image size
, you can also cause images to be
converted to PNG, JPEG, or BMP by the browser during the upload
process by setting the image upload type
to png
, jpeg
, or bmp
.
Going full screen when interview is embedded
It is possible to embed a docassemble interview in a web page using an iframe. However, the user experience on mobile is degraded when an interview is embedded.
If you want the interview to switch to “full screen” after the user
moves to the next screen in the embedded interview, you can do so.
Within a features
block, include go full screen: True
.
For more information about implementing an embedded interview like this, see the HTML source of the web page used in this example.
Note that in this example, the user is provided with an exit button
at the end of the interview that directs the user back to the page
that originally embedded the interview. This is accomplished by
setting the url
of the exit button to the result of the
referring_url()
function.
If you only want the interview to go full screen if the user is using
a mobile device, use go full screen: mobile
.
Note that this example provides a different ending screen depending
on whether the user is on a desktop or a mobile device. If a desktop
user is viewing the interview in an iframe on a web site, the
interview should not provide an exit button that takes the user to a
web site, because then the user will see a web site embedded in a web
site. The interview in this example uses the device()
function to
detect whether the user is using a mobile device. Note that the
interview logic looks both at device().is_mobile
as well as
device().is_tablet
. This corresponds with the functionality of go
full screen: mobile
, which will make the interview go full screen if
the user has either a mobile phone or a tablet.
Infinite loop protection
The infinite loop protection section of the configuration documentation explains how you can change the default limits on recursion and looping for all interviews on the server.
You can also set these limits on a per-interview basis using the loop
limit
and recursion limit
features.
Customizing buttons on review pages
By default, when you use a review
screen that includes buttons,
the buttons have the Bootstrap “success” color. You can style these
buttons using the review button color
and review button icon
features.
The review button color
can be one of primary
, secondary
,
success
, danger
, warning
, info
, light
, link
, and dark
.
The default is 'success'
. The actual colors depend on the Bootstrap
theme.
The review button icon
can be set to the name of the Font Awesome
icon to use at the start of the button. The default is
'pencil-alt'
. The icon name is assumed to refer to an icon in the
“solid” collection (fas
). To use a different collection, specify a
name such as fab-fa-windows
for the windows
icon in the “brand”
collection. The default is None
, which means no icon is included.
Here is an example that uses the same style as “Edit” buttons within tables.
Enabling catchall blocks
If you set use catchall
to True
, then any variables for which no
block is available will be set to a DACatchAll
object.
For more information about this feature, see the catchall questions subsection.
Default date limits
If you want to set a default min
and/or max
on a date
field, you can use default date min
and/or default date max
.
Mako cannot be used to set these dates inside a features
block.
If you want to use a computed value, you need to specify a min
or
max
on the field.
Whether data about the question should be sent to the browser
When a docassemble interview loads in a user’s browser, the user
typically sees a question
. If the user appends &json=1
to the
URL, the user can see a JSON representation of the current
question
. The /api/session/question
API endpoint also
provides a JSON representation of a question.
If you want this data to be available in the JavaScript environment,
you can set send question data
in features
to True
.
Then, the data structure respresenting the current question will be
available as the JavaScript variable daQuestionData
.
Popover trigger
By default, when you use terms
or auto terms
, the definitions
pop up when the user clicks the label. The Bootstrap popover
feature allows the triggering method to be set to click
, hover
,
focus
, or manual
, and it allows you to specify multiple methods
separated by spaces.
The default trigger method is focus
. If you want to set the trigger
method to something else, set the popover trigger
under features
.
features:
popover trigger: hover
Loading custom datatypes
By default, docassemble will load the JavaScript for any
CustomDataType
data types that are used in the interview
YAML. However, if fields are created by Python code, docassemble
cannot detect which CustomDataType
data types will be used. In this
circumstance, you can manually specify which custom datatypes to load
using the custom datatypes to load
feature.
features:
custom datatypes to load:
- ssn
- iso639language
This will cause the web application to run the JavaScript for the
ssn
and iso639language
custom data types.
Jinja2 filters to apply automatically
You can write your own custom Jinja2 filters using
register_jinja_filter()
, but if you would like to apply a text
transformation to all Jinja2 variable interpolations automatically,
you can use the auto jinja filter
feature to specify a Python
function that should be used to transform all text being inserted into
the document.
For example, suppose you have a Python file my_filters.py
,
containing this:
Suppose you have a DOCX file animal_testimonial.docx
that contains
the following:
{{ testimonial }} `
You can then write a YAML file like this:
Any mention of the words “dog,” “fish,” or “turtle” in the
testimonal
will be replaced by the word “cat” in the output.
The result will be as though you used register_jinja_filter()
to
make a filter from the animal()
function and then your DOCX file
contained:
{{ testimonial animal }} `