kmalakoff/knockback

How to structure kb apps with requirejs

Closed this issue · 1 comments

Hey Kevin,

Was wondering if you had any thoughts on the below setup for requirejs app using knockback.

Essentially, my folder structure is:
module
-----model
---------entity.js
---------router.js
---- view
---------entity.js

The model file looks like:

define(...., function() {
 var Model = Backbone.Model.extend({...});
 var Collection = Backbone.Collection.extend({...});
 return {
     model: function(opts) { return new Model(opts); },
     collection: function(opts) { return new Collection(opts); }
});

The view files look like:

define(...., function() {
    var View = kb.ViewModel.extend({...});
    var Collection = kb.CollectionObservable.extend({...});
    var Controller = function() {
          init: function(currentRoute) {
              //return either a kb.ViewModel or a wrapper around the collection based on request
         }
    }
    return new Controller
}); 

And the router:

define(...., function() {
     self.route(/some_regex/, function(params) {
         require([relevent_view_file], function(view) {
             view.init({route: current_route}); //view here is actually the simple controller from above
         }); 
     }); 
});

This is pretty different from the setup you recommended, so I was curious to hear your thoughts. I guess my goal was to keep models & collections in the same file as they're generally very related. Also, this controller implementation is all my own doing --- I was struggling a lot with how to instantiate view models, as a view model requires a Model upon construction --- and generally, I didn't know which model to populate it with off the bat, so there needs to be some type of controller to say "pair up the view model with model, id: 5" or "pair up the collection with these 20 products"

The other approach I've been toying with is to abandon the simple controller and simply have the router make those decisions (they're generally 1-2 lines per route, so having a "controller" built for them doesn't feel completely correct)

Thanks, as always, for your thoughtful responses and for making knockback!

Hey Alan,

Thank you for getting in touch.

I first have to admit that we don't use AMD so I might not be the best person to answer this. We've been evaluating webpack as out client side packaging solution that can do a hybrid AMD and CommonJS solution (although we are currently using Brunch) so our philosophy has been to put everything in their own file to allow for easy reuse:

- app
---models
-----photo
-----photos
---view_models
-----photo
-----photos_page
-----albums_page

So we name our photos collection just photos and have it require synchronously the photo model. Plus, we would have a base photo view model that is used on all pages.

As for the router, that is an area that can be very specific to an app. I would look at the ember and angular routers to see how they try to do some level of automated model lookup.

With Knockback, you can use my Backbone.ModelRef helper if you store models in a collection (it handles both models when they are loaded and when they are not yet loaded). Alternatively, you can create a placeholder model with the id in the router (assuming you know the id from the route) and just call fetch on it and everything will just auto-populate after the model is loaded. Knockback was designed for lazy loading.

We also developed BackboneORM and typically don't even use collections much. Instead we so something like:

@photos = kb.collectionObservable({view_model: PhotoViewModel})
Photo.find query, (err, models) -> @photos.collection().reset(models)

Of course, BackboneORM is currently only supporting Node.js on the server so it might not be appropriate for you.

Let me know if this helps or if it raises more questions that you want to discuss.