Pergunta

I just started messing with Knockout JS, and I have the following scenarion (example).

I have a list of tourists, and that list has CRUD methods - all works great. Now, when I click a tourist, a more detailed description shall be presented - this is a new AJAX call to the server for that info.

My question is, should I have 1 Master view model that contains my TouristsViewModel and TouristsInfoViewModel - which means that the TouristsViewModel should be coupled with the master in order to modify the TouristsInfoViewModel, or should my TouristsViewModel instantiate the TouristsInfoViewModel and call ko.applyBindings?

I've looked at Knockout-postbox, but I'd like to avoid having to introduce too many 3rd party plugins.

To summarize: What's the general approach to separating views and viewmodels while being able to share data between them?

Foi útil?

Solução

Here is a general approach.

  1. Invest your time in to learning about AMD and require.js is a great library for just that.
  2. Keep your viewmodels separate and don't couple them.
  3. knockout-postbox, amplify.js pub/sub work great in communicating with each other.
  4. Look at a Single Page Application framework. Durandal is a great option.
  5. If you are not planning to use Durandal or a SPA, even then, create a separate module that will handle your binding with knockout.
  6. Each view should have a corresponding viewmodel.
  7. Separate out your ajax calls in to modules of its own. ex: touristsRepository.js could be a module that is going to make all the ajax calls for you.
  8. Work with promises. Q.js or jquery's deferred promises will help you out. Your repositories should return promises.
  9. Your viewmodels should be just that... in essence, it should hold state and provide view interaction handlers. The model should be it's own file. The ViewModel can then hold the model data.
  10. The model data should be retrieved only via the repositories.

I think this would be a decent approach and something that will work for you.

EDIT - Adding more based on the comment.

1) You can use shimming and exports in requirejs to load ko validation plugin, instead of using define. Unless you are not using requirejs to load it in the first place.

2) Using a pub/sub is not coupling. Coupling happens when one module depends completely on another's functionality or existence. Considering MasterViewModel is directly communicating with another viewmodel is coupling. In a pub/sub scenario, your one viewmodel (call it Persons.js) is say saving a person object. Once it saves, it is supposed to update the local cache. In this case, Persons.js, after it saves, sends out a message saying "Person saved" and pass any data it has. The ClearCache.js is the one responsible for clearing the cache. It is only listening for a "Person saved" message to take some action. The coupled way would be for Persons.js to instantiate ClearCache and call it's clearCache method directly. So, for Persons.js to exist, clearCache.js must exist. Where as, in pub/sub, even if clearCache.js does not exist, Persons.js can continue to exist.

3) An answer to this question totally depends on your application requirement. Typically, I have a intermediate module called binder.js. binder.js, listens for messages. So, let's say the user wants to see detailed info and clicks on a tourist. The TouristsViewModel is going to publish a message "Tourist Detail Requested" and pass a tourist id or some information. The binder, is listening for this, knows which viewmodel to instantiate and what action to take. That way, your ToursistsViewModel is completely ignorant of TouristsInfoViewModel. If on another view, you are listing all the tourists firstNames and lastNames and don't have to show details, you can re-use TouristsViewModel without having to unnecessarily bring in TouristsInforViewModel. A MasterViewModel in this case is not needed.

Your application sounds like a perfect candidate for a Single Page Application. Follow a "One View - One ViewModel" approach and a "Single Responsibility" approach. TouristsViewModel is showing only tourists, TouristInfoViewModel will show tourist info. Both of them have no clue about each other. I recently worked on a project which had similar requirements. Speakers, speaker details, Sessions, session details. None of my viewmodels know about the other. They are all managed via client side routes and hash change events.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top