Home

Awesome

Skeletor

XMPP Chat CI Tests

Skeletor is a modernization of Backbone's Models and Collections, while getting rid of the old Views.

It provides you with a more modern Backbone-like way to manage state.

Introduction

The original goal of Skeletor was to modernize Backbone to allow writing declarative view code instead of the imperative code (e.g. manually adding and removing DOM nodes). In other words, to allow for component-based code that automatically updates only the changed parts of the DOM, similarly to basically all modern JavaScript frameworks.

The original Backbone Views aren't components and can't be rendered in a nested and declarative way. Instead, it's up to you to manually make sure that these views are rendered in the correct place in the DOM. This approach becomes unwieldy, difficult and fragile as your site becomes larger and more complex.

Skeletor solves this by creating a new type of View, called ElementView, which is very similar to the original Backbone View but which is also a web component that gets instantiated automatically as soon as its rendered in the DOM.

The thing is, Lit Elements already provide anything one might need for a modern Backbone-line application. There's not really a need for the ElementView anymore, except to provide an upgrade path from a Backbone app to one that uses web components. It'll therefore likely be removed entirely in a future version, thereby leaving only Models and Collections, for managing state.

Installation

npm install @converse/skeletor

Changes from Backbone

We've made big, backwards incompatible changes in version 2:

Sekeletor adds the following changes to Backbone

Other backwards incompatible changes

Changes due to using Lodash instead of Underscore

  1. Use drop instead of rest.
  2. indexBy is called keyBy
  3. Use invokeMap for collections instead of invoke.
  4. Use includes instead of contains
  5. The partition and invokeMap methods have been removed.

ElementView example

The ElementView looks very similar to a normal Backbone View.

Since it's a web component, you need to call CustomElementRegistry.define to register it.

The this variable for the ElementView is the custom DOM element itself, in this case, <my-custom-button>.

So there is no el attribute and this.el will be undefined. Whereever in a Backbone View you'd use this.el, with an ElementView you'd just use this.


import { ElementView } from '@converse/skeletor/src/element.js';
import { render } from 'lit';
import { html } from 'lit';

export default class MyCustomButton extends ElementView {
    events = {
        'click .button': 'onButtonClicked'
    }

    async initialize () {
        this.model = new Model({ count: 0 });
        this.listenTo(this.model, 'change', this.render)
    }

    render () {
      return render(html`<button class="button">I've been clicked ${model.get('count')} times!</button>`, this);
    }

    onButtonClicked () {
      this.model.save('count', this.model.get('count')+1);
    }
}

CustomElementRegistry.define('my-custom-button', MyCustomButton);

You can now put your custom element in the DOM, and once the DOM is loaded by the browser, your ElementView will automatically be instantiated and initialize will be called.

  <div>
    <my-custom-button></my-custom-button>
  </div>