2014-12-30 171 views
3

我想使用datatable knockoutjs綁定將數據呈現到表中。 我正在使用下面的鏈接和代碼將數據呈現到表中。 http://datatables.net/dev/knockout/使用knockoutjs的數據表綁定數據綁定

我在上面的例子中做的唯一變化是在渲染年齡數據時,我添加了輸入框在年齡列中記錄和在表格底部更新按鈕,以便用戶可以更改他的年齡並單擊更新按鈕數據應該自動更新,並在下一頁它應該反映在表中。

我面臨的問題是我無法更新本地js「人員」模型,因此無法使用knockoutjs綁定更新的數據。

ko.observableArray.fn.subscribeArrayChanged = function(addCallback, deleteCallback) { 
    var previousValue = undefined; 
    this.subscribe(function(_previousValue) { 
     previousValue = _previousValue.slice(0); 
    }, undefined, 'beforeChange'); 
    this.subscribe(function(latestValue) { 
     var editScript = ko.utils.compareArrays(previousValue, latestValue); 
     for (var i = 0, j = editScript.length; i < j; i++) { 
      switch (editScript[i].status) { 
       case "retained": 
        break; 
       case "deleted": 
        if (deleteCallback) 
         deleteCallback(editScript[i].value); 
        break; 
       case "added": 
        if (addCallback) 
         addCallback(editScript[i].value); 
        break; 
      } 
     } 
     previousValue = undefined; 
    }); 
};` 


`var data = [ 
    { id: 0, first: "Allan", last: "Jardine", age: 86 }, 
    { id: 1, first: "Bob", last: "Smith", age: 54 }, 
    { id: 2, first: "Jimmy", last: "Jones", age: 32 } 
]; ` 

    `var Person = function(data, dt) { 
    this.id = data.id; 
    this.first = ko.observable(data.first); 
    this.last = ko.observable(data.last); 
    this.age = ko.observable(data.age); 

    // Subscribe a listener to the observable properties for the table 
    // and invalidate the DataTables row when they change so it will redraw 
    var that = this; 
    $.each([ 'first', 'last', 'age' ], function (i, prop) { 
     that[ prop ].subscribe(function (val) { 
      // Find the row in the DataTable and invalidate it, which will 
      // cause DataTables to re-read the data 
      var rowIdx = dt.column(0).data().indexOf(that.id); 
      dt.row(rowIdx).invalidate(); 
     }); 
    }); 
}; 

    $(document).ready(function() { 

var people = ko.mapping.fromJS([]); 
    //loadData(); 

    var dt = $('#example').DataTable({ 
     "bPaginate": false, 
     "bInfo" : false, 
     "bAutoWidth" : false, 
     "sDom" : 't', 
     "columns": [ 
      { "data": 'id' }, 
      { "data": 'first' }, 
      { "data": 'age', 
       "mRender": function (data, type, row) {  
           var html = '<div style="display:inline-flex">' + 
               '<input type="text" class="headerStyle h5Style" id="ageId" value="'+data()+'"/>' + 
               '</div>'; 

            return html; 
          } 
      } 
     ] 


    }); 


    // Update the table when the `people` array has items added or removed 
    people.subscribeArrayChanged(
     function (addedItem) { 
      dt.row.add(addedItem).draw(); 
     }, 
     function (deletedItem) { 
      var rowIdx = dt.column(0).data().indexOf(deletedItem.id); 
      dt.row(rowIdx).remove().draw(); 
     } 
    ); 

    // Convert the data set into observable objects, and will also add the 
    // initial data to the table 
    ko.mapping.fromJS(
     data, 
     { 
      key: function(data) { 
      var d = data; 

       return ko.utils.unwrapObservable(d.id);   
      }, 
      create: function(options) { 
       return new Person(options.data, dt); 
      }  
     }, 
     people 
    ); 



}); 
+0

HTML代碼:<表CELLPADDING =「0 「cellspacing =」0「border =」0「class =」display cell-border「id =」example「> \t \t \t \t \t \t ID \t \t \t 名稱 \t \t \t 年齡 \t \t \t \t \t 個 \t \t \t \t \t \t

\t \t \t
\t – Guddyaaa

+0

謝謝! Carpetsmoker爲您的努力:-) – Guddyaaa

回答

1

我做了一個擺弄的解決方案

http://jsfiddle.net/Jarga/hg45z9rL/

點擊「更新」將顯示當前的淘汰賽模型下面的按鈕文本。

缺少的是通過在渲染函數中添加偵聽器將文本框的更改鏈接到可觀察對象。此外,每行的文本框被賦予相同的ID,這也不是一個好主意。 (注:事件別名只是爲了防止與其他處理衝突)

更改渲染功能構建有用IDS並添加以下應該工作:

$('#' + id).off('change.grid') 
$('#' + id).on('change.grid', function() { 
    row.age($(this).val()); 
}); 

理想的淘汰賽將您處理該問題,但由於你不是調用applyBindings,也沒有爲html元素創建數據綁定屬性,所有敲除在這裏真正給你的是可觀察模式。

編輯:附加解決方案

尋找到它一點點就可以讓淘汰賽通過添加data-bind屬性爲模板,結合你的基因敲除模型表元素處理的渲染。

var html = '<div style="display:inline-flex">' + 
    '<input type="text" class="headerStyle h5Style" id="' + id + '" data-bind="value: $data[' + cell.row + '].age"/>' 

而且

ko.applyBindings(people, document.getElementById("example")); 

此構造Person對象時也刪除整個定製預訂電話。

這裏是另一個撥弄第二方案:

http://jsfiddle.net/Jarga/a1gedjaa/

我覺得這簡化了解決方案。但是,我不知道它的執行效率有多高,也沒有使用分頁對其進行測試,因此可能需要完成額外的工作。使用這種方法,mRender函數永遠不會被重新執行,並且輸入的DOM操作完全通過敲除來完成。

+0

謝謝jarga!我會繼續你的改變。此外,您最後的評論關於applyBindings,請告訴我如何實現它? – Guddyaaa

+0

查看我的編輯是否接近您要查找的內容。 – Jarga

3

這是做它的方式......我已經顯示這一個的jsfiddle:

編輯:最近制定了一個辦法讓這個綁定使用香草淘汰賽。我已經在最新版本的knockout(3.4)上測試了這一點。只需使用這個綁定和淘汰賽數據表工作!

ko.bindingHandlers.dataTablesForEach = { 
page: 0, 
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {  
    valueAccessor().data.subscribe(function (changes) { 
     var table = $(element).closest('table').DataTable(); 
     ko.bindingHandlers.dataTablesForEach.page = table.page(); 
     table.destroy(); 
    }, null, 'arrayChange');   
    var nodes = Array.prototype.slice.call(element.childNodes, 0); 
    ko.utils.arrayForEach(nodes, function (node) { 
     if (node && node.nodeType !== 1) { 
      node.parentNode.removeChild(node); 
     } 
    }); 
    return ko.bindingHandlers.foreach.init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext); 
}, 
update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {  
    var options = ko.unwrap(valueAccessor()), 
     key = 'DataTablesForEach_Initialized'; 
    ko.unwrap(options.data); // !!!!! Need to set dependency  
    ko.bindingHandlers.foreach.update(element, valueAccessor, allBindings, viewModel, bindingContext); 
    (function() { 
     console.log(options); 
     var table = $(element).closest('table').DataTable(options.dataTableOptions); 
     if (options.dataTableOptions.paging) { 
      if (table.page.info().pages - ko.bindingHandlers.dataTablesForEach.page == 0) 
       table.page(--ko.bindingHandlers.dataTablesForEach.page).draw(false);    
      else 
       table.page(ko.bindingHandlers.dataTablesForEach.page).draw(false);    
     } 
    })(); 
    if (!ko.utils.domData.get(element, key) && (options.data || options.length)) 
     ko.utils.domData.set(element, key, true); 
    return { controlsDescendantBindings: true }; 
} 

};

JSFiddle

+0

謝謝你這個扎克!我已經測試過了,它運行良好。我對網格排序有一個小問題。在數據表中排序工作正常,但在您的實現中,通常存在於數據表中的黑色排序箭頭(顯示正在排序哪個列以及在哪個方向上)已經消失。你知道爲什麼會出現這種情況嗎? – Jonas

+0

我懷疑是因爲引導數據表使用「glyphIcons」...而我只是沒有將字體導入到小提琴中......在這裏 - > http://jsfiddle.net/zachpainter77/z8us2aej/ - >是一個jQuery具有排序箭頭的UI版本... –

+0

請對與此問題相關的pull請求留言,以便將其合併到knockout 3.4中!感謝https://github.com/knockout/knockout/pull/1856 –

0

下面是一個簡單的解決方法在於重新結合在敲除的數據,然後破壞/重新創建數據表:

// Here's my data model 
var ViewModel = function() { 
    this.rows = ko.observable(null); 
    this.datatableinstance = null; 

    this.initArray = function() { 
      var rowsource1 = [ 
        { "firstName" : "John", 
         "lastName" : "Doe", 
         "age"  : 23 }, 

        { "firstName" : "Mary", 
         "lastName" : "Smith", 
         "age"  : 32 } 
        ];   
     this.redraw(rowsource1); 

    } 

    this.swapArray = function() { 
     var rowsource2 = [ 
         { "firstName" : "James", 
         "lastName" : "Doe", 
         "age"  : 23 }, 

         { "firstName" : "Alice", 
         "lastName" : "Smith", 
         "age"  : 32 }, 

         { "firstName" : "Doug", 
         "lastName" : "Murphy", 
         "age"  : 40 } 

        ];  
     this.redraw(rowsource2); 
    } 

    this.redraw = function(rowsource) { 
     this.rows(rowsource); 


     var options = { paging: false, "order": [[0, "desc"]], "searching":true }; 
     var datatablescontainer = $('#datatablescontainer'); 
     var html = $('#datatableshidden').html(); 

     //Destroy datatable 
     if (this.datatableinstance) { 
     this.datatableinstance.destroy(); 
     datatablescontainer.empty(); 
     } 

     //Recreate datatable 
     datatablescontainer.html(html); 
     this.datatableinstance = datatablescontainer.find('table.datatable').DataTable(options);  
    } 

}; 

ko.applyBindings(new ViewModel("Planet", "Earth")); // This makes Knockout get to work 

https://jsfiddle.net/benjblack/xty5y9ng/