How do you implement a simple two-way data binding in jQuery? Something like knockoutJS, but in the simplest possible form.
Scenario - bind JSON object to table row (every field is td>input/>/td>).
Any suggestions?
Create bindings. $('#form'). bindings('json')('#model-selector'); // or $('#form'). bindings('json')('#model-selector', '<input type="text" data-model="firstname" /><span>your firstname: <b data-model="first-name"></b></span>'); // or $('#form').
To create a two-way data binding, we will create an object's property with a getter and a setter function. Mainly the setter function of the object to update the value of the corresponding HTML element. We will be using Object. defineProperty to define the getter and setter for an object's property.
JavaScript Function bind()With the bind() method, an object can borrow a method from another object. The example below creates 2 objects (person and member).
Two-way binding is a strategy to simplify the synchronization between a JavaScript reference and the HTML element value and vice versa. That means every change in the self property value reflects in the HTML element value, and every change in the HTML element value propagated back to the self.
My try - HTML
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Data Binding</title>
</head>
<body>
<table id="content-table">
<thead>
</thead>
<tbody></tbody>
</table>
<button id="get-data">Get</button>
<button id="set-data">Set</button>
<script src="../js/vendor/jquery-1.9.1.js"></script>
<script src="../js/vendor/jquery-migrate-1.1.1.js"></script>
<script src="../js/vendor/watch.js"></script>
<script src="../js/dataBinder.js"></script>
</body>
</html>
JavaScript
var DataBinder = (function ($) {
var _$table = null,
_objectList = [],
_fieldList = [],
_objectListLength = -1,
_fieldListLength = -1;
/* AJAX call or smth. */
var _loadData = function () {
var fakeData = [{
name: 'John',
surname: 'Doe'
}, {
name: 'Foo',
surname: 'Bar'
}];
_objectList = $.map(fakeData, function (element, index) {
var elementObject = {
_dataBinderId: index,
element: element,
input: {}
};
watch(elementObject.element, function (property, action, newValue) {
_setValue.call(elementObject, property, newValue);
});
return elementObject;
});
_objectListLength = _objectList.length;
};
var _getFields = function () {
for (var i = 0; i < _objectListLength; i++) {
for (var field in _objectList[i].element) {
if (!!!~$.inArray(field, _fieldList)) {
_fieldList.push(field);
}
}
}
_fieldListLength = _fieldList.length;
};
var _setValue = function (field, value) {
this.input[field].val(value);
};
var _bindEvents = function () {
$('#get-data').on('click', function () {
alert(JSON.stringify(_getRowData()));
});
$('#set-data').on('click', function () {
_objectList[0].element.name = 'PIPA';
_objectList[1].element.surname = 'BLAAAAAAH';
});
_$table.on('keyup', 'input', function () {
var $this = $(this), field = $this.data('field'), source = $this.closest('tr').data('source');
source[field] = $this.val();
});
};
var _getRowData = function () {
var elements = [];
$.each(_objectList, function () {
elements.push(this.element);
});
return elements;
};
var _generateEditableElements = function () {
var rowList = [], headerRow = $('<tr>');
for (var k = 0; k < _fieldListLength; k++) {
headerRow.append($('<th>', {
text: _fieldList[k].toUpperCase()
}));
}
_$table.find('thead').append(headerRow);
for (var i = 0; i < _objectListLength; i++) {
var objectData = _objectList[i], currentRow = $('<tr>');
currentRow.data('source', objectData.element);
rowList.push(currentRow);
for (var j = 0; j < _fieldListLength; j++) {
var field = _fieldList[j], $inputElement = $('<input>', {
type: 'text',
value: objectData.element[field]
});
$inputElement.data('field', field);
objectData.input[field] = $inputElement;
currentRow.append($('<td>').append($inputElement));
}
}
_$table.find('tbody').append(rowList);
};
var init = function ($table) {
_$table = $table;
_loadData();
_getFields();
_generateEditableElements();
_bindEvents();
};
return {
init: init
};
})(jQuery);
DataBinder.init($("#content-table"));
I've used amazing Watch.JS. How Does Watch.js Work?
Watch.js now uses Object.observe
Here is another example Easy Two-Way Data Binding in JavaScript.
And another question.
Native JavaScript Data-Binding.
This solution is pretty simple, and it can be extended to have a more complex functionality: http://cssshowcase.co.uk/two-way-data-binding-with-jquery/
It literally binds 2 or more HTML elements together, with it's current form it changes the inner html of any element and the value of any input as well, for each element that holds the same "bind" attribute value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With