Component

For the reference see: Component

A Component takes over a section of the display. It can render inside that section (the section is inside an HTML tag) and is king when it comes to manage anything rendered inside (like binding to events of buttons, changing the text of elements, re-rendering elements on-demand, rendering from network content, applying privately scoped styles, …)

It can host subcomponents which can be in turn in charge of portions of the display which fall within the realm of the main Component.

The usual combination for rendering involves 3 pieces

  • HTML
  • CSS
  • Python

Which can be combined in a single Python class or be divided in 3 proper .html, .css and .py files.

Note

You can use ComponentInline, which already configures htmlpath=None and stylepath=None for you, to avoid looking for external html and css resources for the component

Properties of a Component

  • Attributes and other definitions in the Component can be accessed by:

    • Subcomponents (and subcomponents of it)
  • It can access attributes of parent Component instances and the parent Module

  • It can declare:

    • bindings: which auto-generates an attribute bound to an Observable
    • services: which will be added as attributes and instantiated to provide a service to the component and subcomponents

    Note

    components is not missing from the declaration. The subcomponents mentioned above are generated by means of direct instantiation, by tag based auto-instantiation, or because they are children in a route definition hierarchy in the module.

  • It can define the tag under which it will be rendered or let it be auto-generated (see selector)

  • It can host Html content either fetched from a file or declared inline (see htmlpath and htmlsheet)

  • It can host CSS content either fetched from a file or declared inline (see stylepath and stylesheet)

  • It can render everything programmatically if needed be and/or modify the generated content/styles (see methods render and styler)

  • It can react to being loaded unloaded from the DOM (see the methods loading and unloading or the more generic version load)

Component instantiation

In order for a component to do its work it has to be instantiated. There are several possibilities. But before seeing them:

  • If a component is directly instantiated, it will look for the matching selector tag to render itself.

    Should the tag not be found, the default behavior is to render the tag and then render itself inside

  • If a tag is found in generated/fetched html code which matches the selector of a component, it will be instantiated so that it can render itself inside the tag.

Note

Remember, as stated above, that if no selector is specifically defined, the Component will auto-generate one. It will use its own class name (with hyphens in between lower/upper-case boundaries, then lowercased and receiving a unique suffix)

This dual behavior gives the programmer complete flexibility about how components will render by simply specifying the matching tags in html code, or by instantiating the component directly and letting it auto-render.

Module Bootstrapping

The component is declared in the components directive of a Module. It will be instantiated before the routing engine takes over.

from .app_component import AppComponent

class MyModule(Module):

    ...
    components = AppComponent  # can be a single item or an iterable
    ...

Route Bootstrapping

Components will be instantiated (and given a place to render) when the defined routes are visited

from .one_component import OneComponent
from .two_component import TwoComponent

class MyModule(Module):
    ...
    routes = [
        {'path': 'one', 'component': OneComponent,},
        {'path': 'two', 'component': TwoComponent,},
    ]
    ...

Inline instantiation

When a component is being rendered in render, an instance of another component can be created (it will become a sub-component)

from .two_component import TwoComponent

class OneComponent(Module):

    def render(self, node):
        ...  # do some work
        ...
        TwoComponent()  # create sub-component inline

Tag auto-instantiation

Specify the selector belonging to the component to be rendered in the Html code.

Note

The component has to be imported somewhere. If not, the python file will be just a text file sitting somehwere in the file hierarchy.

In the snippet below it is imported in the same module in which the instantiation will happen in the Html code, but it can actually be imported anywhere

First the component to be rendered, to show the selector being set to a fixed value.

class TwoComponent(Module):
    selector = 'two-component'
    ...
from .two_component import TwoComponent

class OneComponent(Module):
    # Use the selector defined inside TwoComponent
    htmlsheet = '''
    <h1>hello</h2>
    <two-component></two-component>
    '''

    def render(self, node):
        ...  # do some work
        ...

Tag auto-instantiation (2)

Same as in the previous example but issuing the tag programmatically

from anpylar import Component, html

from .two_component import TwoComponent

class OneComponent(Module):
    # Use the selector defined inside TwoComponent
    htmlsheet = '''
    <h1>hello</h2>
    '''

    def render(self, node):
        ...  # do some work
        ...
        html._tag('<two-component>')  # or the alias html._tagout

This is also possible as:

from anpylar import Component, html

from .two_component import TwoComponent

class OneComponent(Module):
    # Use the selector defined inside TwoComponent
    htmlsheet = '''
    <h1>hello</h2>
    '''

    def render(self, node):
        ...  # do some work
        ...
        TwoComponent.selector_render()

Component proceedings

The lifecycle of a component follows this path.

Initialization

  • __init__ will be called if defined

  • If css is defined as a path (stylepath) or inline (stylesheet) it will be placed in the DOM.

    Note

    The css will be scoped to the component and it is thus private to your component.

    This may generate an ajax call if the application has not been packaged and a path or auto-path (stylepath) is defined.

    The default behavior is to look for a css file which uses the Python class name transformed (underscores are placed in the upper/lower-case boundaries, all lowercased and with .css as the extension)

  • If html is defined as a path (htmlpath) or inline (htmlsheet) it will be placed in the DOM. This also includes generating super-charged DOM objects for each element generated, which can be later used in the code.

    This may generate an ajax call if the application has not been packaged and a path (or auto-path) is defined

    See also

    Pseudo-Programming can be done inside the html code with special directives in the names of attributes. See: Html Programming

    The default behavior is to look for an html file which uses the Python class name transformed (underscores are placed in the upper/lower-case boundaries, all lowercased and with .html as the extension)

  • The method styler() will be called

    If no stylesheet has been defined, this method can return text content containing the stylesheet

  • The method``render(node)`` will be called

    node is the html element under which rendering takes place. If html code (from either a file or an inline definition) was available, it will already be present and ready under node.

    If not, any html element generated with the anpylar.html module tags will be placed under node

DOM Loading/Unloading

  • After the initialization or when the component is again being navigated to, the method loading() will be called to indicate that the component is being placed in the DOM
  • When the component is being unloaded from the DOM (for example: navigating away to other route) the method unloading() will be called.

These two methods allow executing actions like for example clearing an input field when a component is loaded/unloaded. Upon the next visit to the component, the user will always have a fresh input field to type in.

There is a generic method load(loading=True) which can be overridden too. The default behavior is to call loading or unloading.

Deactivation

  • If the route that took to this component defines it, can_deactivate() will be called before navigating away (before unloading)

    can_deactivate can prevent navigating away, because the component may ask the application user if changes have to be saved.

Component actions

Those are the ones not defined by the platform. These will be the consequence of binding and callback functions set during rendering and/or loading/unloading.

It’s the programmer the one providing the sauce here.