Hi I am struggling through working with backbone routers, and I am wanting to find out about instantiating routers.
Can I have one routers file in my app where all the routes are defined, but I make an instance of the router in my appView and in my appModel. I am doing this so that I can call the router from both the view and the model, however I feel that this might be a rather sloppy way to do this?
Is there a better way?
The best way to handle this that has worked for me in the past is to create a global javascript file that is included on every page:
<script type="text/javascript" charset="utf-8">
window.APP = {};
APP.Routers = {};
</script>
Render the router once on page load:
APP.Routers['my_router_name'] = new MyRouterName({});
Now you can access it anyplace throughout the app by
APP.Routers.my_router_name
I tend to follow this pattern with not only routers, but also we collections, models, etc. also.
<script type="text/javascript" charset="utf-8">
window.APP = {};
APP.Routers = {};
APP.Collections = {};
APP.Models = {};
</script>
This solves the problem you have stated here it seems...."I am doing this so that I can call the router from both the view and the model".
Related
I was just going through the code of a online reppositoty using angular.js and came across the following example:
<!DOCTYPE html>
<html ng-app="demoapp">
<head>
<script src="js/ol.js"></script>
<script src="js/angular.min.js"></script>
<script src="js/angular-sanitize.min.js"></script>
<script src="js/angular-openlayers-directive.js"></script>
<link rel="stylesheet" href="css/ol.css" />
<link rel="stylesheet" href="css/angular-openlayers-directive.css" />
<script>
var app = angular.module('demoapp', ['openlayers-directive']);
</script>
</head>
<body>
<openlayers lat="39.92" lon="116.38" zoom="10" height="400" custom-layers="true">
<ol-marker lat="39.92" lon="116.38" message="Here is Beijing. Dreamful place.">
</ol-marker>
</openlayers>
<h1>Adding a layer with markers with no javascript example</h1>
</body>
</html>
Now there is the below part:
var app = angular.module('demoapp', ['openlayers-directive']);
I am not quite sure about, the above line, I read about dependency injection HERE. But i am not quite sure what is the purpose of the above line ? what is it really doing ?
I have gone though a few online examples that have code like the below:
// Define a new module for our app. The array holds the names of dependencies if any.
var app = angular.module("instantSearch", []);
(See the comment) , Ok but i still don't get what ['openlayers-directive'] , is doing ?
It declares a module named 'demoapp' that is dependant on a module named 'openlayers-directive'. This, basically, means that all the angular components (directives, services, filters, controllers, constants, etc.) defined in the module 'openlayers-directive' will be usable in your angular application.
Read the documentation.
openlayers-directive is an angular module. When you are creating your demo app module, you are including a reference to the openlayers module.
So if you wanted to use other modules in your demo app module you would also include them here, where you are declaring your module for the first time.
For example:
var app = angular.module('demoapp', ['openlayers-directive', 'anotherModule', 'yetAnotherModule']);
In your code you can then pass in any services from these modules by simply including them as parameters.
So if you have a demoController you could pass in a service from one of the included modules and use it.
For example
angular.module('demoApp').controller('demoContoller', function($scope, anotherModuleService)
{
$scope.someFunctionFiredFromController = function()
{
//I have access to this service because the module it
//belongs to was referenced by the demoApp module, and the
//service was injected into the controller
anotherModuleService.doSomethingRelevant();
}
});
Backbone.Router.extend is giving me the error: "extend" cannot be used on
undefined
Nodejs and express is also used in this project.
but i have not mentioned anythin related to backbone in app.js
Below is my index.html and main.js.
I have a feeling, the jquery,underscore and backbone files may not be loading properly,due to which this error is happening
Kind of beginner in backbone.Any help is greatly appreciated
index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" href="/stylesheets/style.css">
<script src="javascripts/jquery.min.js"></script>
<script src="javascripts/json2.js"></script>
<script src="javascripts/underscore-min.js"></script>
<script src="javascripts/backbone-min.js"></script>
<script src="javascripts/main.js"></script>
</head>
<body>
<h1>< title </h1>
<p>Welcome to world of html</p>
</body>
</html>
main.js
$(document).ready(function(){
var Theater = {
Models: {},
Collections: {},
Views: {},
Templates:{},
Routers:{}
}
Theater.Models.Movie = Backbone.Model.extend({});
Theater.Collections.Movies = Backbone.Collection.extend({
model: Theater.Models.Movie,
url: "/json",
initialize: function(){
console.log("Movies initialize")
}
});
Theater.Routers = Backbone.Router.extend({
initialize:function(){ console.log("defaultRoute");},
routes: {
"": "defaultRoute"
},
defaultRoute: function () {
console.log("defaultRoute");
}
});
console.log("gonna call approuter");
var appRouter = new Theater.Routers();
Backbone.history.start();
});
A large number of tiny tweaks and micro bugfixes, best viewed by looking at the commit diff. HTML5 pushState support, enabled by opting-in with: Backbone.history.start({pushState: true}). Controller was renamed to Router, for clarity. Collection#refresh was renamed to Collection#reset to emphasize its ability to both reset the collection with new models, as well as empty out the collection when used with no parameters.
Backbone change log of 0.5.0
http://backbonejs.org/
Backbone's Router was called Controller and renamed to Router when it got version 0.5
Simply replace your Backbone and Underscore files into newer version or use Controller instead. then your code should work.
I strongly recommend to update your Backbone file due to bugs which Backbone used to have.
My AngularJS app makes calls to an API which is currently hosted at one service, but was previously hosted at a different one, and in the near future is likely to be hosted yet somewhere else.
The URL is regularly changing. For example from
myfirst.heroku.com/app/user/mike/profile
to
mysecond.bluemix.com/app/user/mike/profile
etc.
Instead of changing the URL in every location everytime, I want to just have to change the part before the /app....
In an Angular App what is the best way to do this?
NOTE: Many of the URLs I use throughout the app, are in modules that are added as dependencies to my main app. So Module1 and Module2 both use the URL in their controllers and resources and are then included in MainApp. So a good solution for me needs to be accessible to all dependee apps. Is that possible.
I would like to suggest you that you must use angular constant, Its similar to a service but it creates a constant value which can be inject everywhere in our angular project.
This is how we can create constant
Constant service:
angular.module('AppName')
.constant('REST_END_POINT', 'https://rest.domain.com/');
Usages in controller:
angular.module('AppName')
.controller('CTRL_NAME', ['REST_END_POINT', '$scope', function(REST_END_POINT, $scope){
//your business logic.
]);
$location.host() is the client browser's 'prefix.domain.suffix'
You can inject $location into whatever scope or service.
angular.module('app',[]).run(function($rootScope, $location){
$rootScope.host = $location.host();
})
Plunk: http://plnkr.co/edit/gDgrlwZFyWNKUJgbHHKj?p=preview
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.7/angular.js"></script>
</head>
<body>
<i>Host:</i>
<h1>{{host}}</h1>
<script>
angular.module('app',[]).run(function($rootScope, $location){
$rootScope.host = $location.host();
});
</script>
</body>
</html>
I do use request interceptor for this
csapp.factory('MyHttpInterceptor', [function () {
var requestInterceptor = function (config) {
var prefix = "http://api.example.com";
if (config.url.indexOf("/api/") !== -1) {
config.url = prefix + config.url;
}
}
}]);
configure this intercept in app.config like
csapp.config(["$httpProvider", function($httpProvider) {
$httpProvider.interceptors.push('MyHttpInterceptor');
});
now all your api requests would be prefixed with api.example.com.
I'd like to have multiple routers living on a single page for modularity. I initialize the routers on $(document).ready() in different js files. When I had just one router that worked fine because I could call History.start() right after initializing the router, but now that I have multiple routers that could be initialized from different files, I'm not sure when to call History.start().
For example:
<script src="router1.js" type="text/javascript"></script>
<script src="router2.js" type="text/javascript"></script>
In router1.js:
$(document).ready(function(){
new Core.Routers.Router1()
});
and likewise for router2.
Is the best solution just to add a new $(document).ready() that calls History.start() at the end of the page? I don't think the doc ready calls are blocking, so doesn't that introduce a race condition where all the Routers may not have been initialized by the time History.start() has been called.
You only need to call Backbone.history.start() once in your app and the only criteria for when you call it is that at least one router has to be instantiated already.
So, you could easily do this:
$(function(){
new MyRouter();
Backbone.history.start();
});
$(function(){
new AnotherRouter();
});
$(function(){
new AndMoreRouters();
});
I do a similar thing with routers on a regular basis, and I often start up new routers long after the page has been loaded and the user is interacting with the page.
FWIW though, you might be interested in the idea of initializers that I have in my Backbone.Marionette plugin and documented as part of this blog post: http://lostechies.com/derickbailey/2011/12/16/composite-javascript-applications-with-backbone-and-backbone-marionette/
You also may be able to check Backbone.History.started...
var Router = Backbone.Router.extend({
routes: {
'': 'load'
},
initialize: function () {
},
load: function () {
}
});
$(function () {
new Router();
if (!Backbone.History.started) {
Backbone.history.start();
}
});
It was added recently in a pull request.
Be sure and check out Derick's Marionette plugin as well, it's pretty awesome.
I use a lot of script in an application, some of them are not required to load the application, I want to load them just before their use if possible, knowing that my application is coded in ExtJS, and uses many ajax calls
You could look at using LABjs which is a script loader.
Old and busted:
<script src="framework.js"></script>
<script src="plugin.framework.js"></script>
<script src="myplugin.framework.js"></script>
<script src="init.js"></script>
New hotness:
<script>
$LAB
.script("framework.js").wait()
.script("plugin.framework.js")
.script("myplugin.framework.js").wait()
.script("init.js").wait();
</script>
Update:
If you want to load jQuery you could do something like this from this blog post.
<script type="text/javascript" src="LAB.js">
if (typeof window.jQuery === "undefined") {
$LAB.script("/local/jquery-1.4.min.js");
}
You can load an external file using javascript only when/where you need it:
function LoadJs(url){
var js = document.createElement('script');
js.type = "text/javascript";
js.src = url;
document.body.appendChild(js);
}
LoadJs("/path/to/your/file.js");
Here's a great post on the topic with a proposed solution you might want to check out: http://www.nczonline.net/blog/2011/02/14/separating-javascript-download-and-execution/