DEV Community

Anurag Vohra
Anurag Vohra

Posted on

bloc-them : JS UI framework, learn it in 15 minutes

The simplest, but mighty reactive UI framework, any JS developer can learn in less than 15 minutes!

Tutorial

The core theme of this framework is "Separation of concerns".
Its provides JS classes to separately encapsulate Business logic and UI code.

Lets start with the code:

<!--Custom web component we created in below our script!-->
<counter-widget></counter-widget>
<script type="module">
    import {Bloc, ListenerWidget,html, render } from "./index.js";

    class CounterBloc extends Bloc{
        constructor(){
            super(0);
        }
        increment(){
            this.emit(this.state+1);
        }
        decrement(){
            this.emit(this.state-1);
        }
    }

    class CounterWidget extends ListenerWidget{
        constructor(){
            super({
                blocName:"CounterBloc",
                hostedBlocs:{
                    CounterBloc: new CounterBloc()
                }
            });
        }

        build(state){
            return html`
                <div>
                    <div>
                        <button @click=${()=>this.bloc().increment()}>increment</button>
                        <button @click=${()=>this.bloc().decrement()}>decrement</button>
                    </div>
                    <div>Result: ${state}</div>
                </div>`;
        }
    }
    //custom web component defined here
    customElements.define("counter-widget",CounterWidget);
</script>
Enter fullscreen mode Exit fullscreen mode

What the above code does:

Business Logic is encapsulated in Bloc class (Business Logic Components) and the UI code logic in ListenerWidget.

  1. CounterBloc contains all your business logic (manges state of count).
  2. CounterWidget contains all the UI code.

After configuring, the ListenerWidget, it starts listening for changes in state from its subscribed Bloc.
As soon as a bloc emit a new state, the listener widget will reactively update itself with new values.

CounterBloc

/**
 * Business logic must be encapsulated in Bloc class
*/
 class CounterBloc extends Bloc{
    constructor(){
        //initial state of the Bloc
        super(0);
    }
    increment(){
        //emit function 
        //provided in Bloc class 
        //to emit new state
        this.emit(this.state+1);
    }
    decrement(){
        //emit new state
        this.emit(this.state-1);
    }
}
Enter fullscreen mode Exit fullscreen mode

CounterWidget

/**
 * ListenerWidget listens for state changes from blocs
 * In this case we have provided the blocName as `CounterBloc`
 */
class CounterWidget extends ListenerWidget{
        constructor(){
            super({
                blocName:"CounterBloc",//listen to this bloc
                hostedBlocs:{ //Listener UI can host different blocs for other nested UIs
                    CounterBloc: new CounterBloc()
                }
            });
        }

        build(state){
            //`html` is tagged template literal which helps in converting the code into HTML dom Nodes
            //@click is used to attach event listener to a particular node.
            //${state} can be used to get values 
            return html`
                <div>
                    <div>
                        <button @click=${()=>this.bloc().increment()}>increment</button>
                        <button @click=${()=>this.bloc().decrement()}>decrement</button>
                    </div>
                    <div>Result: ${state}</div>
                </div>`;
        }
    }
Enter fullscreen mode Exit fullscreen mode

Registering as web component
customElements.define("counter-widget",CounterWidget);

This line register CounterWidget class as a custome web component. So that we can use the <counter-widget> whereever we need this functionality.

whats that html

html is a tagged template.
Its actually plain old Javascript!, and not JSX. It helps in converting template strings into DOM Node.

No JSX , do it means it re-render entire nodes.

It do not uses virtual dom, but still it only modify those portion of UI nodes, which have been updated!!!
Its comparable to virtual DOM, though using plain old vanilla javascript.

More about what can go inside html

  1. You can add any valid HTML code inside html tagged template string.
  2. You can add event listeners using @ prefix: For example @touchmove to listen to touchmove event.
  3. You can add custom properties to a component using .: For example <my-app .config=${runtimeConfig}>, and whenever the runtimeConfig changes , it will automatically change the properties on my-app.
  4. You can also add attributes as such <div style=${"color:white;display:"+{true?"block":"none"}}>
  5. Also can add and aut remove optional attributes using ?: For example <div ?optional_att=${ifTrueThenShow}>.

How are blocs found

A listener widget first searches for the bloc its hostedblocs properties, if its not found than it looks for it in its parentNode , if not found there too, than it goes further up to grandParent nodes, until it finds the Bloc its listening too.
And once its finds it , it subscribes to that bloc. So that whenever new state is published , the listener widget will automtically update itself to the new state.

And thats it!!!


THE END

See how this has been used to create complex UI web component library : use-them

Top comments (0)