Components

A component provides a powerful solution for crafting reusable functionalities. This section outlines the essential considerations for developing your custom components within LemonadeJS.

Custom components

In LemonadeJS, custom components consist of two primary elements: 'self', which encompasses the data and controls, and the HTML template, which forms the view. LemonadeJS simplifies the process of binding self and the template within a unified scope, thus ensuring a fluid interchange of properties, objects, and methods.

Summary of this chapter

Key points to remember

  • Self properties: All attributes from the component's HTML tag are accessible in the method as this;
  • Reserved Properties: parent, el, and refresh are reserved properties in any component;
  • Dynamic template: All HTML contained within a component tag serves as the template and is part of the function call;
  • Component refresh: Re-render the component while preserving the self's state;
  • Component declaration: A custom tag and its methods should bear the same name and be declared in your call to lemonade.element(template, self, { Component1, Component2, ... });

Self Properties

All attributes defined within the custom component tag in the template are accessible inside the corresponding custom component's JavaScript code via this.

<html>
<script src="https://lemonadejs.net/v4/lemonade.js"></script>
<div id='root'></div>
<script>
function Hello() {
    // Get the attributes from the tag
    const self = this;
    // Title and year are declared in the parent template
    return `<p>{{self.title}} {{self.year}}</p>`;
}

function Component() {
    const self = this;
    self.value = '2023';
    // title and year will be available inside Hello through (this)
    return `<>
        <Hello title="Hello" year="{{self.value}}" />
        <input type="button" value="Next"
            onclick="self.value++" />
    </>`;
}
// Register custom tags
lemonade.setComponents({ Hello });
// Render the component
lemonade.render(Component, document.getElementById('root'));
</script>
</html>
import lemonade from 'lemonadejs';

function Hello() {
    // Get the attributes from the tag
    const self = this;
    // Title and year are declared in the parent template
    return `<h1>{{self.title}} {{self.year}}</h1>`;
}

// Register custom tags
lemonade.setComponents({ Hello });

export default function Component() {
    const self = this;
    self.value = '2023';
    // title and year will be available inside Hello through (this)
    return `<>
        <Hello title="Hello" year="{{self.value}}" />
        <input type="button" value="Next"
            onclick="self.value++" />
    </>`;
}

Reserved Self Properties

Upon instantiation of a custom component, specific properties within the self object are reserved for distinct functions:

  • parent: Refers to the self of the parent component from which the current component is called.
  • el: Denotes the root HTML element of the custom component.
  • refresh: A method that initiates a re-render of the component. It is frequently used after operations on arrays or objects when the view needs to be refreshed.

Dynamic Template

Any HTML content within a custom component tag is recognized as its template. This content is passed into the component's method handler as the first argument, facilitating dynamic template functionality.

<html>
<script src="https://lemonadejs.net/v4/lemonade.js"></script>
<div id='root'></div>
<script>
// Template is based on the caller innerHTML
function Crypto(template) {
    // this received title from the caller
    const self = this;
    // Create the component
    return template;
}

function Component() {
    let self = this

    // The innerHTML of Crypto is the template for the component
    return `<>
        <Crypto title="Bitcoin">
            <b>Coin: {{self.title}}</b>
        </Crypto>
    </>`;
}
// Register custom tags
lemonade.setComponents({ Crypto });
// Render the component
lemonade.render(Component, document.getElementById('root'));
</script>
</html>
import lemonade from 'lemonadejs';

// Template is based on the caller innerHTML
function Crypto(template) {
    // this received title from the caller
    const self = this;
    // Create the component
    return template;
}

// Register custom tags
lemonade.setComponents({ Crypto });

export default function Component() {
    let self = this

    // The innerHTML of Crypto is the template for the component
    return `<>
        <p>Example</p>
        <Crypto title="Bitcoin">
            <b>Coin: {{self.title}}</b>
        </Crypto>
    </>`;
}

Component declaration

It is important to notice in the examples above that the components Hello and Crypto need to be declared to be used across the application.

Local declaration

To declare a local component, you can use lemonade.element to create your component as below.

<html>
<script src="https://lemonadejs.net/v4/lemonade.js"></script>
<div id='root'></div>
<script>
// Component
function Test() {
    let self = this;
    return `<p>Hello {{self.type}}</p>`;
}

function Form() {
    let self = this;
    // Declare the components locally
    let template = `<>
        <Test type="World" />
    </>`;

    return lemonade.element(template, self, { Test });
}
// Render the component
lemonade.render(Form, document.getElementById('root'));
</script>
</html>
import lemonade from 'lemonadejs';

// Component
function Test() {
    let self = this;
    return `<p>Hello {{self.type}}</p>`;
}

lemonade.setComponents({ Element })

export default function Form() {
    let self = this;
    // Declare the components locally
    let template = `<>
        <Test type="World" />
    </>`;
    return lemonade.element(template, self, { Test });
}

Component refresh

The refresh method within self is designed to initiate the update of an entire component or a specific array within a component. The following example illustrates conditional rendering: the component should execute a refresh to render different content based on certain conditions

<html>
<script src="https://lemonadejs.net/v4/lemonade.js"></script>
<div id='root'></div>
<script>
// Component
function Test() {
    let self = this;
    if (self.type) {
        return `<select :bind="self.value">
            <option value=""></option>
            <option value="test">test</option>
        </select>`;
    } else {
        return `<input type="text" :bind="self.value" />`;
    }
}

function Form() {
    let self = this;
    // The innerHTML of Crypto is the template for the component
    return `<>
        <p>Form</p>
        <Test :type="self.type" :ref="self.element" /><br><br>
        <input type="button" value="Update type"
            onclick="self.type = !self.type; self.element.refresh();" />
    </>`;
}
// Register custom tags
lemonade.setComponents({ Test });
// Render the component
lemonade.render(Form, document.getElementById('root'));
</script>
</html>
import lemonade from 'lemonadejs';

// Component
function Test() {
    let self = this;
    if (self.type) {
        return `<select :bind="self.value">
            <option value=""></option>
            <option value="test">test</option>
        </select>`;
    } else {
        return `<input type="text" :bind="self.value" />`;
    }
}

// Register custom tags
lemonade.setComponents({ Test });

export default function Form() {
    let self = this;
    // The innerHTML of Crypto is the template for the component
    return `<>
        <p>Form</p>
        <Test :type="self.type" :ref="self.element" /><br><br>
        <input type="button" value="Update type"
            onclick="self.type = !self.type; self.element.refresh();" />
    </>`;
}

Next Chapter

The next Chapter presents how to create a Component as a JavaScript class.

 

Next chapter: Classes