2013-03-09 4 views
18

Jak zaimplementować proste dwukierunkowe powiązanie danych w jQuery? Coś jak knockoutJS, ale w najprostszej możliwej formie.jQuery TwoWay Data Binding

Scenariusz - należy powiązać obiekt JSON z rzędem tabeli (każde pole to td> input />/td>).

Wszelkie sugestie?

+2

Powinieneś podać bardziej konkretny przykład i kilka prób. – soyuka

+1

Zrobiłem. Sprawdź moją własną odpowiedź. Wszelkie sugestie, sztuczki? – kayz1

+0

http://jquerymy.com/ –

Odpowiedz

11

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

Użyłem niesamowite Watch.JS. How Does Watch.js Work?

Watch.js now uses Object.observe

Oto kolejny przykład Easy Two-Way Data Binding in JavaScript.

I jeszcze question.

Native JavaScript Data-Binding.

+2

Watch.JS wygląda ładnie, ale korzysta z setInterval do okresowych kontroli. To nie może być dobre dla wydajności ... –

+2

Teraz używa Object.observe, jeśli jest obecny. – kayz1

+0

Awesome! Czekam na testowanie Watch.js w świetle tej nowej funkcji! –

2

To rozwiązanie jest bardzo proste, a to może być przedłużony, aby mieć bardziej złożoną funkcjonalność: http://cssshowcase.co.uk/two-way-data-binding-with-jquery/

Dosłownie wiąże 2 lub więcej elementów HTML razem z jego obecna forma zmienia wewnętrzną html jakiegokolwiek elementu i wartość dowolnego wejścia również dla każdego elementu, który ma tę samą wartość atrybutu "wiązania".