jQuery双向数据绑定

27
如何在jQuery中实现简单的双向数据绑定?类似于knockoutJS,但是以最简单的形式。
场景- 将JSON对象绑定到表格行(每个字段都是标签)。
有什么建议吗?

2
你应该给出一个更具体的例子并进行一些尝试。 - soyuka
2
我已经检查了自己的答案。有什么建议或技巧吗? - kayz1
2
http://jquerymy.com/ - Clay Smith
3个回答

15

我的尝试 - 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"));

结果

我使用了惊人的Watch.JSWatch.js如何工作?

Watch.js现在使用Object.observe

这里是另一个例子:JavaScript中简单的双向数据绑定

还有一个问题

本地JavaScript数据绑定


2
Watch.JS看起来不错,但它使用setInterval进行定期检查。这对性能肯定不利... - John Slegers
2
现在如果可用,它使用Object.observe。 - kayz1
太棒了!我很期待在这个新功能的基础上测试Watch.js! - John Slegers
使用jQuery的delegate { on() }也可以实现这个功能吗? - daslicht
1
多年来我所看过的最好的问题和答案! - Rob Sutcliffe

4
这个解决方案非常简单,它可以扩展到更复杂的功能:http://cssshowcase.co.uk/two-way-data-binding-with-jquery/。它能够将2个或多个HTML元素绑定在一起,当前形式下,对于每个具有相同“bind”属性值的元素,它会改变任何元素的内部html和任何输入的值。

0

以下这段jQuery代码似乎像是AngularJS中的双向绑定

<script purpose="Setting value for total cost">
    $(document).ready(()=>{ 
        var sumTotalCost = () => {
            var val1 = +$("#base_salary").val();
            var val2 = +$("#on_cost").val();
            $("#total_cost").val(val1 + val2);
        }
        $(".sumtotal-elements").keyup(function () {
            sumTotalCost()
        });
    })
</script>

<input class="form-control sumtotal-elements" type="text" name='base_salary'id="base_salary">

<input class="form-control sumtotal-elements" type="text" name='on_cost' id="on_cost">

<input class="form-control" type="text" name='total' id="total_cost" >

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接