Most of the open Backbone.js single–page apps and demos out there seem to deal with one or maybe two different resources and usually populate the collections in questions when initially loading the page.
How do you guys deal with multiple (more than 2 or 3) different resources having their data stored remotely? When do you load the content?
An example which should sound familiar to Rails devs:
A current_user object exists, having has_many associations to Project, Team, Task and Invoice models. My client–side app provides some kind of CRUD functionalities for these models, maybe some additional views to connect stuff, etc., having in total many different views and corresponding routes.
I want the user to be able to jump straight to any of these routes by e.g. pasting a link, let's say /#project/34/invoices, which would require the app to have the Project with ID 34 loaded as well as the invoices connected to this project.
How do people solve this issue, given that you can easily end up having many cases like this within a single app? Are you just loading everything initially
current_user: {
projects: {
invoices: {…},
tasks: {…}
tasks: {…}
…
}
which doesn't seem clean to me, or do you have a clever way to always load what you need?
Cheers!
One approach is to load enough at start-up to do most high-level tasks. Thereafter, lower-level tasks might need to perform fetches to get detail-level resources.
In a travel management app, you might establish a session for a user and get the user and any reservations that user has. This would enable you to quickly show reservation summaries without having to make additional server calls.
Requests for more detailed reservation data might require a lower level call. For instance, if I have a flight reservation, I might periodically call for flight status information.
I think the key question revolves around your caching strategy. You need to evaluate how long data can live within your app without needing to be refreshed. If your resources go stale quickly, then they should be fetched when needed.
I'm working on a backbone project that you can take a look at here: http://sourceforge.net/projects/myelin/ but more specifically maybe this model: http://myelin.git.sourceforge.net/git/gitweb.cgi?p=myelin/myelin;a=blob;f=public/javascripts/models/tab.js;h=6b4cb6ad26d2fc12a817ec027b60b2b5ef13f463;hb=HEAD
(a couple of caveats: This is my first project using pretty much all of the technologies I chose to use, so I'm positive I made some design errors. If you notice anything, just send me a note so I can try to fix it! I didn't use the backbone controller, and rolled up my own, but I think in your case, the default controller is exactly what you're looking for.)
Backbone.js is very REST-ish in it's approach to dealing with things. I think if you approach it much the same way as you would in the rails world, then it may become more apparent as to a solid solution.
For example, take a look at the way Backbone does it's routing / controllers: http://documentcloud.github.com/backbone/#Controller-routes
It maps a route to an event, which you can set a listener to. So, in your example route above, you could fire an event, and have your projects controller catch it and execute some stuff.
If you were implementing the example in Rails, your invoices controller would be called, you'd grab the data through your Model, then send that data off to the view to have it rendered. Same idea with backbone (Though it's more code-involved than the rails world).
In my app, that's what's happening. The user does something in the UI, which triggers an event, which is caught and sent off to a controller. The controllers have methods very similar to the names in rails: 'get', 'index', 'create', 'destroy' etc... Once the model has done it's thing, it then calls it's view, and renders, or does whatever it needs to do.
In the example above (tab.js), when a Tab is instantiated, it's TabContents Collection is built, but empty. Which is similar to rails (I think). Rails won't load the whole kit n kaboodle, unless you ask it to.
Hope that helps!
I found a way for myself to handle this — maybe it helps someone else:
I'm extending a base collection class which implements a method isStale.
Like this I can fetch or "refresh" the data for a collection if this hasn't been done for a certain time:
if (this.collection.isStale()) {
this.collection.fetch();
}
Related
I've created a BookService that is used for storing (add), getting (getAll) and removing (remove) books. Now I want to use this BookService inside my controller to publish some methods that I can later use in my view. My controller looks like the following:
app.controller('BookController', ['BookService', '$scope', function(BookService, $scope) {
$scope.addBook = function() { BookService.add(); }
$scope.getAllBooks = function() { BookService.getAll(); }
$scope.removeBook = function() { BookService.remove(); }
}]);
As you can see, the controller is just a proxy that forwards the method calls to the service. Is this in general bad practice? And is there a better way to solve that using Angular.js? Calling the service directly from the view without a controller seems, to me like a bigger problem.
Best Practice
From what I can see this is perfectly good practice, I'm assuming that you're using $scope here to bind these services to a button or something similar. The Idea of using a factory or a service is to create some well organised reusable code that you can then instantiate in your controller exactly like you have done.
Controllers can get quite complex so moving basic functionality to your service is the best thing to do. In your case you have a relatively simple controller so you may not see the benefit of coding in this way. But I assure you that as your code base grows you will be required to code like this just to keep things readable.
Note
Just as an extra note I've added a data process that you might take with an example of a database request
database > API > service/factory > controller > view
This would be the correct path to take when requesting something from a database.
What you have shown is not bad practice; it is in fact recommended that you abstract resource management logic (like adding, removing and finding resources of the same type) into a separate service, for organization and maintainability and reusability purposes.
I do understand from your example how the controller seems to be just a proxy to the service though, and why you would think it's repetitive and possibly redundant. Let me expand on your example to see if I can explain the reasons for abstracting the logic. In doing so, let's consider only the adding operation, even though the logic would apply to others as well.
Reason 1: adding a book (or any resource for that matter) in a web app is usually more complicated than just a bookService.add() call. It requires having some sort of form to enter the details, a submit button to handle the actual request, possible massaging of the entered data, adding new fields like time stamps and author ids, and persisting to some data storage. The first two or three of those steps would be applicable to the screen or view from which you are adding, so it makes sense to put that in a controller (the view model), whereas the rest of the steps should go into the generic service.
Now say you have another screen where you see a friend's list of books and you can add it to your list by selecting a book. In that case, the controller logic for that view's controller will differ from the previous example, but the service steps will still be identical, and thus do not need to be duplicated since the service can be injected into both controllers.
That's a big win.
Example 2: let's say you've already split the code between controller and service as describe in example 1 above. Then you decide that your data storage needs have changed and now you want to update your logic to save to a different database system. Now instead of having to change all the controllers, you just change your services and the everything works.
This is also a really big win.
Yes you'ved done this correctly. Just keep in mind that as you scaled up your app in complexity, you'll want to have isolated scopes, (and) decomposition into component directives. Each directive will have its own controller and template fragment.
I'm making a single page application using Require.js and Backbone.js. Its a fairly large web app with a lot of different "pages" aka views. Below is my router to give you an idea. There are several main pages with sub pages.
So for example there's a Settings section that has multiple different sub pages such as user settings, language settings, email settings etc.
How would I structure many routes and their views for simplicity?
Right now Im giving each sub page its own view but that means I have to import 20-30 views into the router so that all possible views are available for when that page is routed.
Another way I thought of was to have one view for each section and that in that view I should load different partials. That way I only have to load the 5-6 section views into the router... but then the view would have to understand routing.
Whats the right way to do this?
I create 'controller' objects that take care of view rendering and model fetches.
I prefer to keep the router clean at all times, which means that I will don't clutter it with callback functionality. Doing so would make the router a mess over time, while part of its purpose would be to get a quick overview of the available routes.
In Backbone, I found that it is useful to create your own conventions, just like a framework would do.
For example, for every view I create, I will create one controller object.
Every controller object has a method that is named 'makeView()', and which takes care of rendering the view, as well as memory management.
In my own theory, I created a method of 'cascading controllers', in the sense that one controller may also control other controllers, and controllers may use 'helper' objects to fulfil certain tasks.
For example, when you say that you may need to manage 20 views and subviews; we could imagine that some of the views are related to each other; that there will be a central controller that takes care of common tasks between related views, and specific controllers that take care of specific, individual view functionality.
A route in my router looks something like this:
auth: function(){
//--- Check the authStatus and render status independent views
var auth_ctr = new Auth_ctr();
auth_ctr.makeViews();
}
In the example given, you could imagine that you will create and render multiple views. So what I really do, is instantiate new controllers from within this controllers, that each individually will create and manage views, provide functionality that support the view, get the collection/model data.
It would be important to create a sort of independent 'View manager' that prevents memory leaks from occurring when you render new views each time.
This is just how I do it, but of course, I'm sure there are people who do this differently.
It is a theory I came up with; it has given me a clear structure, and it has worked well for me until now.
There is a new MVC mechanism built in Enyo 2.3pre but there is absolutely now docs on it.
The question is how can I bind specific controller to my view?
I have a new kind based on enyo.Control e.g. and I have a controller based on kind: 'enyo.ViewController',
In my controller I have handlers object with a function that should handle event.
If I put view prop into controller with a name of my view that doesn't work since
my handler in controller is not invoked
Can you post some examples on this?
So, the enyo.ViewController, by default, wants to renderInto document.body and we use it to define the enyo.Application kind as the "starting point" for your application.
The Enyo implementation is not necessarily "pure" MVC in the sense that you don't necessarily have to have a proper controller for every view (or enyo.Control) that you are dealing with. Enyo has always had a sort of hybrid view/controller system baked into the controls themselves.
With that being said, recent changes to the implementation removed bubbling of events to a "controller" that owned your "view" as it resulted in a lot of unnecessary overhead. In fact, we're removing the "controllers" block from the enyo.Application kind as an app-global reference to various controllers, and instead you will place them in a components block as typical of "traditional" Enyo development.
So, the current thinking is that your view will handle events as before, but you can bind to properties of various "controllers" and models.
Now, you can still create an MVC architecture if you really want to, but the system is flexible enough to support any of the "separation of concerns" methodologies (MVC, MVP, MVVM, etc.)
My current way of going about things is to create a "controller" for doing some things (like make Web service requests) and then build out models from the data I get back, add them to a collection, and then my views probably have a data-aware control (such as enyo.DataRepeater or enyo.DataList) that will automatically generate some rows for each model.
Take a look at this simple example: http://github.com/clinuz/college-football but, be advised it may not be up-to-date with the switch from app-wide controllers to components. And also, we're removing the "controller" property of the DataRepeater/List and it will change to "collection."
Let me know if you need some more hints. We're aware the lack of documentation is making this difficult while we finalize our implementation. Please bear with us!
You could see my example of to checkout enyo MVC structure.
https://github.com/prajnavantha/enyo-internetradio
Basically we have a model, view and controller.
models: In my case is a simple enyo.Model kind. U can have enyo.collections etc...
Controller: i've used enyo.ModelController.
Views: have the kinds:
The application is not totally MVC. Since my logic is still in views. However you can understand, how to set model and use the componenets.
I know this is a very commonly discussed topic but I can't find anything that answers my question exactly :)
I'm working on a Backbone.js project at the moment. Router wise I don't instantiate views, models or collections within the router but instead just use the router as one way of dealing with state - the router calls methods on my custom controller object.
My controller then instantiates the different views, models and collections for index, show etc. This is all fine and dandy.
I'm just having a bit of a struggle with how to deal with page transitions. I've read all of the great posts on managing zombies etc, and know that whatever happens I have to have some cleanup system for old views (I'm currently using the .close() method that Derick Bailey blogged about).
If I'm going from #show to #index, or any other route change, I understand that it makes sense to just instantiate new, fresh views, models, etc - which is what I see in pretty much every tutorial. Making sure to cleanup old ones, of course.
But, if I'm already on #show say, and I route to another #show page, all of the views etc that I want are already instantiated and rendered. All I want to change is the data of the models and collections.
So I guess my question is why do I not see people re-using views very much. In my head I was thinking if you're already on the page that you want, it would make more sense to just update the url or urlRoot of the model / collection that that view is linked to and re-fetch. This would then trigger a reset event, and all views that need to can subscribe to this and re-render themselves.
But, as I say, I don't see people doing this. Is it just because it's a really bad idea? If someone is doing something like this, how do you deal with tracking 'refreshable' models and collections?
Thanks!
I think it depends a lot on how you are using your views and how complicated/large they are.
If your views are very simple then it is often just easier to rerender the entire view and replace the existing HTML with the new markup (it might also be faster then traversing the DOM to change the necessary parts. However if you have a more complicated view and there is only a small amount of information changing it is most likely better to listen to the appropate attributes change events (eg. _bind('change:name', this.nameChanged,this)) and then only update that part of the DOM.
Keep in mind that while the convention is to use a render method which renders the element, you can just as easily apply an additional refresh event to only refresh certain parts, you can then just swap models (like #jackwanders suggested) and call the refresh method.
I have a question regarding Backbone JS's Models. I've already delved into Backbone JS quite a bit the last few days. I am understanding it now (and thanks to Stackoverflow, I have understood further with a few things).
At present, my web app is using Backbone Models to store dynamic navigation and other such bits. Stuff that is generally used in Backbone Collections. At present, my web app is still needing to store sort of 'global' states... Such as what the user has currently selected in the navigation (which then effects other parts of the app etc.)
I've been keeping all of these stored 'states' in variables like this:
App.data.selectedPage = whatever etc.
But I'm thinking more about Backbone Models... Should I be storing these 'global states' in a Model? Is that something that the Models can be used for?
At present, the webapp doesn't save to the server, or local storage, it's more of a converted Flash presentation I have to code for an iPad. So it still made sense to use something like Backbone for code organisation purposes... I mean, that's ok too right? To use Backbone, even I don't intend on storing the models anywhere?
Anyhow, yes, using models to store this sort of information is ok too? Anything goes? ...please do tell me if I'm approaching this wrong.
Many, many thanks.
James
I think one good rule of thumb for using backbone model is if you need events when some data is changing.
For exemple, you have a calendar with a selected date. Many other parts (views) of your app needs to know and be informed about the selected date. Then it makes sense to store the date in a model and have everyone listen on events from the calendar.
This is more for data related functions. For state it is different. Your selected page is a state to me. Page selection, page state, globals, they should be in your controllers. They (or it) should know what the state of the page is and they can trigger event when it changes.
Model => data centric with events