Backbone.Marionette / progressive model loading strategy - backbone.js

I'm working on an analytics-like dashboard with heavy data. Obviously waiting for all this data to come in isn't a good idea as it would increase load-times beyond acceptable lengths. My idea is to progressively add parts of data when certain Controllers instantiate a model. I imagine it'll end up looking something like this:
class List.Controller extends Marionette.Controller
initialize: (options) ->
{ model } = options
model.fetch( something here ) unless model.get('data')
#showData model
getDataView: (model) ->
new List.Data {model}
showData: (model) ->
dataView = #getDataView model
App.mainRegion.show dataView
I was wondering if someone has experience with this, and what a good strategy would be for what to pass into the fetch call and how to structure that...
Edit: to clarify, I'm looking for a scalable strategy to load more data for a model based on a get-param or a different endpoint when my app needs it. Should this be handled by methods on my model or by passing stuff into fetch for example?

The "standard" way is having a pageable collection, such as Backbone Pageable
Then you can have a CollectionView or CompositeView which will handle most of the work for you.

Related

backbone js using multiple collection in view

I am quite new in backbone js . I was reading the documentation of backbone and I come up with this idea to use multiple collection in view.
If I have single view and I want to use more than one collection how can I achieve it?
how can the view understand multiple collection?
thanks.
Why do you ever need to use multiple collection inside a single view? Backbone's strength is it's modularity, which means you can develop the whole structure of your application by building it's components piece-by-piece. So in normal circumstances one view has one model or collection of models, but it's acceptable and it's often used the case when a collection has multiple views (for example a chat system).
To have multiple collections inside a single view is against backbone's modularity principle. Breaking up views to respond to only one model/collection turns out much more modular and reusable code.
So i suggest to break up your application into smaller pieces and operate on segment level, but if you really need to preserve the current structure you can do something like this:
var view = new MyView({
collection: {
users: new UsersCollection(),
organization: new OrganizationCollection()
}
});

What's the best practice for handling loading child resources in ngResource?

Context: I'm new to Angular, and this feels like a lot more of a "What's the right way to do this in AngularJS" kind of question.
My API backend has a couple of related objects that I need to request and assemble into a coherent user interface. It can be modeled as a subscription hub thing, so I have: Subscription hasMany Subscription_Items, belongsTo Source.
What I want to do is look up a user's Subscriptions (/api/subscriptions?user_id=1), which gives me some JSON that includes a subscription_item_ids=[1,2,3 ...] array. I then want to query on those ids, as well as query the server on source_id to pull shared info, and then repackage everything nicely into the $scope so the view layer has easy access to the system and can do stuff like ng-repeat="item in subscription.subscription_items" inside an outer ng-repeat="subscription in subscriptions".
Conceptually this makes sense, and I've thought of a few ways to load this linked data, but what I'm curious about is: what's the best practice here? I don't want to excessively reload the data, so it seems like a plain old function that does a REST request every time I look at an item is a bad idea, but at the same time, I don't want to just push the data in once and then miss out on updates to items.
So, the question is: what's the best way to handle linked resources like this, to trace hasMany and belongsTo types of connections out to other models in a way that aligns with the ideas embedded in $scope and the $apply cycle?
I like to use a lazy-loaded dataModel service which will cache results and return promises. The interface looks like this:
dataModel.getInstitution(institutionId).then(manageTheInstitution);
If I need something that is a child, I call it like this:
dataModel.getStudents(institutionId).then(manageStudents);
Internally, getStudents looks something like this:
function getStudents(institnutionId) {
var deferred = $q.defer();
getInstitnution(institutionId).then(function(institution) {
institution.students = Student.query({institutionId: institutionId});
institution.students.$promise.then(function(students) {
deferred.resolve(students);
});
});
return deferred.promise;
}
These functions are a bit more complex. They cache the results and don't request them again if they already exist... and return or chain the existing promise. They also handle errors.
By carefully crafting my dataModel service this way, I can manage any nesting of resources and I can optimize my network requests. I've been very happy with this approach so far.

Why do BackboneJs Collections have URL's?

I'm starting to use backbone.js and I'm confused as to why you can specify url's in a bunch of different ways. It doesn't seem like the collection url is used anywhere except in the model url function. So is there any harm in just setting urlroot on all of my models and never using collection urls?
there is no harm at all, you can work perfectly fine at the model level doing updates, deletes etc, but when you want to GET a set of models from the server all at once it comes handy to do something like this.
Books = Backbone.Collection.extend({
url : "/books"
});
books = new Books();
books.fetch(); // this will line will make a GET request to your backend, the result will
// be a list of models.
In Backbone.js, Models and Collections are related to 'structuring' data, and Backbone provide methods for doing this. With Restful routes, you most often need updates/fetches like this:
GET /students
[{name: "...", ...}]
GET /students/1
{name: "..."}
As you observed, the URLs are similar, but in most cases processing the response of a Collection and Model fetch, will look different. Since conceptually, Models are part of a Collection, Model URLs can in most cases be resolved from the collection. There are other APIs where models and collection don't match, and you need to set the URLs yourself (e.g. a session model, that does not belong to a collection)
Maybe it also helps to compare the documentation for the Model and Collection fetch:
http://backbonejs.org/#Collection-fetch
http://backbonejs.org/#Model-fetch
This might also help to understand the Backbone way of thinking: http://jonathanotto.com/blog/backbone_js_for_the_everyman.html

Passing data from main application view to some subviews

Please consider following Backbone application structure:
AppView
Subview
FirstSubviewInQuestion
Subview
Subview
SecondSubviewInQuestion
Application view creates and stores a collection of special items. At a certain time the first and the second subview needs to get access to that collection. Now what is the best way to pass the collection it to them?
I myself see some ways, yet each has a downside:
1) Create instance of that collection not inside the App View but even more globally and then pass it around as dependency (project uses RequireJS; so it would be passed to AppView and both Subviews).
Downsides: app view is supposed to be the top most element in application. Yet suddenly we have some instances of collections floating above.
2) Or I can do following:
// some subview
var collection = {};
Backbone.trigger( "item:getSpecialItems", collection);
// now the collection has data
// app view
this.listenTo( "item:getSpecialItems", function(obj) {
// copy collection to passed object
_.extend(obj, this.specialCollection);
});
Downsides: we are triggering a global event. We know that only the app view would respond, but it feels like a bad design. Plus, this way to pass the collection seems like a hack.
Maybe there are some other clever ways to do it?
I would say #1.
app view is supposed to be the top most element in application
Right, but you're talking about (I think) a Collection, not a View; the two are totally separate parts of your application (in MVC the first is the "M" and the second is the "V"). By definition, if your views are driven by your data, the data must be "higher" (in the dependency tree) than any view, so I don't see anything wrong with that approach.
If your goal is to get a shared instance of the collection, my approach would be to pass that down from the parent to "subview" and from subview into its children. However, I wouldn't necessarily use require to pass around a singleton of this collection.
You could also pull out all of the logic from the view regarding the special methods for "creation and storage of special objects" into a helper class whose sole domain is just this. That helper then becomes a utility available from outside the view hierarchy, perhaps even globally or via require.

Should views set model data?

I'm just trying to figure out a probably simple question.
Should views set model data directly or only call model methods that change their own data?
like everything else in software development, "it depends".
if you're using form inputs in your views and you just need to get the data from those inputs in to the models, set the data directly. You can do this any number of ways, including "change" events from the input fields, like this:
MyView = Backbone.View.extend({
events: {
"change #name", "setName"
},
setName: function(e){
var val = $(e.currentTarget).val();
this.model.set({name: val});
}
});
On the other hand, if you're kicking off business logic and other code that happens to set the data in the model (but really only does this as part of the business logic), then you should call a method on the model.
A "state machine" would be a good example of when you would do this. Or, in an image gallery that I wrote, I had some logic around the selection of an image for display. If an image is already selected, don't select it again. I put this logic in a method on my image model:
Image = Backbone.Model.extend({
select: function(){
if (!this.get("selected")){
this.set({selected: true});
}
}
});
As illustrated here, I like to run by the simple rule that if I have zero logic around the call to set, then I set it directly from wherever I am. If there is any logic related to the model, around the set, then I put it in the model.
Either way, when you do want to set data, you should use the set method. Bypassing this and setting the model's attributes directly through model.attributes will prevent a lot of Backbone's code from firing and potentially cause problems for you.
That depends on your programming style. I always set them directly. If the Law of Demeter sounds good to you and you're into object orientation (and possibly with a Java/Microsoft -stack background), then the style would be to create getter/setter methods.
If you on the other hand is in the "Size is the Enemy" camp (I also recommend Jeff Atwood's comments) the you certainly should set model data directly (as I hinted before, I'm in this camp myself).
That being said, Backbone.js models already have getter and setter methods .get and .set. You should not manipulate the .attributes member directly. I'm not as sure you shouldn't read from it, I tend to do that now and then and haven't run problems because of that yet.

Resources