Backbone.js - Dynamic routing for a large site - backbone.js

I am planning to use backbone + require for an application which has more than 30 modules. Instead of creating separate route for each module, I am planning to create something like this.
Not sure it this is a best practice. Please guide.
routes: {
":module" : "routeLevelOne",
":module/:id" : "routeLevelTwo",
},
routeLevelOne: function(module){
require(['views/' + module + 'View',],
function(){
require('views/' + module + 'View').render();
}
);
},
routeLevelTwo: function(module, id){
require(['views/' + module + 'View',],
function(){
require('views/' + module + 'View').renderWithId(id);
}
);
},

I wrote a blog post about this very topic. The single-router approach might work for awhile, but you're right to worry about scalability issues in the future.
As #schacki mentioned above, check out my Backbone.Subroute plugin to make this more scalable, and transfer the burdon of subroutes to the developers working on those modules.

From my point of view, this is totally fine and is best practice. It keeps your code lean and clean and it very easy to understand what is supposed to happen.
The only alternative option to me would be something like subroutes. But since your "dispatch" logic seems to be the same in all modules, that is probably not required.

Related

in-page anchor with backbone

Hi everyone,
I am developing a backbone app and I went through one "big" problem, I can't find any useful thinking on internet but I can't imagine I am the only one to have this problem.
I just want to use basic in-page anchor with backbone like old time.
Example : I want to my page to go down to a section when I have #section at the end of the URL.
My backbone url path is site.com/#/page .... so of course site.com/#/page#section will freak out.
The only solution I found is to use push state but I don't really want to.
Is there another way to handle this behaviour ? even with another pattern or plugin .. but no push state.
Thanks very much,
jdmry
Here's how I'm doing it:
First, add Backbone.history.anchor
pathParts = Backbone.history.fragment.split('#')
Backbone.history.anchor = pathParts[1]
Then, use jQuery to scroll to the element
if (Backbone.history.anchor) {
$('html, body').animate({
scrollTop: $('#' + Backbone.history.anchor).offset().top - 10
});
}

UI testing an ExtJS webapp using CasperJS/PhantomJS

I'm working on UI testing an ExtJS web-app, and I'm a beginner.
I am trying to test the ExtJS widgets by using CasperJS/PhantomJS tool.
Also, I generate the required CasperJs script using Resurrectio and by making necessary changes to it.
Since ExtJs generates unique ids dynamically for the DOM elements that it creates, I want to know how to provide those ids in CasperJs script for testing.
For example, The following Casper Script was generated by Resurrectio:
casper.waitForSelector("#ext-gen1142 .x-tree-icon.x-tree-icon-parent",
function success() {
test.assertExists("#ext-gen1142 .x-tree-icon.x-tree-icon-parent");
this.click("#ext-gen1142 .x-tree-icon.x-tree-icon-parent");
},
function fail() {
test.assertExists("#ext-gen1142 .x-tree-icon.x-tree-icon-parent");
});
casper.waitForSelector("#gridview-1038",
function success() {
test.assertExists("#gridview-1038");
this.click("#gridview-1038");
},
function fail() {
test.assertExists("#gridview-1038");
});
Here #ext-gen1142 and #gridview-1038 are the ids dynamically created. How should one provide data in the tests? Is there any stub or mocking tools which works with ExtJs in the code to provide these ids at runtime during tests?
I came across SinonJS. Can it be used or Do I need to used CSS or XPath Locators as mentioned in this answer? How reliable it is to use CSS or Xpath Locators?
Thanks in advance!
Not so easy to answer this, but here a few thoughts...
Don't rely on generated IDs. Never. They'll change in moments you won't like and if you have luck very much earlier.
Your best friends will probably be pseudo CSS classes you attach to your components. You could also use IDs, but this is only reasonable when you have elements which occur only once in your page. If that is the case, they are very good anchors to start with selections/queries.
XPath with ExtJS is possible, but you have to carefully choose the elements. ExtJS is so verbose in generating little things so your paths can be quite complicated. And when Sencha drops support for problematic browsers (IE < 8) maybe they change their templates and your XPath doesn't find anything.
SinonJS is great. But it won't help you much in DOM problems. But sure you can use it in your tests. I suppose it will payoff most in testing parts of your controllers or non-trivial models.
Model your test components after your real UI components and screen sections. Don't just record a script. Test code should be engineered like production code. If you create reusable components of test code and logic, you don't have to fear changes. In the best case the changes in one component will only touch the testing code of that particular component.
I know you have ExtJS. But take some time to look at AngularJS and see how easy it can be to test all parts of a JavaScript web application. I'm not saying you should switch to AngularJS, but you can learn a lot. Have a look at Deft JS as it has many concepts which enhance testability of ExtJS applications.
I use Siesta for my ExtJs testing. It works amazingly good for all JavaScript (jQuery based and others), but is specifically designed for ExtJS/Sencha Touch.
It has the feature to combine CSSquery and ComponentQuery to select your elements I think that will fix a lot of problems for you.
In the paid version there is even a test recorder to record scenario's and use them for your tests.
Here's a demo
Here's some sample code:
StartTest(function(t) {
t.chain(
{ waitFor : 'CQ', args : 'gridpanel' },
function(next, grids) {
var userGrid = grids[0];
t.willFireNTimes(userGrid.store, 'write', 1);
next();
},
{ waitFor : 'rowsVisible', args : 'gridpanel' },
{ action : 'doubleclick', target : 'gridpanel => .x-grid-cell' },
// waiting for popup window to appear
{ waitFor : 'CQ', args : 'useredit' },
// When using target, >> specifies a Component Query
{ action : 'click', target : '>>field[name=firstname]'},
function(next) {
// Manually clear text field
t.cq1('field[name=firstname]').setValue();
next();
},
{ action : 'type', target : '>>field[name=firstname]', text : 'foo' },
{ action : 'click', target : '>>useredit button[text=Save]'},
function(next) {
t.matchGridCellContent(t.cq1('gridpanel'), 0, 0, 'foo Spencer', 'Updated name found in grid');
}
);
})

Using bluetooth in AngularJS

I've been trying to develope some mobile app and I'm thinking of picking up AngularJS+ZeptoJS.
But there is one problem - I couldn't find anything about accessing the bluetooth actions with Angular. I've looked through some tutorials but haven't find a single word about it. I've been thinking if it is even possible?
I mean - accessing bluetooth in mobile-app ( created in angularjs, converted in phonegap ). Not mobile-web.
I'm quite new with mobile app programming so please don't hurt me :)
And also a little bit desperate to get the answer..
It looks like there is a PhoneGap plugin for accessing Bluetooth:
https://build.phonegap.com/plugins/23
Once you get the plugin installed, you can access it via Angular. I recommend creating a service for interacting with it. It will go a little something like this:
App.factory('bluetooth', function() {
var bluetoothSerial = cordova.require('bluetoothSerial');
return {
sendMessage: function(message) {
// interact with bluetoothSerial
}
};
});
Then, your controllers can require it:
App.controller('appCtrl', function(bluetooth) {
$scope.communicate = function() {
bluetooth.sendMessage("all your base are belong to us");
};
});
Good luck!

Using Backbone models with AngularJS

Recently I was thinking about the differences and similarities between Backbone.js and AngularJS.
What I find really convenient in Backbone are the Backbone-Models and the Backbone-Collections. You just have to set the urlRoot and then the communication with the backend-server via Ajax basically works.
Shouldn't it be possible to use just the Backbone-Models and Collections in AngularJS application?
So we would have the best of both worlds two-way data-binding with AngularJS and convenient access to the server-side (or other storage options) through Backbone-Models and Collections.
A quick internet search didn't turn up any site suggesting this usage scenario.
All resources either talk about using either the one or the other framework.
Does someone have experience with using Backbone-Models or Collections with AngularJS.
Wouldn't they complement each other nicely? Am I something missing?
a working binding for example above...
http://jsbin.com/ivumuz/2/edit
it demonstrates a way for working around Backbone Models with AngularJS.
but setters/getters connection would be better.
Had a similar idea in mind and came up with this idea:
Add just a getter and setter for ever model attribute.
Backbone.ngModel = Backbone.Model.extend({
initialize: function (opt) {
_.each(opt, function (value, key) {
Object.defineProperty(this, key, {
get: function () {
return this.get(key)
},
set: function (value) {
this.set(key, value);
},
enumerable: true,
configurable: true
});
}, this);
}
});
See the fiddle: http://jsfiddle.net/HszLj/
I was wondering if anyone had done this too. In my most recent / first angular app, I found Angular to be pretty lacking in models and collections (unless I am missing something of course!). Sure you can pull data from the server using $http or $resource, but what if you want to add custom methods/properties to your models or collections. For example, say you have a collections of cars, and you want to calculate the total cost. Something like this:
With a Backbone Collection, this would be pretty easy to implement:
carCollection.getTotalCost()
But in Angular, you'd probably have to wrap your custom method in a service and pass your collection to it, like this:
carCollectionService.getTotalCost(carCollection)
I like the Backbone approach because it reads cleaner in my opinion. Getting the 2 way data binding is tricky though. Check out this JSBin example.
http://jsbin.com/ovowav/1/edit
When you edit the numbers, collection.totalCost wont update because the car.cost properties are not getting set via model.set().
Instead, I basically used my own constructors/"classes" for models and collections, copied a subset of Backbone's API from Backbone.Model and Backbone.Collection, and modified my custom constructors/classes so that it would work with Angular's data binding.
Try taking a look at restangular.
I have not implemented it anywhere, but I saw a talk on it a few days ago. It seems to solve the same problem in an angular way.
Video: http://www.youtube.com/watch?v=eGrpnt2VQ3s
Valid question for sure.
Lot of limitations with the current implementation of $resource, which among others doesn't have internal collection management like Backbone.Collection. Having written my own collection/resource management layer in angular (using $http, not $resource), I'm now seeing if I can substitute much of the boilerplate internals for backbone collections and models.
So far the fetching and adding part is flawless and saves code, but the binding those backbone models (or the attributes within, rather) to ng-models on inputs for editing is not yet working.
#ericclemmons (github) has done the same thing and got the two to marry well - I'll ask him, get my test working, and post the conclusion...
I was wondering the same-
This is the use-case:
salesforce mobile sdk (hybrid) has a feature called smartstore/smartsync, that expects backbone models/collection ,which gets saved to local storage for offline access .
And you guessed it right, we want to use angularjs for rest of the hybrid app.
Valid question.
-Sree
You should look at the angularJS boilerplate with parse here. Parse is backbone like, but not exactly backbone. Thats where im starting my idea of a angularJS backboneJS project

Backbone general router vs. separate routing files?

I found that most tutorials use one big router.
For example: https://github.com/thomasdavis/backboneboilerplate/blob/gh-pages/js/router.js
Wouldn't it be better to separate the routes (controllers) into separate files?
If yes how can I combine this with requirejs?
I think this is a question of preference. If you're doing a ginormous application with gazillion routes, then dividing your routers up is sensible. For small applications having just one big router is just fine.
If you decide to have multiple routers, make sure you don't have conflicting routes, so there won't be any unexpected behavior or errors.
So with requireJS: I think the best way would be to define each router in it's own file like this
define([blaa, blaa], function(Blaa, Blaa) {
var SubRouter1 = Backbone.Router.extend({
// work your routing magic here, remember to make no conflicting routes
});
return SubRouter1;
});
When you have all your desired routers set up you can bundle them up in the app.js
define([...,'subrouter1', 'subrouter2', ... , 'subrouterN', ...],
function(..., SubRouter1, SubRouter2, ... , SubRouterN, ...) {
// work your app magic here
initialize: function() { // or wherever you start your application
subrouter1 = new SubRouter1();
subrouter2 = new SubRouter2();
...
...
subrouterN = new SubRouterN();
Backbone.history.start(); // remember to start the history
},
// maybe work some more magic?
});
I've never done this myself, but I don't see why it wouldn't work if you keep the routes from conflicting. Hopefully this clears stuff for you.
check Backbone.js "fat router" design conundrum out : you can find #jakee answer there and some more options

Resources