4

現在、ページにコントロールを形成するためのカスタム バインディング ハンドラーを作成しています。
このコントロールは、元のビューモデルを変更しないように、メイン ビューモデルの子として独自のビューモデルを生成します。(コントロールの実装はページの問題ではありません)

コードサンプル
抽象的な例を作成しました:
http://jsfiddle.net/jdarn/

JS:

ko.bindingHandlers.subBinding = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var actualValue = valueAccessor();

        ko.virtualElements.emptyNode(element);

        var subViewModel = {};
        subViewModel.subValue =
            new ko.observable(ko.utils.unwrapObservable(actualValue) * 2);

        var childBindingContext = bindingContext.createChildContext(viewModel);
        ko.utils.extend(childBindingContext, subViewModel);

        var getDomNodesFromHtml = function(html) {
            var div = document.createElement('div');
            div.innerHTML = html;
            var elements = div.childNodes;
            var arr = [];
            for(var i = 0; i < elements.length; i++) {
                arr.push(elements[i]);
            }
            return arr;
        };

        var html = '<p data-bind="text: subValue"></p>' +
            '<pre data-bind="text: JSON.stringify(ko.toJS($data), null, 4)"></pre>';

        ko.virtualElements.setDomNodeChildren(element, getDomNodesFromHtml(html));
        ko.applyBindingsToDescendants(childBindingContext, element);

        return { controlsDescendantBindings: true };
    },
    update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
    }
};
ko.virtualElements.allowedBindings.subBinding = true;

var mainViewModel = {
    value1: new ko.observable(100),
    value2: new ko.observable(200)
};
ko.applyBindings(mainViewModel, document.getElementById('main'));

HTML:

<div id="main">
    <p>Main viewmodel:</p>
    <pre data-bind="text: JSON.stringify(ko.toJS($data), null, 4)"></pre>

   <hr />

   <!-- ko subBinding: value2 -->
   <!-- /ko -->
</div>

問題bindinghandler のビューモデルで利用可能な $data は、実際には親 (メイン) ビューモデル
ですsubValueなどの他のプロパティは実際には正しくバインドされているため、これは奇妙な動作のようです。これらのプロパティは、メイン ビューモデルにはありません。

推測
私の推測では、controllesDescendantBindings はバインディングが発生した後にのみ返されます。そのため、メインのビューモデルが浸透します。KO は、代わりに mainviewmodel-context に存在する $data を優先します。

質問
(私の推測が正しいと考えて)
子ビューモデルを作成して(この場合は仮想)バインディングハンドラーの独自のコントロールにバインドする適切な方法はありますか?

4

1 に答える 1

4

ため息、重大な見落とし。

http://knockoutjs.com/documentation/custom-bindings-controlling-descendant-bindings.htmlのドキュメント ページに基づいて実装しました。

更新されたコードは
http://jsfiddle.net/jdarn/2/にあります。

変更点:

var childBindingContext = bindingContext.createChildContext(viewModel);
ko.utils.extend(childBindingContext, subViewModel);

になる

var childBindingContext = bindingContext.createChildContext(subViewModel);

createChildContext が受け入れるパラメーターを誤解しました。このパラメーターは、子のコンテキストの viewModel です。

--

コントロールの HTML スニペットは次のようになります。

var html = '<p data-bind="text: subValue"></p>' +
        'data: <pre data-bind="text: JSON.stringify(ko.toJS($data), null, 4)"></pre>' + 
        'parent: <pre data-bind="text: JSON.stringify(ko.toJS($parent), null, 4)"></pre>' +
        'root through parentcontext: <pre data-bind="text: JSON.stringify(ko.toJS($parentContext.$root), null, 4)"></pre>' +
        'root (not working): <pre data-bind="text: JSON.stringify(ko.toJS($root), null, 4)></pre>';
于 2013-10-17T09:36:36.253 に答える