imba / docs.imba.io

📝The official Imba documentation
https://docs.imba.io
4 stars 3 forks source link

Creating reusable components #38

Closed somebee closed 4 years ago

somebee commented 8 years ago

One valuable pattern in Imba is to create reusable and extendable tags for components and controls. Here we'll show you how to create a basic tag whose rendertree is composed of separate segments.

tag panel

    def header
        <@header> title or "Panel"

    def body
        <@body> "My content"

    def render
        <self>
            header
            body

# Now we can inherit from panel, and only override the body.
tag settings < panel

    def body # override body
        <@body>
            <div> "Stuff in settings"
            <div> "More settings"

Tip! When splitting the rendering into several methods outside of <self> all top-level tags must have an explicit name using the @-syntax like <div@myname>. Otherwise the div and its children will be recreated on every render. When tags have a name they will be created once (on the first call) and cached inline. This is one of the things that make Imba really fast.

Wrapping content

As you might know, tags are compiled to chains of setters. <div.hello> "world" will compile to something along the lines of div().flag('hello').setContent(['world']).end(). As you can see, the inner content of a tag is using a setter. We can override setContent to simply store a reference to the content, and then include the content somewhere inside the render-tree of the tag.

Overriding setContent is not something we'd recommend unless you really understand how rendering in Imba works. To learn more about rendering, see guide.

tag panel
    def setContent value
        @content = value
        self

    def render
        <self>
            <div.header> title
            <div.body> @content
            <div.footer> "My footer"

# spawn a panel with some buttons
<panel title="Settings">
    <button> "Save"
    <button> "Load"

All panels we spawn will now always wrap their content inside a div.body.