2014-12-03 9 views
10

PagerJS può raccogliere i parametri URL e associarli al modello. Per esempio, in questo esempio, dal sito web PagerJS (see link), quando si fa clic sul link, si navigherà a #/user?first=Philip&last=Fry e apparirà la pagina secondaria associazione a dati, visualizzando "Philip Fry":PagerJS come eseguire "binding a due vie" con i parametri URL?

<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> 

Questo è un legame unidirezionale: se l'osservabile cambia, a causa delle azioni dell'utente sulla pagina, l'URL non verrà aggiornato.

Qual è il modo consigliato di mantenere i parametri URL in sincronia con le osservabili quando si utilizza PagerJS?

Desidero memorizzare i criteri di ricerca creati dall'utente dinamicamente, prodotti selezionando un gruppo di controlli dell'interfaccia utente, nei parametri URL in modo che lui/lei possa condividere l'URL con altri o aggiungerlo ai segnalibri, il tutto senza ricaricare la pagina , ovviamente.

+0

+1 a questo. IMO, la soluzione migliore non sarebbe esplicitamente legata ai controlli (ad es.i controlli non producono navigazioni, ma inoltrano le loro modifiche alla pagina viewmodel, che può tranquillamente assumere la propria esistenza e navigare verso una versione diversa di se stessa). – TheHansinator

risposta

5

Disclaimer: Non so nulla di pager.js, ma spero che la mia esperienza generale a eliminazione diretta possa ancora essere d'aiuto.

Osservando l'esempio, il legame page sembra creare osservabili utilizzando i valori iniziali dall'URL. Il mio primo istinto sarebbe quello di estendere questo legame e assicurarmi che un abbonamento a ciascuno di questi valori aggiorni l'URL. Nome

Let questo legame 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); 

    // ... 
    } 
} 

e chiamarlo sull'esempio è vincolante:

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

Dopo aver chiamato page.init, la pagina di legame ha esteso il ViewModel, aggiungendo le osservabili definiti nel params per l'oggetto viewModel. Ciò significa che possiamo sottoscrivere i cambiamenti in questi osservabili.

La prossima sfida è calcolare l'hash giusto. Ho osservato come l'associazione page-href calcola il suo attributo href. Risulta che utilizza pager.page.path() su un oggetto con una proprietà path e params. Es .:

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

Ho cercato di costruire un oggetto simile in un osservabile calcolato.

// ... 
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" } }); 

non riuscivo a trovare un modo "pulito" per aggiornare l'hash tramite un metodo pager.js, ma ho notato che internamente, pagerjs utilizza location.hash = "newhash" per impostare un valore (anche se ci sembra anche essere un history/html5 alternative ...). Ad ogni modo, siamo in grado di iscriversi alla nostra osservabile per aggiornare l'hash:

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

Ora, al posto dei text attacchi dalla esempio, useremo textInput attacchi in modo che possiamo aggiornare i valori:

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

Quindi, per concludere: la mia ipotesi migliore sarebbe quella di

  1. Estendere un cercapersone esistente.js binding
  2. Creare sottoscrizioni a tutti gli osservabili che devono essere aggiornati nell'URL
  3. Aggiorna automaticamente l'hash quando i valori cambiano; utilizzare l'estensione rateLimit per evitare un sovraccarico di aggiornamenti

fare cose con l'hash posizione è un po 'difficile da mostrare in un violino, così ho registrato un gif della mia prova di concetto:

live updating the hash using a custom pagerjs binding

Il codice completo personalizzato vincolante è:

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 } 
    } 
}; 
2

non posso aggiungere un commento in modo devo aggiungere una nuova risposta. Risposta molto bella da user3297291, mi ha davvero aiutato molto. Tuttavia, alcuni problemi sorgono nel mondo reale, ad esempio:

  1. profonde di navigazione: pagine, sottopagine, subsubpages, ecc il options.id non è sufficiente, abbiamo bisogno il percorso completo page/subpage/subsubpage (senza #!/)

  2. quando si condividono alcuni parametri URL tra le pagine, ogni volta che il parametro cambia, ogni pagina attiverà una navigazione, l'ultima verrà visualizzata. Condivido gli stessi parametri ID tra alcune pagine (productID, ecc.).

Per il rilascio 1, calcola percorso completo:

...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 oggetto si trasforma in:

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

Per il rilascio 2, dobbiamo dire loro che possono innescare solo una navigazione quando la pagina attiva è la loro.

All'interno del metodo iscriversi, si calcola il percorso ActivePage e li confronta:

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); 
    } 
}) 

Inoltre, fate attenzione quando loop params tiro, può essere un array o un oggetto se avete fornito valori di default:

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

esigenze:

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

Vs

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

ha bisogno di qualcosa di simile a:

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

Grazie ancora a user3297291 per la risposta, ha fatto davvero la differenza.

Problemi correlati