Providing values to the arguments of an Event on the fly¶
As explained in the tutorial example, when transitioning to an UrlBoundView
which is parameterised, the Event
used to specify the transition has
arguments matching those of the destination UrlBoundView
and also
values for these arguments.
Event
argument values are supplied where the Event
is passed to a ButtonInput
by calling the
with_arguments()
method.
Sometimes, however, those argument values are not yet known at this time:
In this example an Address is added on the ‘/add’ view, and the user is transitioned after that to the ‘/review’ view. The ‘/review’ view needs an argument: the id of the added address to review.
When the ButtonInput
is rendered on the ‘/add’ view, the new Address is not yet saved to the
database, and thus its id is not known. Only once the user clicks on ‘Save’ do we know the
id of the new Address.
In this case, instead of passing the ButtonInput
an Event
with_arguments()
, pass an
Event
with_returned_argument()
:
class AddressForm(Form):
def __init__(self, view):
super().__init__(view, 'address_form')
new_address = Address()
grouped_inputs = self.add_child(FieldSet(view, legend_text='Add an address'))
grouped_inputs.use_layout(FormLayout())
grouped_inputs.layout.add_input(TextInput(self, new_address.fields.name))
grouped_inputs.layout.add_input(TextInput(self, new_address.fields.email_address))
grouped_inputs.add_child(Button(self, new_address.events.save.with_returned_argument('address_id'), style='primary'))
Declare the save Event
with an address_id argument and return the new Address’ id
from the method executed by the Action
of the save Event
:
class Address(Base):
__tablename__ = 'eventresult_address'
id = Column(Integer, primary_key=True)
email_address = Column(UnicodeText)
name = Column(UnicodeText)
reviewed = Column(Boolean)
fields = ExposedNames()
fields.name = lambda i: Field(label='Name', required=True)
fields.email_address = lambda i: EmailField(label='Email', required=True)
def save(self):
Session.add(self)
Session.flush()
return self.id
def review(self):
self.reviewed = True
events = ExposedNames()
events.save = lambda i: Event(label='Save', action=Action(i.save), address_id=IntegerField())
events.review = lambda i: Event(label='Mark as reviewed', action=Action(i.review))
Also parameterise the ‘/review’ UrlBoundView
to require a matching address_id argument:
class AddressBookUI(UserInterface):
def assemble(self):
home = self.define_view('/', title='Show')
add = self.define_view('/add', title='Add')
review = self.define_view('/review', view_class=ReviewView, address_id=IntegerField())
home.set_slot('main', AddressBookPanel.factory())
add.set_slot('main', AddressForm.factory())
bookmarks = [f.as_bookmark(self) for f in [home, add]]
self.define_page(AddressBookPage, bookmarks)
self.define_transition(Address.events.save, add, review)
self.define_transition(Address.events.review, review, home)