An open API service indexing awesome lists of open source software.

https://github.com/pimbrouwers/weld.js

Declarative DOM Bindings for great good.
https://github.com/pimbrouwers/weld.js

Last synced: 2 months ago
JSON representation

Declarative DOM Bindings for great good.

Awesome Lists containing this project

README

        

# weld.js

[![Build Status](https://travis-ci.org/pimbrouwers/weld.js.svg?branch=master)](https://travis-ci.org/pimbrouwers/weld.js)
[![npm Version](https://img.shields.io/npm/v/weld.js.svg)](https://www.npmjs.com/package/weld.js)
[![npm License](https://img.shields.io/npm/l/weld.js.svg)](https://www.npmjs.com/package/weld.js)
[![npm Downloads](https://img.shields.io/npm/dm/weld.js.svg)](https://www.npmjs.com/package/weld.js)

Declarative DOM bindings for great good. And it only costs you **998 bytes**.

> Don't select it. [Weld](https://github.com/pimbrouwers/weld.js) it.

## Getting Started

One of the first things you learn after spending some time with JavaScript is that DOM selectors are tricky. We often rely on classes and sometimes id's for this. Creating this invisible association between your CSS and JavaScript, which becomes a maintenance nightmare. Especially troublesome for teams, and onboarding new developers.

> We essentially ask CSS selectors to also become "JavaScript hooks", which violates one of the core tenants of software developent, single-responsibility principle.

### CDN

```html

```

### npm

```bash
npm install weld.js --save
```

## Usage

Attaching functionality to DOM elements is achieved using the custom attribute `data-weld="binderName: ..."`, where "binderName" is the identifer for a binder defined using `weld.addBinder()`.

```html











// a simple gretting binder
weld.addBinder('hello', function (el, msg) {
el.innerText = 'hello ' + msg;
});

weld.addBinder('helloObj', function (el, obj) {
el.innerText = (obj.greeting || 'hello') + ' ' + obj.name;
});

weld.addBinder('helloFunc', function (el, fn) {
el.innerText = fn();
});

weld.addBinder('helloMulti', function(el, name, values) {
el.innerText = (values.greeting || 'hello') + ' ' + name;
});

weld.applyBindings(); //activate weld

```

## Usage with modern JavaScript Frameworks

Many of the modern JavaScript frameworks, which typically angle their value proposition toward single-page application (SPA) development. But many of them are actually extremely viable options for multi-page application (MPA) development as well. Think of these as server-side application with ~sprinklings~ of JavaScript enhancements.

When building a SPA we create a root element, `

`, pass it to our framework of choice and it takes over from there. Effectively eliminating the brittle CSS<->JS relationship. But in MPA development, there isn't a clean entry-point like this, since the markup is primarily generated server-side. Thus, we often turn to using existing (or creating new) classes to begin attaching our JavaScript logic.

Instead, using weld.js we can declaratively inject our components removing any reliance on selectors for activation.

### An example using [mithril.js](https://mithril.js.org/):

```html

// A mithril component
function HelloWorld() {
return {
view: function (vnode) {
var msg = 'hello ' + vnode.attrs.name;
return m('div', msg);
}
}
}

weld.addBinder('hello', function (el, name) {
// We encapsulate in a closure so we can pass arguemtns
m.mount(el, {
view: function () {
return m(HelloWorld, { name: name });
}
})
});

weld.applyBindings();

```

## Why?

Take the trivial example of a client-side hello world greeter, which receives it's data (i.e. name) from the server.

### Using DOM selectors

```html

var msg = 'pim';


var greeter = document.getElementById('hello-greeter');
if(greeter)
greeter.innerText = 'hello ' + msg;

```

Notice how we're forced to create CSS taxonomy in order to facilitate discovery, and create a globally scoped ad hoc script tags to associate data from our server.

Now imagine we wanted multiple greeter elements. In order to do this, we need to update not only the JavaScript, but also the CSS. This could be a complete nightmare and it's often safer to create new classes and functionality altogether just to avoid breaking anything that might also be reliant on these.

```html

var msg = 'pim';

msg = 'jim';


var greeters = document.getElementsByClassName('hello-greeter');
if (greeters) {
for (var i = 0; i < greeters.length; i++) {
greeters[i].innerText = 'hello ' + msg;
}
}

```

That's not so bad. It's slightly more code, still reasonable though. But hang on... does this work? It looks accurate, but will it output what we think? The answer is no! If you attempt to run this sample, you'll see "hello jim" printed twice. This happens because second assignment to `msg` occurs before the JavaScript is executed.

We can solve this though, using `data-*` attributes.

```html


var greeters = document.getElementsByClassName('hello-greeter');
if (greeters) {
for (var i = 0; i < greeters.length; i++) {

var msg =
greeters[i].hasAttribute('data-msg') ?
greeters[i].getAttribute('data-msg') :
'world';

greeters[i].innerText = 'hello ' + msg;
}
}

```

Again, slightly more code than before. But still reasonable. Where this approach begins to fall apart though is when we need to start passing in more parameters, or more complex parameters. Imagine trying to pass in an entire object this way?

**This** is where weld.js comes to the rescue

```html











weld.addBinder('hello', function (el, msg) {
el.innerText = 'hello ' + msg;
});

weld.addBinder('helloObj', function (el, obj) {
el.innerText = (obj.greeting || 'hello') + ' ' + obj.name;
});

weld.addBinder('helloFunc', function (el, fn) {
el.innerText = fn();
});

weld.addBinder('helloMulti', function(el, name, values) {
el.innerText = (values.greeting || 'hello') + ' ' + name;
});

weld.applyBindings(); //activate weld

```

By using weld.js we've created a _declarative_ way to associate JavaScript code to our DOM. The `hello` binding will only ever be one thing, a hook between our DOM and our JS. We've also now sandboxed our code within a closure, which is key to preventing leaky state.

So next time you think of reaching for a DOM selector... "weld it, don't select it!".

## Find a bug?

There's an [issue](https://github.com/pimbrouwers/weld.js/issues) for that.

## License

Licensed under [Apache License 2.0](https://github.com/pimbrouwers/weld.js/blob/master/LICENSE).