Routing
App routing
Your Wave app gets hosted at the route you passed to @app()
.
To host your app at localhost:10101/foo
or www.example.com/foo
, pass /foo
to @app()
.
To host your app at localhost:10101
or www.example.com
, pass /
to @app()
. Do this if you plan to host exactly one app and nothing else.
You can host multiple apps behind a single Wave server.
caution
/foo
and /foo/bar
are two distinct paths. /foo/bar
is not interpreted as a sub-path of /foo
.
Hash routing
Wave apps support hash routing, a popular client-side mechanism where the location hash (the baz/qux
in /foo/bar#baz/qux
) can be used to decide which part of the UI to display.
Setting the location hash
To set the location hash, prefix #
to the name
attribute of command-like components. When the command is invoked, the location hash is set to the name of the command.
For example, if a button is named foo
is clicked, q.args.foo
is set to True
. Instead, if a button named #foo
is clicked, the location hash is set to foo
(q.args.foo
is not set).
Names don't have to be alphanumeric, so you can use names with nested sub-paths like #foo/bar
, #foo/bar/baz
, #foo/bar/baz/qux
to make route-handling more manageable.
The components that support setting a location hash are:
ui.button()
ui.command()
ui.nav_item()
ui.tab()
ui.breadcrumb()
Getting the location hash
To get the location hash, read q.args['#']
(a string). If the route in the browser's address bar is /foo/bar#baz/qux
, q.args['#']
is set to baz/qux
.
Hash route switching
Combining the two examples above gives us a basic pattern for handling routes and updating the user interface:
Organizing code
In most sizeable applications, the logic in the above if/elif/else
conditionals can call into sub-functions, possibly spread across other modules:
Reducing boilerplate
As your application gets larger, using the above if/elif/else
conditionals can seem tedious or repetitive. If so, you can use on
and handle_on
to reduce the boilerplate.
In the above example, the @on('#heads')
is read as "if q.args['#']
is 'heads'
, then invoke the function the @on()
is applied to" - in this case, on_heads()
.
Pattern matching
The @on()
annotation supports pattern matching.
This function is called when q.args['#'] == 'menu'
:
This function is called when q.args['#'] == 'menu/donuts'
:
This function is called when q.args['#']
matches, say, 'menu/donuts/chocolate', with the parameter donut_name
set to 'chocolate':
Same as above, but donut_name
is explicitly set to a string:
This function is called when q.args['#']
matches, say, 'menu/donuts/42', with the parameter donut_id
set to 42:
This function is called when q.args['#']
matches, say, 'menu/donuts/7e21c93f-3a8f-4994-b63e-4275bc975e60', with the parameter donut_id
set to the UUID:
This function is called when q.args['#']
matches, say, 'menu/donuts/below/2.99', with the parameter donut_price
set to 2.99: