以下に示すこの質問から参照されるノックアウト バインディング ハンドラーと一緒にブートストラップ スイッチを使用しています。
ko.bindingHandlers.bootstrapSwitchOn = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
$elem = $(element);
$elem.bootstrapSwitch();
// Set intial state
$elem.bootstrapSwitch('setState', ko.utils.unwrapObservable(valueAccessor()));
$elem.on('switch-change', function (e, data) {
// Update the model when changed.
valueAccessor()(data.value);
});
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var vStatus = $(element).bootstrapSwitch('status');
var vmStatus = ko.utils.unwrapObservable(valueAccessor());
if (vStatus != vmStatus) {
$(element).bootstrapSwitch('setState', vmStatus);
}
}
};
これは非常にうまく機能しているようで、ここでそれをどのように使用しているかを示すためにフィドルをモックアップしました:
http://jsfiddle.net/swervo/of0q42j0/5/
ただし、満足のいく方法で解決できないように見えるいくつかの問題があります。
1) ko.observable 配列にアイテムの配列がある場合、それらすべてにクリック ハンドラーを配置し、次のように親ビュー モデルで関数を呼び出させることができます。
data-bind="click: $parent.clickHandler"
これは、呼び出されると、アイテム独自のビュー モデルを通過します。これは、クリックされた項目のプロパティ (id など) を取得するのに非常に便利です。これがいかに簡単かを示すために、上のフィドルにボタンを配置しました。
ただし、単純なボタンの代わりにブートストラップ スイッチを使用している場合、スイッチは親を認識していないようで、スイッチを含むビュー モデルを親に渡すエレガントな方法を見つけることができません。ボタンでできます。配列内の各項目にその親ビュー モデルへの参照を与えようとしましたが、これは機能しますが、循環参照が作成されるため、正しいアプローチではないようです。
2)私が構築しているアプリケーションでは、リスト内のアイテムの状態を別のクライアントで変更できます-これらのリモートクライアントを反映するためにローカル状態を更新する必要があります。同様に、ローカル クライアントで状態を変更することもできます。これは、他のクライアントに伝達されます。ここでの問題は、ローカルで発生した状態の変更 (つまり、ユーザーがスイッチをクリックしたため) とリモートで発生した変更 (つまり、サーバーからの更新による変更) をどのように区別するかです。私の実際のプロジェクトでは、ノックアウト サブスクライブを使用して、次のようにスイッチにリンクされた値の変更をリッスンしています。
viewModel.observableValue.subscribe(function(newValue) {
// test value on server and if it is different update
});
スイッチが新しい状態を反映するように変更されたときに、サーバーから更新を受信してから、サーバーを (同じ状態で) 再度更新することを避けたいと考えています。現時点では、更新を送信する前にサーバーの状態をテストして (上記のコード スニペットに示されているように)、これを修正しました。保留状態の更新と同じ場合は破棄します。(上記のフィドルのボタンを使用してサーバーの更新をシミュレートしました)。
これらの問題に対する私の解決策はどちらもエレガントに感じられないため、ここで質問します。どんな助けでも大歓迎です。