Skip to content

Commit

Permalink
Merge pull request #2 from Daniel-Hug/live-binding
Browse files Browse the repository at this point in the history
add live data-binding with Snoopy
  • Loading branch information
Daniel-Hug committed Jan 20, 2016
2 parents f6d259a + 47d0331 commit 0c94e03
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 21 deletions.
39 changes: 36 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,45 @@ var label = dom({
document.body.appendChild(label);
```


### Get live DOM updates with [Snoopy](https://github.com/Daniel-Hug/snoopy)

1. include [Snoopy](https://github.com/Daniel-Hug/snoopy) before DOM builder:

```html
<script src="path/to/snoopy.js"></script>
```

2. stick data in a Snoopy instance

```js
var counter = Snoopy({count: 0});
```

3. live-bind data with DOM-Builder

```js
var button = dom({
el: 'button',
text: counter.snoop('count'),
on_click: function() {
counter.set('count', counter.count + 1);
}
});
```


### node values

Node values can be any of the following:
- **object:** creates an element
- **string:** creates a text node
- **DOM node without parent:** uses the node
- **object:** renders an element
- **string or number:** renders a text node
- **DOM node without parent:** renders the existing node
- **array of node values:** renders a document fragment
- **"snoopable" function ([Snoopy](#get-live-dom-updates) makes this easy):**
1. should accept a callback
2. call it right away passing a node value
3. call it again whenever the node value should change


### properties
Expand Down
47 changes: 44 additions & 3 deletions dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@
})(this, function() {
'use strict';

function bindSet(val, setter) {
// if val is function it's snoopable so the setter should be passed to it.
if (typeof val === 'function') {
val(setter);
} else {
setter(val);
}
}

function createDocFrag(array) {
// build each node and stick in docFrag
var docFrag = document.createDocumentFragment();
Expand All @@ -21,14 +30,35 @@
return docFrag;
}


// snoopable fn should:
// - accept a callback
// - call it right away passing a node value
// - call it again whenever the node value should change
function createDataBoundNode(fn) {
var node;
fn(function(newVal) {
//if (node instanceof HTMLElement && newVal.el === node.tagName) {
// take props from newVal and stick on node
//}
var newNode = dom(newVal);
if (node) node.parentNode.replaceChild(newNode, node);
node = newNode;
});
return node;
}

function createEl(elData) {
var el = document.createElement(elData.el || 'div');

Object.keys(elData).forEach(function(key) {
if (['el', 'text', 'kids'].indexOf(key) === -1) {
// set JS properties
if (key[0] === '_') {
el[key.slice(1)] = elData[key];
var prop = key.slice(1);
bindSet(elData[key], function(newVal) {
el[prop] = newVal;
});
}

// add event listener(s)
Expand All @@ -46,12 +76,20 @@
}

// add html attributes
else el.setAttribute(key, elData[key]);
else {
bindSet(elData[key], function(newVal) {
el.setAttribute(key, newVal);
});
}
}
});

// set text
if (elData.text) el.textContent = elData.text;
if (elData.text) {
bindSet(elData.text, function(newVal) {
el.textContent = newVal;
});
}

// otherwise add child nodes
else if (elData.kids) el.appendChild(createDocFrag(elData.kids));
Expand All @@ -72,6 +110,9 @@
// array -> document fragment
Array.isArray(nodeData) ? createDocFrag(nodeData) :

// function -> data bound DOM node
type === 'function' ? createDataBoundNode(nodeData) :

// object -> element
createEl(nodeData);
};
Expand Down
51 changes: 36 additions & 15 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,49 @@
<title>DOM Builder demo</title>
</head>
<body>
<script src="snoopy.js"></script>
<script src="dom.js"></script>

<script>
var input = dom({
el: "input",
type: "text",
placeholder: "type something",
_autofocus: true
// setup observable data
var counter = new Snoopy({count: 0});

// counter.even subscribes to counter.count
counter.snoop('count', function(val) {
counter.set('even', val % 2 === 0);
});

counter.snoop('even', function(even) {
counter.set('evenText', even ? 'even.' : 'not even.');
});
var output = dom({ el: 'output' });

document.body.appendChild(dom([
// <button>0</button>
var button = dom([
{
el: 'form',
on_submit: function(event) {
event.preventDefault();
output.textContent = input.value ? ' Text: ' + input.value : '';
},
kids: [ input, { el: 'button', text: 'Go' } ]
el: 'button',
text: counter.snoop('count'),
on_click: function() {
counter.set('count', counter.count + 1);
}
},
output
]));
{
el: 'label',
kids: [
' ',
{
el: 'input',
type: 'checkbox',
_checked: counter.snoop('even'),
_disabled: true
},
counter.snoop('count'), ' is ',
counter.snoop('evenText')
]
}
]);

// append to <body>
document.body.appendChild(button);
</script>
</body>
</html>

0 comments on commit 0c94e03

Please sign in to comment.