2016-12-05 6 views
0

サンプルコードはこちらです。 https://jsfiddle.net/zLnuyk3w/4/observableArray.removeが手動でhtml変更された後正しく動作しない

function ViewModel(){ 
    var self = this; 
    var ids = [ 
    { id:50, order:1}, 
    { id:25, order:2}, 
    { id:35, order:3} 
    ]; 
    var list = ko.observableArray(ids); 
    self.sortedList = ko.observableArray(); 
    ko.computed(function(){ 
    var computedList = list().sort(function(l, r){ 
     return l.order < r.order ? -1 : 1; 
    }); 
    self.sortedList(computedList); 
    }); 
    self.addNewItem = function(){ 
    list.push({id: 40, order:2}); 
    } 
    self.deleteItem = function(item){ 
    list.remove(item); 
    }  
} 
var vm = new ViewModel(); 
ko.applyBindings(vm); 

$('tbody').sortable({ 
update: function(event, ui) { 
    // vm.list().updateOrder(); // somehow update 'order' property but for simplicity reason, omit the actual code 
    vm.list.valueHasMutated(); 
} 
}); 
$("tbody").disableSelection(); 

私は基本的にjqueryのUIソート可能なプラグインを用いて手でテーブルの行をソートしたいです。しかし、手でソートしてobservableArrayから項目を削除しようとすると、removeは正しく機能しません。

関連する問題を徹底的に調べて、ko.cleanNodeを呼び出した後でビューモデルを再バインドする必要があるようです。それがこの問題を解決する唯一の方法ですか?私は実際に私が再生しているデータは動的に生成され、ビューは多くのテンプレートを使用するので、このアプローチを避けたいので、要素を再バインドするための正しいデータを渡すのはかなり複雑です。

+1

ノックアウトのためのjQuery UIのソート可能なバインディングが存在します。あなた自身を転がしてはいけません。 https://github.com/rniemeyer/knockout-sortable – Tomalak

+0

ああ私はそれを知らなかった。あなたの情報をありがとう。私はそれを調べます。 –

+0

結論:最初は思っていた以上に複雑です。 – Tomalak

答えて

0

Tomalakそれは私が考えて、彼が私を指摘したカスタムバインディングは非常によく働いていた以上に複雑だと述べています。
https://github.com/rniemeyer/knockout-sortable

後でサンプルコードを投稿します。

EDIT
私は今回のみのサンプルコードでフィドラーするために、ローカルのjsファイルを追加する方法を見つけ出すことができませんでした。 knockout-sortable.jsを参照すると、あなたのために仕事が完了します。この場合、リスト内のアイテムの位置がカスタムバインディングによって実際に変更され、それが私が望むものなので、計算されたオブザーバブルは必要ありませんでした。もちろん、他のアクションでリストの順序を変更したい場合は、ソートのために計算されたオブザーバブルが必要です。

<table> 
<tbody data-bind="sortable: list" > 
<tr> 
    <td data-bind="text:id"></td> 
    <td ><button data-bind="click:$root.deleteItem"> 
    delete 
    </button></td> 
</tr> 
</tbody> 
</table> 

function ViewModel(){ 
    var self = this; 
    var ids = [ 
    { id:50}, 
    { id:25}, 
    { id:35} 
    ]; 
    self.list = ko.observableArray(ids); 
    self.deleteItem = function(item){ 
    self.list.remove(item); 
    } 
}  
ko.applyBindings(new ViewModel()); 
2

問題はあなたが思うよりも簡単で、そしてないが関連ノックアウト:

あなたが同じorderインデックスを持つ項目について0戻っていません。ソート方法を次のように変更してください。

return l.order === r.order ? 0 : l.order < r.order ? -1 : 1; 

ここで、項目を追加すると、テーブルが正しく並べ替えられます。 orderのプロパティを動的に変更する場合は、何らかの外部ロジックによって、observableにする必要があります。あなたはここから行くよ:

self.sortedList = ko.pureComputed(function() { 
    return list().sort(function(l, r){ 
     return l.order === r.order 
      ? 0 
      : l.order < r.order ? -1 : 1; 
    }); 
}); 

この目的のために:

self.sortedList = ko.pureComputed(function() { 
    return list().sort(function(l, r){ 
     var oL = l.order(), 
      oR = r.order(); 
     return oL === oR 
      ? 0 
      : oL < oR ? -1 : 1; 
    }); 
}); 

さて、いつでもlistまたはそのアイテムorderプロパティの変更の1のいずれか、リストが再ソートされます。

これが機能しない場合や必要でない場合は、問題はおそらくjQueryウィジェットにあります。あなたのhtmlから要素を削除する場合、ノックアウトはその接続を失う可能性があります。 (例えば、要素のクローニングと並べ替えによってソートする場合)

update関数にウィジェットを再適用するカスタムバインディングハンドラを記述するか、またはプラグインを削除してIのようなシステムを使用して解決できます'mを記述する。この例をチェックアウト:

function ViewModel() { 
 
    var self = this; 
 
    var ids = [{ 
 
    id: 50, 
 
    order: ko.observable(1) 
 
    }, { 
 
    id: 25, 
 
    order: ko.observable(2) 
 
    }, { 
 
    id: 35, 
 
    order: ko.observable(3) 
 
    }]; 
 
    var list = ko.observableArray(ids); 
 
    self.sortedList = ko.observableArray(); 
 
    ko.computed(function() { 
 
    var computedList = list().sort(function(l, r) { 
 
     var lO = l.order(), 
 
     rO = r.order(); 
 
     return lO === rO ? 0 : lO < rO ? -1 : 1; 
 
    }); 
 
    self.sortedList(computedList); 
 
    }); 
 
    self.addNewItem = function() { 
 
    list.push({ 
 
     id: 40, 
 
     order: 0 
 
    }); 
 
    } 
 
    self.deleteItem = function(item) { 
 
    list.remove(item); 
 
    } 
 

 
} 
 
var vm = new ViewModel(); 
 
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> 
 
<table> 
 
    <tbody data-bind="foreach: sortedList"> 
 
    <tr> 
 
     <td data-bind="text:id"></td> 
 
     <td> 
 
     <label>order: 
 
      <input type="number" data-bind="value: order"> 
 
     </label> 
 
     </td> 
 
    </tr> 
 
    </tbody> 
 
</table>

+0

これはおそらく問題の1つですが、実際には計算されたソートされたリストを使用しなくても正しく動作しません。そしてあなたのコードは悲しいことにも役に立たなかった。とにかくありがとう –

+0

実際には、あなたのフィドルで、それは動作するようだ:https://jsfiddle.net/sh6dfd4c/私の答えにいくつかの説明を追加します...希望が助けてくれるだろう – user3297291

+0

編集のコードうまくいかない場合、問題はjQueryプラグインにあります。 DOMからデータバインドされた要素を削除すると、ノックアウトによってテーブルへの接続が失われる可能性があります。 – user3297291

関連する問題