|
|
Documentation - Tags
3.9.3. Active Handlers
Active Handlers allow you to "attach" python functions to Spyce form submissions.
Instead of old-fashioned inspection of the request environment, Spyce will
pull the parameters required by your function's signature out for you.
Let's have a look at an example. Here, we define a calculate
function and assign it to be the handler for our submit input:
examples/handlerintro.spy
|
[[!
def calculate(self, api, x, y):
self.result = x * y
]]
<spy:parent title="Active Handler example" />
<f:form>
<f:text name="x:float" default="2" label="first value" />
<f:text name="y:float" default="3" label="second value" />
<f:submit handler="self.calculate" value="Multiply" />
</f:form>
<p>
Result: [[= hasattr(self, 'result') and self.result or '(no result yet)' ]]
</p>
|
Run this code
|
-
Handlers may be inline, as the calculate handler is here, or in a
separate Python module. When using a handler from a Python module, Spyce
will automatically import the module when needed. (Handler parameters are
strings, not Python references.) The todo demo
demonstrates using handlers this way.
- You can give your form inputs a data type; Spyce will perform the
conversion automatically before passing parameters to your handler function.
Active Handlers also make it easy to incorporate user-friendly error messages
into your forms simply by raising a HandlerError:
examples/handlervalidate.spy
|
[[!
def calculate(self, api, x):
from spyceException import HandlerError
try:
x = float(x)
except ValueError:
raise HandlerError('Value', 'Please input a number')
if x < 0:
raise HandlerError('Value', 'Cannot take the square root of negative numbers!')
self.result = x ** 0.5
]]
<spy:parent title="Active Handler Validation" />
<f:form>
<f:text name="x" default="-1" label="Value:" />
<f:submit handler="self.calculate" value="Square root" />
</f:form>
<p>
Result: [[= hasattr(self, 'result') and self.result or '(no result yet)' ]]
</p>
|
Run this code
|
You can show multiple errors at once with a CompoundHandlerError:
examples/handlervalidate2.spy
|
[[!
def errors(self, api):
from spyceException import HandlerError, CompoundHandlerError
cve = CompoundHandlerError()
cve.add(HandlerError('One', 'First error'))
cve.add(HandlerError('Two', 'Second error'))
if cve:
raise cve
]]
<spy:parent title="Active Handler Validation 2" />
<f:form>
<f:submit handler="self.errors" value="Show me some errors" />
</f:form>
|
Run this code
|
All Spyce modules are available via the api handler parameter (which
should always be the first parameter (after self in a class). Here
is an example that uses the db module:
examples/db.spy
|
<spy:parent title="To-do demo" />
[[!
def list_new(self, api, name):
if api.db.todo_lists.selectfirst_by(name=name):
raise HandlerError('New list', 'a list with that description already exists')
api.db.todo_lists.insert(name=name)
api.db.flush()
]]
(This is an self-contained example using the same database as the
<a href=/demos/to-do/index.spy>to-do demo</a>.)
<h2>To-do lists</h2>
[[ lists = db.todo_lists.select(order_by=db.todo_lists.c.name) ]]
<spy:ul data="[L.name for L in lists]" />
<h2>New list</h2>
<f:form>
<f:submit value="New list" handler=self.list_new />:
<f:text name=name value="" />
</f:form>
|
Run this code
|
Handlers in Active Tags allow you to
create reusable components, as in the the chat demo.
(Since Spyce captures stdout, you can use print to debug handlers.)
|