makesites / backbone-app Goto Github PK
View Code? Open in Web Editor NEWAn APP() class that encapsulates popular Backbone.js operations
An APP() class that encapsulates popular Backbone.js operations
An old story for sure. With personal experience trying best practices in projects, there's some re-usable code that can be included in backbone-app.
Caching is considered one of those "core" features, as there's a very small percentage of client-side apps that don't want to cache any remote requests.
That's why it's included as a feature of backbone-app, instead of an independent extension.
As this repo is solely dedicated to the library it makes sense to partition the objects in separate files and introduce a build script for publishing.
This will improve the development as it will limit code lookup
The data is simply converted to JSON before parsed by the template, which works in most cases.
When we need access to the options of the view, there's no easy way around it.
The APP.View could accomodate by setting a flag inRender
in the view's options.
As known a MongoDB will return results with "_id" instead of "id"
Would be nice to create a Model and Collection that would extend the default with a custom parse method that would "normalize" the results with proper ids...
As this method only seems to serve one purpose (fix a Nginx quirk) it may not belong in the generic base class.
See if the problem is fixed simply by using "emulateJSON" in Backbone.js
A view that's rendered with APP.View is always trying to become visible on postRender
.
Although that's the case most of the time, in some cases it may not be the desired behaviour.
Setting an option like silentRender
to act as a flag might be helpful.
Add a fallback route for all "not found" routes.
Something similar to what's described here:
http://stackoverflow.com/a/6522963
Add this gist to the main Router()
https://gist.github.com/3044124
The current version of Backbone.js has the router initiate the route with no delay, even sooner than the initialise method.
As it is quite common to have logic run before every route (ex. loading the session). Keeping the convention with the views it may be named preRoute
An empty method needs to be present so there is no runtime error, if a no custom compiler is set.
There have been ways of stating when the app is loading content, on and off, but maybe we should stick to specific conventions moving forward.
A loading class on the container seems the most popular method, that's removed when the data arrives.
For the layout, which shouldn't have data directly attached to it, removing the loading class on the first render seems reasonable.
Very common on "one-page apps" to authenticate with a remote API and return back to the original page, in which case there's a hash "url" containing the token. This usually (in OAuth2) looks like this:
http://domainname.com/path/to/app#access_token=234564321345
The APP() can predict this pattern with a special route and possibly forward/save the token for later use...
The APP should monitor the user's position - set optionally with a flag.
Backbone doesn't allow you to save a collection back to the server.
A rather popular feature when a collection is actually the smallest (data) entity.
As containers are often being re-purposed to display different content it makes sense to add an unbind action that will relieve them fron any previously stated events.
Something along these lines could live in the main view:
// unbind this container from any previous listeners
$(this.el).unbind();
As a convention a global "config" object might have app configuration, possibly separated between development and production variables.
In addition, the app can have a dev/prod flag set for future reference.
When we do a fetch() it might be useful to fire an event named fetch
.
There is already some code for Google Analytics but it's not functioning properly in all cases.
First of all the binding for tracking the events is optional. Plus there's an exception when looking if the ga object is undefined.
Along with making the tracking activated by default and better error handling, there could be ground work laid for more tracking service to be supported...
When setting this.data in the views there is a lookup for either a model or collection
It would be nice to have a condition if there is no data - so a view can be rendered (as pass-through markup)
The parent APP.View has the of defining the data as such:
this.data = this.model || this.collection || null;
In this case, new views have the option to either pass a model or collection, whereas if it is defining a (final) dataset in this.data
it will be overwritten and most likely set to null
As this is undesirable it is best if the data is checked against itself first before replacing:
this.data = this.data || this.model || this.collection || null;
jQuery's $.get
method is used in a number of occasions when an external fragment is requested (ex. the Template, View...)
Consider making an (underscore?) utility function that will be included in all plugins as a small snippet.
Backbone.js is proven suitable for mobile apps and Phonegap is the most common way to compile a web app with a native wrapper.
It would be nice is some of the setup is "automated" so working with Backbone+Phonegap feels seamless.
This issues is especially created for the ChildBrowser plugin but may be extended to other Phonegap functionality...
When there is an API in the config, it is applied through the ajaxPrefilter in all the $.ajax() requests.
This works well when the api and the web app URLs match - but when they are different (ex in a Phonegap app) some requests may need to be done locally, namely fetching the html fragments.
For these cases it is better if the ajaxPrefilter only applies the API url when data is requested.
This is often the case when some of the views are static (or have data already loaded).
Their state appears to be loaded instantly and the equation registered == loaded
validates more than once
Sometimes targeting a container by id is not possible - especially if the same container is used for more than one views.
Maybe there can be flag (by default set to false) that adds an attribute 'data-view' on the container with the name of the view.
Targeting can then be done (in CSS):
[data-view='{{name}}'] { ... }
APP.Model now has a custom sync method, to bypass the zero content request issue...
That should in fact be decoupled to an external helper/shim.
It is often the case that we want logic to be executed right before or right after the view is rendered.
For that reason it makes sense to include a preRender() or postRender() method.
backbone-app can lookup the existence of these functions and automatically execute them.
the default router does a lot of configuration in the initialize
method - it would be good if all that (conditional) logic was moved to an internal _setup method.
As session communication with the client is becoming a standard, it is better if it's encapsulated in the app
namespace, and what more appropriate than:
app.session
Although backbone.session is an independent plugin it's a reasonable assumption to check if it exists and automatically handle the session...
The Template() class is expecting to have the compiler setup manually.
If not available the Template will not parse anything.
To have a better behaviour and more seamlessly integrated with the "default" parts it is better if it uses the _.template()
method instead.
To accomodate other template engines the developer will have to override the underscore method with their own custom method. Fore example:
_.template = Handlebars.compile;
This will allow the Template class to have a persistant behaviour across any dependency list.
Add an override for jQuery resize that handles the event being triggered multiple times in webkit mobile browsers
For more information on the issue and code examples, see these posts:
http://www.emoticode.net/jquery/fix-bounce-of-resize-event.html
http://paulirish.com/2009/throttled-smartresize-jquery-event-handler/
Also requires this code:
remove: function() {
// unbind the namespaced
$(window).unbind("resize");
// don't forget to call the original remove() function
Backbone.View.prototype.remove.call(this);
}
It is often the case that you load a "main" view from the controller, which in turn has a number of "smaller" views, each with their own separate data model.
Although the term view is totally valid when it is describing a portion of the page and has a specific model attached to it, it looses its scope when it's trying to describe a collection of sub-views while it's not rendering data but containers for other views.
Since the purpose and function of these "views" is different (skewed) from the original concept of a view, lets group them together in their own container and give them their own base class: Layout()
The container APP.Layouts can be organised the same way as usual
PS. I was trying to deny these facts for a long time and did not want to believe e needed a separate group. But then I got sick of writing exceptions for the layout views or even reverting back to the vanilla Backbone.View to rid all of the extra functionality View() offers....
It is a common sight to see three lines of bindings for every model in a view.
There must be a more 'discrete' way of setting those bindins - probably putting all that logic in one generic method.
The main objects created by the library live are named:
Model, View, Collection, Router...
This population of the global namespace could be risky. It would be preferable if all the objects are under the APP namespace.
When Facebook completes the OAuth2 authentication it redirect back to the site with the following hash:
http://website.com#_=_
This is a known "bug", as described here:
http://stackoverflow.com/questions/7131909/facebook-callback-appends-to-return-url
Instead of finding "custom" solutions it would be better if the Backbone app monitored this "route" and redirected back to the home view.
Or course we're assuming that there's no case where this could be an actual route.
Especially for "static" templates like the Markdown template, all that's returned by executing the template is a string.
Need to check if the template is a function and only execute with the data if so...
With new platforms arriving (Firefox OS & Chome Packaged Apps) just letting the click troughs pass may not always have the desired result.
Even with existing platforms this is a problem, like in iOS full screen websites don't persist in the same window. Related work (for iOS):
https://github.com/mrmoses/jQuery.stayInWebApp/blob/master/jquery.stayInWebApp.js
There needs to be a method that has an overview of the links clicked and redirects as appropriate for each case.
As a principal all hash urls should be available as actual urls, presenting the same content.
This can be achieved with the same client code - rewriting the URLs back to the main index.
Currently the main router looks up the URL and expect to find different Routers based on the path (up to one level).
It would be nice if in addition pushstate URLs were supported - possibly by switching between the two processing methods with a flag.
Here's a relevant discussion:
http://stackoverflow.com/questions/9184959/rewriting-nginx-for-pushstate-urls
Automatically lookup app options and set an ajax pre-filer for a remote api.
Not that this config option should be accompanied with CORS setup on the server side
Some related information on CORS :
http://backbonetutorials.com/cross-domain-sessions/
It is reported that with the latest version of backbone.js (>0.9.10), certain models fail with the following message:
Object #<Object> has no method 'parse'
Possibly a binding issue that makes the parse
method ont available after the success method.
With this as an excuse, the APP() namespace need to be thoroughly tested against the latest iteration of Backbone.js
The APP.Templates container exists but the APP.View is always trying to load the default APP.Template.
It would be better if a template var passed as part of the options had the priority to set the template.
Only then the APP.Templates container has any meaning and use in a generic way...
Trigger the first render() call (in initialise) only if there is data already
This has been a controversial subject and there has been a lot of discussion if .extend() should preserve the values of the parent objects.
The official position of Backbone is that this convention is too binding for the child classes, for example:
jashkenas/backbone#244
I have to agree with the (counter) argument that if you don't want the child to inherit all the options & events of the parent maybe the OO structure has problems...
Instead the extend
method can be easily enhanced with this extra functionality, affecting only the objects in the classes.
Backbone Extender is an small extension with that scope:
https://gist.github.com/tracend/5425415
Relying on the $().ready
event to load the backbone app may not be always the best option.
Backbone.ready is trying to bridge the gap by encapsulating a number of fallbacks in a custom .ready()
method
It would be nice if backbone app had that functionality out of the box, and all apps were initiated like this:
Backbone.ready( function (){
// initialize APP
window.app = new APP( config );
// start backbone history
Backbone.history.start();
});
Need some user specs to automatically generate the models based on them.
navigator.platform
to get the OS
navigator.appName
to get the browser family
navigator.appCodeName
to get the browser name (or group)
Sometimes the container needs to be completed with additional content, instead of being fully replaced.
An append : true
variable could accomodate in this to differentiate the two methods of rendering the view.
The app.state
can be enhanced with information related with the memory usage, based on the console.memory
property (where supported)
Layouts set views, pass data to the views, but there's no easy way of keeping track of that data on the layout level.
Automation in this area may help, by making a few conventions.
For example if the _view key matches the data key_ in the layout data, there should be a natural attachment - and all data updates in the view should be reflected back to the layout data set.
As the old attributes is deprecated in models & collections, in favor of the more concise options
it's a hassle to pass options to the constructor that need to manually be set in the initialize
method to persist.
Automation can be beneficial here. Something like:
options = options || {};
this.options = _.extend({}, this.options, options);
APP.View
currently supports views that have no data attached to them but there's always a requirement to run the render
method. This is mainly to load external html fragments...
To fully support static views the render method shouldn't be called if there's no html
and data
in the options
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.