3

フロート チャートを更新するためのカスタム バインディングを作成しようとしてきましたが、最初に読み込まれたときに動作するように見えますが、ナビゲートすると終了します。

シナリオは次のとおりです。1つのページ(これはjQuery Mobileにあります)にリストビューがあり、グラフのサムネイルがほとんどありません。グラフの隣には、同じビューモデルのプロパティにバインドされたスライダーがあり、グラフポイントを再計算されます。リスト項目の 1 つをクリックすると、グラフのより大きなバージョンを表示する別のページに移動し、テキスト ボックスに入力して値を変更できます (後で、グラフを直接クリックできるようになります)。 . バインディングは次のようになります。

    ko.bindingHandlers["plot"] = {
        init: function (element, valueAccessor, allBindingsAccessor) {
            var qe = $(element);
            var page = qe.closest("div[data-role='page']");
            page.bind("pageshow", function () {
                ko.bindingHandlers["plot"].update(element, valueAccessor);
            });
        },
        update: function (element, valueAccessor, allBindingsAccessor) {
            var qe = $(element);
            var page = qe.closest("div[data-role='page']");
            var curr = $.mobile.activePage;
            var val = ko.utils.unwrapObservable(valueAccessor());
            var data = val.plotData();
            if(data && page.prop("id") == curr.prop("id")) {
                var marker = val.markerData();
                var opt = val.chartOptions();
                opt.yaxis.show = opt.xaxis.show = !qe.hasClass("graphThumb");
                marker.points.radius = opt.yaxis.show ? 5 : 3.5;
                $.plot(qe, [
                    data, 
                    marker
                ], opt);
            }
        }
    };

ハンドラーはinit、非表示の に描画するときに flot が正しく機能しないため、ページ ショーにグラフを描画するように設定しますdiv。更新では、現在表示されているページがバインディングのあるページと同じかどうかがチェックされ、必要に応じてグラフが再描画されます。

リスト ビューのグラフは、メソッドによってすぐに描画され、update正しく機能します。ただし、最初は非表示のページの場合、グラフを描画する関数が起動し、グラフは描画されますが、更新は機能しなくなります。さらに悪いことに、最初のページに戻ると、pageshowイベントにバインドされた関数が起動し、グラフが再描画されますが、更新も停止しています。

ビュー モデルは次のようになります。

var viewModel = (function () {
    this.current = ko.observable(0);
    this.plotData = ko.computed(function () {
        var points = [];
        // a bunch of calculations that depend on the value of current of this and other viewModels in a collection
        return points;
    }
}

計算結果にブレーク ポイントを設定するplotDataと、正しく更新されていることがわかります。これらの更新がバインディング ハンドラーをトリガーしないだけです。

HTML バインディングは次のようになります。

<!-- the first, visible page -->
<div data-role="page" id="index">
    <ul data-role="listview" data-bind="foreach: factors">
        <li data-bind="attr: {id: listId}">
            <a data-bind="attr: {href: idLink}">
                <div class="graphThumb" data-bind="plot: $data"></div>
            </a>
        </li>
     </ul>
</div>
<!-- hidden details pages -->
<!-- ko foreach: factors -->
<div data-role="page" data-bind="attr: { id: id }"> 
    <div class="graphPlaceHolder" data-bind="plot: $data"></div>
</div>
<!-- /ko -->

更新:イベント ハンドラーで を呼び出すだけで問題は解決しないことに気付いたので、バインディングを少し変更しupdateました。pageshowそれを行うと、バインディングの依存関係であるノックアウトが更新されないようです。

更新:別の更新、変数への割り当てval.plotData()が機能せず、ifステートメントに含めることもできませんでした。currentただし、親ビューモデルの値と別のプロパティに依存する別の計算されたオブザーバブルがあり、それらを取得してifステートメントに追加することができます。ただし、私の解決策は、おそらく一般的に役立つようにすることです。簡単に言うと、ノックアウトは更新ごとにバインディングの依存関係を再評価するため、条件付きロジックに関係なく重要なものを評価していることを確認する必要があります。そうしないと、更新が停止します。

4

1 に答える 1

0

この質問をまとめて回答済みとしてマークすることができるので、私の経験を簡単に要約します。

カスタムバインディングは、Knockout の計算されたプロパティと同じように実装され (KO ドキュメントによると)、計算されたプロパティが行うことの 1 つは、実行されるたびに依存しているプロパティを再評価することです。これが意味することは、計算されたプロパティ (またはカスタム バインディング) に条件がある場合、実際に実行される条件のブランチでアクセスされるプロパティのみがノックアウトによって変更を監視されるということです。たとえば、次のようなプロパティがあるとします。

var myComputedProperty = ko.computed(function() {
    if(this.myBool()) {
        $("#someElement").text(this.foo());
    }
    else {
        $("#someElement").text(this.bar());
    }
});

KO は の値を追跡しmyBool、プロパティが変更された場合は再計算しますが、myBoolが true の場合は も追跡し、が false のfoo場合は も追跡しますが、両方を追跡することはありません。に。ほとんどの場合、これで問題なく動作します。myBoolbar

私の場合、ビューモデルの一部ではない(したがって観察できない)条件があり、条件がtrueまたはtrueと評価されたかどうかに関係なく、ビューモデルのプロパティを追跡する必要があったため、失敗しました間違い。だから私はこのようなものを持っていました:

if(page.prop("id") == curr.prop("id")) {
    $("#someElement").text(this.foo());
}

idここでは、バインディングが存在するページの とjQuery Mobile によって提供された を比較しています$.mobile.activePage(明らかに観察できません)。それらidが一致する場合、ノックアウトは変更時にバインディングを更新しfooます。ただし、そうでない場合、ノックアウトは依存関係を失い、後で do が一致したfooとしてもid、依存関係が失われ、変更時に再評価されませんfoo

これを回避する方法は、条件に関係なく、追跡する必要があるすべてのプロパティが評価されるようにすることです。したがって、次のようなものが一般的なケースを解決するはずです。

if(this.foo() && page.prop("id") == curr.prop("id")) {
    $("#someElement").text(this.foo());
}

条件がまったく必要な理由は、flot が非表示の div にグラフを描画しようとすると非常に混乱するため、現在のページではないときにグラフの描画をスキップする必要があるためです。

于 2012-12-20T18:50:18.757 に答える