How to use hooks#

What are hooks for?

Hooks are special functions (“methods”, because they always belong to classes in alfred3), that will be executed by alfred3 at fixed moments in the experiment. Their purpose is to be redefined by you, when you write an experiment – and that can be really powerful. Here are a few things that you can accomplish through hooks:

  • Use data from previous pages in the creation of following pages

  • Use data from previous experiment sessions in the creation of following pages

  • Jump to a certain page upon page submission, depending on the input given by participants.

  • Add many pages with a few lines of code to a section.

How do hooks work?

Most hooks (with very few exceptions) can be recognized by the fact that they strat with on_. We aim to name the hooks in a way that will tell you, at which moment in the experiment they will be executed. That’s usually the second part of the hook.

You can use a hook by defining a page or section in class style (see How to write a page in class style) and redefining the hook methods that can help you.

Example – A dynamic page

Let’s say, we wish to do a calculation with a number that a participant entered on the first page of our experiment, and show the result to her on the following page. If we use the instance style, we can’t do it - because pages that are created in instance style get filled right at the start of an experiment. At that time, our participant has obviously not yet filled in her number.

We also can’t use the on_exp_access hook - because that one only makes shure that we can access the experiment session object from our page. So, instead we utilize the on_first_show hook, which will only get executed when a page is shown for the first time. A minimal experiment would look like this:

import alfred3 as al
exp = al.Experiment()

exp += al.Page(name="page1")
exp.page1 += al.NumberEntry(toplab="Enter a number", name="n1")


@exp.member
class Page2(al.Page):

   def on_first_show(self):
      entered_number = self.exp.values.get("n1")
      calculated_number = entered_number - 10
      self += al.Text(f"The result of our calculation is: {calculated_number}")

In the sections below, you find a list of all available hooks - their documentation will contain further examples.

Page Hooks#

Note

You can define multiple hook methods on the same page. In this case you should be aware, that elements are added to the page in order. To change the order of the elements on your page, you can work with the Page.elements dictionary.

on_exp_access

Executed once, when the ExperimentSession becomes available to the page.

on_first_show

Executed once, when the page is shown for the first time, before executing on_each_show().

on_each_show

Executed every time the page is shown, after executing on_first_show().

custom_move

Hook for defining a page's own movement behavior, executed every time a movement from the page takes place, before on_first_hide() and on_each_hide().

on_first_hide

Executed once, when the page is hidden for the first time, before executing on_each_hide().

on_each_hide

Executed every time the page is hidden, before closing it and before saving data, but after executing on_first_hide().

on_close

Executed once, when the page is closed, before data saving.

You can also use a hook to define custom page-specific validation:

validate

Returns True, if the validation checks pass, False otherwise.

There is also an additional hook that is defined by alfred3.page.TimeoutPage:

on_timeout

Executed once, after the timeout of the page runs out.

Section Hooks#

Warning

We are currently questioning the four section hooks on_enter, on_hand_over, on_resume, and on_leave. Everything that you may wish to accomplish with these hooks can be done in page hooks. The section versions have some caveats that make them a bit tougher to use correctly. So, for the meantime, please avoid these hooks and use page hooks instead. The attributes Section.first_page and Section.last_page may be useful for you in this regard.

The Section.on_exp_access() hook is not going anywhere, although we may at some point decide to introduce an alternative name for it in order to avoid confusion with Page.on_exp_access().

on_exp_access

Executed once, when the ExperimentSession becomes available to the section.

on_enter

Executed every time this section is entered.

on_hand_over

Executed every time a direct subsection of this section is entered.

on_resume

Executed every time the experiment resumes from a direct subsection to this section.

on_leave

Executed every time this section is left.

A section’s validation methods can also be used like hooks. Refer to How to customize validation behavior and the docs for these methods for more information.

validate_on_move

Validates the current page and its elements.

validate_on_forward

Called for validation on each forward move.

validate_on_backward

Called for validation on each backward move.

validate_on_jump

Called for validation on jumping from this section.

validate_on_leave

Validates pages and their input elements within the section.

Experiment Hooks#

Experiment hooks work in a different way than page and section hooks: They require the use of decorators. Click on the names of the hooks in the table below to get to their documentation, including examples.

setup

Decorator for functions that work on the experiment session directly after intialization.

finish

Decorator for code to be run upon ExperimentSession.finish().