Viewloader

A teensy package that simplifies the process of binding DOM nodes to JavaScript functions. It does this by creating a convention for mapping between the DOM and your JavaScript and ensures that only the functions for the components in the DOM are executed.

Let’s create a "Hello, World!" component:

 // Add a `data-view-*` attribute
<input data-view-hello-world>

<script>
  import viewloader from "viewloader";
  // Create an object to hold our views
  const views = {
    // Create a camelCased key matching the dasherized data-view-hello-world
    // from our HTML: data-view-hello-world -> helloWorld
    helloWorld: (el, props) => {
      // The DOM node is passed here as `el` so we can do stuff!
      el.value = "Hello, World!";
    }
  }
  // Set up the manager
  var manager = viewloader(views);
  // Call viewloader with our "views" object whenever the DOM is ready
  manager.callViews();
</script>

This simple approach:

😎
Lets you stop worrying about if your JavaScript is going to be called — if there’s a data-view-* in the DOM it will be.
🔗
Establishes a clear convention for binding JavaScript to the DOM — makes it easy to find where in your codebase behaviour is originating from.
💊
Encourages (though doesn’t force) you to encapsulate behaviour within the context of a component’s DOM node.
💅🏽
Viewloader has one extra trick up its sleeve that makes it an incredibly powerful pattern: the value of the `data-view-*` attribute is passed to your matching JavaScript function as a second argument.
<input data-view-hello-world="Angela Merkel">

<script>
  import viewloader from "viewloader";

  const views = {
    helloWorld: (el, name) => {
      // Our attribute is available here!
      el.value = `Hello, ${name}!`;
    }
  }

  var manager = viewloader(views);
  manager.callViews();
</script>

And for additional ✨ it parses JSON-encoded values from that attribute into a proper object for you:

<input data-view-hello-world='{\"greeting\":\"Guten tag",\"name\":\"Angela Merkel\"}'>

<script>
  import viewloader from "viewloader";

  const views = {
    helloWorld: (el, props) => {
      // Our attribute is available here!
      el.value = `${props.greeting}, ${props.name}!`;
    }
  }

  var manager = viewloader(views);
  manager.callViews();
</script>

This gives you the power to create reusable components that can be "called" from your HTML with their own properties.

Viewloader provides freedom and flexibility to focus on encapsulating functionality within a minimal framework.

Viewloader is plain JavaScript; it doesn't have any dependencies.

See the Pen Hello Viewloader by icelab (@icelab) on CodePen.

Installation

Using npm:

npm install --save viewloader

Using yarn:

yarn add viewloader

Using unpkg:

https://unpkg.com/viewloader@latest/dist/viewloader.js

API

Initialisation

var manager = viewloader(views, scope, includeScope);
  • views — An object of view functions mapped to data-view-[name] attributes. (Required)
  • scope — An element or nodelist to scope the view loader to. (Optional. Defaults to document)
  • includeScope — A boolean to indicate if the scoped element should be included in the scoped views. (Optional: Defaults to false)

Calling views

You can call the views for an initialised instance:

manager.callViews();

Resetting views

Call the reset functions for an instances called views:

manager.resetViews();

Destroying views

Call the destroy functions for an instances called views:

manager.destroyViews();

Detailed examples

Customization with per-instance props

You can customize and reuse Viewloader components by providing different properties to each instance, through the data-view attribute.

In this example we have components that change the background color of another element. Since color is the only thing that changes, we can send the color in as a parameter and use the same component multiple times.

Let's create the color changer Viewloader component.

<script>
  import viewloader from "viewloader";

  const views = {
    changeColor: (el, color) => {
      el.style.backgroundColor = color;
      const container = document.body;

      el.addEventListener("mouseover", function(e) {
        container.style.backgroundColor = color;
      });
    }
  };

  var manager = viewloader(views);
  manager.callViews();
</script>

Finally we bind the component to the DOM nodes, by adding the data-view attributes with the various colors.

<div class="container">
  <div class="box" data-view-change-color='#5C526F'>1</div>
  <div class="box" data-view-change-color='#7CBB97'>2</div>
  <div class="box" data-view-change-color='#E78A37'>3</div>
  <div class="box" data-view-change-color='#F05051'>4</div>
</div>

That's it! You can see a live version of this example.

See the Pen Box of colours - Viewloader by icelab (@icelab) on CodePen.

Show me the scope

Viewloader can be scoped to specific elements, allowing it to be used only in specific parts of the template or to be applied only to new DOM elements.

You can pass in a boolean flag as the third parameter to indicate if the scope gets included or not in the set of executed views.

In this example we will show how to scope a component with Viewloader

We have two boxes, a "main" box and an inner box. The inner box represents the "target" element.

Let's create a simple Viewloader component that changes the border color of our boxes.

<script>
  import viewloader from "viewloader";

  const views = {
    changeBorder: (el, borderColor) => {
      el.addEventListener("mouseover", function(e) {
        el.style.borderColor = borderColor;
      });

      el.addEventListener("mouseout", function(e) {
        el.style.borderColor = "#fff";
      });
    }
  };

  var includeScope = document.querySelector(".include-scope");
  var excludeScope = document.querySelector(".exclude-scope");

  var includeScopeManager = viewloader(views, includeScope, true);
  includeScopeManager.callViews();
  var excludeScopeManager = viewloader(views, excludeScope, true);
  excludeScopeManager.callViews();
</script>

We select an element to be the starting point of our scope and pass it as the second argument to the `viewloader` function. The third argument is a boolean indicating if the element is included in the scope or not.

It's worth remembering that the false scope is the default Viewloader behavior.

Last but not least, let's add the data-view attributes to set the border color.

<h2>Include scope</h2>
<div class="main-box include-scope" data-view-change-border='#10BFAB'>
  <div class="inner-box" data-view-change-border='#D4AE89'></div>
</div>

<h2>Exclude scope</h2>
<div class="main-box exclude-scope" data-view-change-border='#10BFAB'>
  <div class="inner-box" data-view-change-border='#D4AE89'></div>
</div>

The border that changes color depends on the scope you pass; the scope option gives you flexibility in how you use each component.

That's it! You can see a live version of this example here.

See the Pen Scope Viewloader by icelab (@icelab) on CodePen.