Component ######### For the reference see: :doc:`/reference/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. .. code-block:: python 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 .. code-block:: python 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) .. code-block:: python 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. .. code-block:: python class TwoComponent(Module): selector = 'two-component' ... .. code-block:: python from .two_component import TwoComponent class OneComponent(Module): # Use the selector defined inside TwoComponent htmlsheet = '''