Html Super-Nodes
################
*AnPyLar* extends the powers of the Html Nodes (call them tags if you wish) to
make them:
- Aware of Observables and its events.
- Simplify template formatting.
- Integrate them in the routing engine (``routerlink``).
- Allow some direct programming in html code.
.. note::
The additional methods are all prefixed with ``_`` to make it clear that
they don't belong to the standard hierarchy of node methods
Formatting
**********
The method applied for it is: ``_fmt`` (we could have named it ``_format``, but
that takes longer to type)
The method takes regular values and can also take *Observables* which will
force re-formatting with each new value produced, i.e.: the node subscribes to
the value of the observable. An example from the *Tour of Pyroes*::
html.txt(' {name}')._fmt(name=pyro.name_) # obs name_
``pyro`` has an observable ``name_`` (generated through a binding) and in this
case:
- ``{name}`` will be formatted and reformatted with each value delivered by
``pyro.name_``
Notice how the ``{name}`` and later ``_fmt(name=xxx)`` syntax resembles that of
the string method ``format`` in Python. **It is the same**
When designing *AnPyLar* the question was if a new templating language had to
be designed and the answer was quick: let's use something which is already
built into the language and people know.
The same code above could have been written without names, as in::
html.txt(' {}')._fmt(pyro.name_) # obs name_
Still the same *Format Mini-Language* present in Python.
Rendering
*********
A node (or better said: underneath the node) can be rendered when an observer
generates a value.
From the *Tour of Pyroes*
.. code-block:: python
def render(self, node):
# render under ul in render_pyroes when observable self.pyroes_ fires
with node.select('ul') as ul: # find node where to display the list
ul._render(self.render_pyroes, self.pyroes_)
def render_pyroes(self, pyroes):
for pyro in pyroes:
with html.li() as li: # per-pyro list item
# per-pyro anchor routing path with parameter pyd
with html.a(routerlink=('/detail', {'pyd': pyro.pyd})):
html.span(pyro.pyd, Class='badge') # show pyd as badge
html.txt(' {name}')._fmt(name=pyro.name_) # obs name_
with html.button('x', Class='delete') as b:
# def param avoids closure using last pyro.pyd
def pyro_delete(evt, pyd=pyro.pyd):
evt.stopPropagation() # avoid evt clicking on "a"
self.pyro_delete(pyd)
b._bind.click(pyro_delete) # use "bind" to get event
The first part describes the rendering binding::
ul._render(self.render_pyroes, self.pyroes_)
which can be translated to:
- Whenever the observable ``self.pyroes_`` produces a value
- Call ``self.render_pyroes`` (with the value generated by ``self.pyroes_``)
to render underneath ``ul``
It is guaranteed that:
- Any previous DOM structure below ``ul`` will have been unloaded
- ``ul`` is selected as the node under which things will be rendered.
Dual Binding Formatting-Value
*****************************
A standard use case is an ```` field (or ``