Skip to content

Latest commit

 

History

History
206 lines (175 loc) · 7.94 KB

index.md

File metadata and controls

206 lines (175 loc) · 7.94 KB

Table of contents

Back

Bootstrap

Just import the framework, create an istance of Luce, register the components, optionally set the roouter and the middlewares, and init the framework:

import Luce from 'lucejs':

window.onload = function () {

    const root = document.getElementById('output');  // root of the app
    const app = new Luce(root, {debug:true});        // (optional) pass a configuration object

    // (optional) run middlewares to set plugin, global services etc
    app.use((luce,next)=>{
        const config = {
            URL: 'localhost:3000',
            language:'en'
            availableLanguages:['en','ita']
            ...
        };
        luce.plug('config', config); // .plug() injects a $<name> obj in each component (in this case $config)
        next();     // advance to the next middleware
    })
    use((luce,next)=>{
        // do something...
    });

    // (required) registering components 
    app.addComponent('dad-component', dadCtrl)
       .addComponent('child-component', childCtrl)
       .addComponent('about-component', aboutCtrl);
        
    // (required) if ROUTER is not used a root and the name of the component to be rendered must be provided
    app.init(root, 'dad-component');
}

Components

Each component has in one single .jsfile the function responsible for the compilation of the template and the object representing the component, containing the component name, model data, functions associated with events, computed properties and component hooks. For didactic purpose I haven't used the events of lit-html)so events have been automatically added and removed according to the life cycle of the component and its presence in the current route. Events are registered with the attribute data-event="<event type>:<action name>". It's higly recommeded to use in the root of the component a classclass=${uppercase(this.name)} to distinguish the style of the component in a .sass distinct file, while it's mandatory to have an idid="${this.id}" which is injected during the creation of the different istances and then used by the engine to manage the cached istances.

To have nested components just place in the component template a div with the attribute data-component="<name of the component>". Porperties passed from a parent to child components are defined by the attribute data-props="<property x name>:<property x name>...". Luce.js injects, inside each component, $ele for accessing the HTML root of the component, $log for logging (according to the debug flag passed during the bootstrap phase) and $event for emit, subscribe (.on()) and unsubscribe (.off())to custom events. For filter functions inside the template just use pure functions.

function template () {
    return html`<div class=${this.name} id="${this.id}">
                <h3>Dad component</h3>  
                <p>Counter: ${this.counter}</p>
                <button data-event="click:add"> + </button>
                <button data-event="click:remove"> - </button>
                <p>Computed properties and filter: ${uppercase(this.interpolated)}</p>
                <hr> 
                <div data-component="child-component" data-props="form:name"></div>
            </div>`;
}

import {html} from 'lit-html';

// FILTER
import uppercase from './../filters/uppercase';

export function dadCtrl (id) {
    return {
        id: id,
        name: 'dad-component',
        template: template,
        data: {
            counter: 0
        },
        computed:{
            interpolated (params) {
                return `Clicked ${this.counter} times`;
            }
        },
        events: {
            add: function (e) {
                this.counter++;
            },
            remove: function (e) {
                this.counter--;
            }
        }
        onInit(){
            this.$event.on('from-child', (payload)=>{
                this.$log.log(payload);
            });
         },
        onPropsChange(){ },
        onDestroy(){ 
             this.$event.off('from-child', (payload)=>{
                this.$log.log(payload);
            });
        }
    }
};

Forms

Luce injects inside each component the $formsobject containing the forms of the relevant component istance, each with the elements to be validated. The form must be marked with the attributes data-form="<name of the form>" and the name while the items to be validated must have the attributes data-validation="<validation rules>".

    <form data-form="formTest" name="formName" novalidate>
        <div class="field">
            <label class="label">Name</label>
            <div class="control">
                <input class="input" type="text" placeholder="Your name" name="exampleImput" data-model="form.name" data-validation="required" value="${this.form.name}">
            </div>
        </div>
        <div class="field is-grouped">
            <div class="control">
                <button class="button is-link" type="button" data-event="click:validateForm">Submit</button>
            </div>
        </div>   
    </form>

Router

To use the provided router during the bootstrap of the app just map the URLs with the associated components to be displayed, set the 'fallback' component:

window.onload = function () {

    const root = document.getElementById('root');  // root of the app

    const app = new Luce(root, { debug: true });   // passing the root and a config obj

    // registering components
    app.addComponent('dad-component', dadCtrl)
        .addComponent('child-component', childCtrl)
        .addComponent('shared-component', sharedCtrl)
        .addComponent('about-component', aboutCtrl)
        .addComponent('not-found-component', notFoundCtrl)

    // rendering the root with FE ROUTER
    app.router
        // page fade animation 
        .beforeChange((luce) => luce.main.classList.add('fade'))
        .afterChange( (luce) => luce.main.classList.remove('fade'))
        // mapping path
        .addRoute('/', 'dad-component')
        .addRoute('/about', 'about-component')
        .addRoute('/about/:id/:counter', 'about-component')
        .ifNotFound('not-found-component')
    
    // start the app (if router is set .init() does not need arguments)
    app.init()
}

To use links for routing inside the a tag of the templates just use the attribute data-navigation as follows:

 <nav>
    <a data-navigation href="/about"> About </a>
    <a data-navigation href="/about/:${this.id}/${this.counter}"> About "with params"</a>
</nav>

In order to access the router navigation methods and read the URl params Luce injects inside each component the $routerobject:

export function aboutCtrl (id) {
    return {
        id: id,
        name: "about-component",
        template: templateFactory,
        data: {

        },
        events: {
            gotoHome () {
                this.$router.navigate('/');
            }
        },
        onInit () {
            console.log('Route params', this.$router.params);
        }
    }
}

Http

Luce injects inside each component the $httpobject for HTTP .get, .post, .put, .patch, .delete requests:

async getRandom () {
                try {
                    this.loading = true;
                    let toAvoidCors = 'https://cors-anywhere.herokuapp.com';
                    let response = await this.$http.get(toAvoidCors + '/https://swapi.co/api/people');
                    this.items = response.results;
                    this.loading = false;
                } catch (error) {
                    console.log('Error: ', error);
                    this.loading = false;
                }
            }