Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery TwoWay Data Binding

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?

like image 654
kayz1 Avatar asked Mar 09 '13 10:03

kayz1


People also ask

How can two-way binding in jQuery?

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').

How to achieve two-way data binding in JavaScript?

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.

How to Bind the data in JavaScript?

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).

What is 2 way binding in JS?

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.


2 Answers

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"));

Result

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.

like image 133
kayz1 Avatar answered Oct 20 '22 10:10

kayz1


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.

like image 23
Fery Kaszoni Avatar answered Oct 20 '22 09:10

Fery Kaszoni