10

PagerJS は URL パラメーターを取得してモデルにバインドできます。たとえば、PagerJS Web サイト (リンクを参照) のこの例では、リンクをクリックすると、そこに移動し#/user?first=Philip&last=Fry、データにバインドされたサブページが表示され、「Philip Fry」と表示されます。

<a class="btn" data-bind="page-href: {path: 'user', params: {first: 'Philip', last: 'Fry'}}">Send parameter to page</a>

<div data-bind="page: {id: 'user', params: ['first','last']}" class="well-small">
    <div>
        <span>First name:</span>
        <span data-bind="text: first"></span>
    </div>
    <div>
        <span>Last name:</span>
        <span data-bind="text: last"></span>
    </div>
</div>

これは一方向のバインディングです。ページでのユーザーの操作によってオブザーバブルが変更された場合、URL は更新されません。

PagerJS を使用するときに、URL パラメータとオブザーバブルとの同期を維持するための推奨される方法は何ですか?

もちろん、ページをリロードすることなく、ユーザーが動的に作成した検索基準を URL パラメーターに保存し、URL パラメーターに格納して、他のユーザーと URL を共有したり、ブックマークしたりできるようにしたいと考えています。

4

2 に答える 2

5

免責事項: pager.js については何も知りませんが、一般的なノックアウトの経験が役立つことを願っています。

例を見ると、pageバインディングは URL の初期値を使用してオブザーバブルを作成しているようです。私の最初の本能は、このバインディングを拡張し、これらの各値へのサブスクリプションが URL を更新することを確認することです。

このバインディングに名前を付けましょうtwoway-page:

ko.bindingHandlers["twoway-page"] = {
  init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    // Call pager.js' page binding
    ko.bindingHandlers.page.init(element, valueAccessor, allBindings, viewModel, bindingContext);

    // ...
  }
}

そして、例のバインディングでそれを呼び出します:

<div data-bind="twoway-page: {
                  id: 'start', 
                  params: ['first','last']
                 }">

を呼び出した後、ページ バインディングはビューモデルを拡張し、配列page.initで定義されたオブザーバブルをオブジェクトに追加します。これは、これらのオブザーバブルの変更をサブスクライブできることを意味します。paramsviewModel

次の課題は、正しいハッシュを計算することです。page-hrefバインディングがそのhref属性を計算する方法を調べました。andプロパティpager.page.path()を持つオブジェクトで使用されていることがわかりました。例えば:pathparams

var hash = pager.page.path({
  path: "user",
  params: {
    "first": "John",
    "last": "Doe"
  }
});

計算されたオブザーバブルで同様のオブジェクトを構築しようとしました。

// ... 
var options = valueAccessor();
var pathObj = ko.computed(function() {

    var result = {
        path: options.id,
        params: {}
    };

    options.params.forEach(function(param) {
        result.params[param] = viewModel[param]();
    });

    return result;
}).extend({ rateLimit: { timeout: 200, method: "notifyWhenChangesStop" } });

pager.js メソッドを介してハッシュを更新する「クリーンな」方法を見つけることができませんでしたが、内部的に pagerjs がlocation.hash = "newhash"値を設定するために使用していることに気付きました (history/html5 の代替手段もあるようですが...) . とにかく、オブザーバブルをサブスクライブしてハッシュを更新できます。

// ...
pathObj.subscribe(function(newValue) {
    location.hash = pager.page.path(newValue);
});

textここで、例のバインディングの代わりにバインディングを使用textInputして、値を更新できるようにします。

<div>
  <span>First name:</span>
  <input type="text" data-bind="textInput: first">
</div>

まとめとして、私の最善の推測は

  1. 既存の pager.js バインディングを拡張する
  2. URL で更新する必要があるすべてのオブザーバブルへのサブスクリプションを作成します
  3. 値が変更されたときにハッシュを自動的に更新します。rateLimit更新の過負荷を防ぐために拡張機能を使用する

ロケーション ハッシュを使って何かを行うのは、フィドルで表示するのが少し難しいため、概念実証の gif を記録しました。

カスタム pagerjs バインディングを使用したハッシュのライブ更新

完全なカスタム バインディング コードは次のとおりです。

ko.bindingHandlers["twoway-page"] = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        ko.bindingHandlers.page.init(element, valueAccessor, allBindings, viewModel, bindingContext)

        var options = valueAccessor();

        var pathObj = ko.computed(function() {

            var result = {
                path: options.id,
                params: {}
            };

            options.params.forEach(function(param) {
                result.params[param] = viewModel[param]();
            });

            return result;
        }).extend({ rateLimit: { timeout: 200, method: "notifyWhenChangesStop" } });

        pathObj.subscribe(function(newValue) {
            location.hash = pager.page.path(newValue);
        })

        return { controlsDescendantBindings: true }
    }
};
于 2016-06-02T20:40:25.980 に答える
2

コメントを追加できないため、新しい回答を追加する必要があります。 さんのとてもいい回答でuser3297291、本当に助かりました。ただし、現実の世界では次のような問題が発生します。

  1. 深いナビゲーション: ページ、サブページ、サブサブページなど。 options.idこれだけでは不十分です。完全なパスが必要です page/subpage/subsubpage(なし#!/)

  2. ページ間でいくつかの URL パラメーターを共有する場合、パラメーターが変更されるたびに、各ページでナビゲーションがトリガーされ、最後のページが表示されます。一部のページ (productID など) 間で同じ ID パラメータを共有しています。

問題 1 については、完全なパスを計算します。

...var options = valueAccessor();
var parent = pager.getParentPage(bindingContext);
var fullroute = parent.getFullRoute()();
if(fullroute.length == 0) 
    var path = fullroute.join('/')+options.id;
else 
    var path = fullroute.join('/')+'/'+options.id;

resultオブジェクトは次のようになります。

var result = {
    path: path, 
    params: {}
};

問題 2 については、アクティブなページが自分のページである場合にのみ、ナビゲーションをトリガーできることを伝える必要があります。

subscribe メソッド内で、activePage パスを計算して比較します。

pathObj.subscribe(function(newValue) {
    //calculate activePath
    var activeParent = pager.activePage$().parentPage.getFullRoute()();
    var activeId = pager.activePage$().getCurrentId();
    if(activeParent.length == 0)
        var activePath = activeParent .join('/')+activeId;
    else 
        var activePath = activeParent .join('/')+'/'+activeId;

    if( path == activePath ){
        location.hash = pager.page.path(newValue);
    }
})

また、throw パラメータをループするときは注意してください。デフォルト値を指定した場合は、配列またはオブジェクトになる可能性があります。

<div data-bind="page: {id: 'search', params: ['product','price']}" class="well">

ニーズ:

options.params.forEach(function(param) {...

<div data-bind="page: {id: 'search', params: {'product': null,'price': 0}}" class="well">

次のようなものが必要です:

Object.keys(options.params).forEach(function(key,index) { 
    result.params[key] = viewModel[key](); 
}

user3297291 の回答に感謝します。本当に違いがありました。

于 2017-02-16T11:14:54.650 に答える