backbone js not routing to my url - backbone.js

I have the set up below; backbone routing does not kick in on clicking on the products or sales link
DO I have to call navigate from the view explicitly?
<script type="text/javascript">
$(function () {
var Router = Backbone.Router.extend({
routes: {
"Products": "products",
"Sales": "sales"
},
products: function () {
console.log('products');
},
sales: function () {
console.log('sales');
}
});
new Router();
Backbone.history.start();
});
</script>
And I have 2 links for products in the aspx page
<div id= "Store">
<ul>
<li>Products </li>
<li> Sales </li>
</ul>
</div>

The only problem I can see with your code is that app.init is undefined, so the script crashes before hitting the router. If I simply add a stub for that method (or remove app.init()), then the routes get triggered as you expect.
var app = {
init: function() {}
};
See here: http://jsfiddle.net/ZnrPd/2/

Related

Backbone multi routers trap - sub router handler doesent invoke

got in trap with Backbone Router. Imagine, i have 2 Backbone Routers:
1) RootRouter - has only one route and the only responsibility - load subRouters with RequireJS and instance it.
var RootRouter = Backbone.Router.extend({
routes: {
'*all': 'invokeSubModule'
},
invokeSubModule: function(route, args) {
require(['SubRouter'], function(subRouter) {
new subRouter()
})
}
});
2) SubRouter - standard BB router with routes hash and handlers.
var SubRouter = Backbone.Router.extend({
routes: {
'some/bar': 'doBar',
'some/foo': 'doFoo'
},
doBar: function() { ... },
doFoo: function() { ... }
});
I start the application from some/bar URL.
On start RootRouter instancing and Backbone.History starts.
As expected RootRouter - match any URL and fire invokeSubModule - async load and SubRouter instancing works as expected, but the problem is associated with some/bar SubRouter handler does not firing as page URL has not changed from last route.
Looking for solution i've found answers only for the case u load sub routers before history start, but it useless in my case.
So after some digging i've found solution - extend Backbone.Route and override route method to make possible to invoke handler if the Backbone.getHash() is equal to the route method operate with.
Backbone.Router.extend({
route: function(route, name, callback) {
...
if (!callback) callback = this[name];
/* run handler immediately if route we add is the current URL fragment */
if(routeRegexp.test(Backbone.history.getHash()) ) {
this.execute(callback, this._extractParameters(routeRegexp, routeStr));
}
Backbone.history.route(route, function(fragment) {
....
});
return this;
}
})
So i'm confused that this just a hack and may cause possible bugs in future.
So looking for best practice how to resolve such issue and critic of my solution.
Also expect as possible answer how to manage routers lazy loading without RootRouter, as in this case first route will not be fired.
i was able to replicate the behavior you need without hacking the internals of backbone routing, but i have to do some stuff in the initialization.
first i will create the main router and start backbone history in with silent option = true
var mainRouter = new RootRouter();
Backbone.history.start({silent: true});
this will start backbone history, but without routing the current url.
then i got the current fragment and saved it for later use, then navigated to the base url, then back to the original fragment
var fragment = Backbone.history.fragment;
mainRouter.navigate('reset',true);
mainRouter.navigate(fragment, true);
the bad side of this approach is that you need to do 2 routing on start up
UPDATE:
below the full sample
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title> sample </title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="http://underscorejs.org/underscore-min.js"></script>
<script type="text/javascript" src="http://backbonejs.org/backbone-min.js"></script>
<style type="text/css">
</style>
<script>
var RootRouter = Backbone.Router.extend({
routes: {
'*all': 'invokeSubModule',
'reset': 'invokeSubModule',
},
invokeSubModule: function(route, args) {
new SubRouter();
},
navigate: function () {
Backbone.Router.prototype.navigate.apply(this, arguments);
},
execute: function(callback, args) {
console.log('execute root');
Backbone.Router.prototype.execute.apply(this, arguments);
console.log ('current fragment ' + Backbone.history.fragment);
}
});
var SubRouter = Backbone.Router.extend({
routes: {
'some/bar': 'doBar',
'some/foo': 'doFoo'
},
navigate: function () {
Backbone.Router.prototype.navigate.apply(this, arguments);
},
execute: function(callback, args) {
console.log('execute sub');
Backbone.Router.prototype.execute.apply(this, arguments);
console.log ('current fragment ' + Backbone.history.fragment);
},
doBar: function() {
$('#content').html('').append('<p>BAR</p>');
},
doFoo: function() {
$('#content').html('').append('<p>FOO</p>');
}
});
$(document).ready(function(){
var mainRouter = new RootRouter();
Backbone.history.start({silent: true});
var fragment = Backbone.history.fragment;
mainRouter.navigate('#',true);
mainRouter.navigate(fragment, true);
$('a').click(function(){
mainRouter.navigate($(this).attr('href'));
});
});
</script>
</head>
<body>
<a id='home' href="#">home</a></br>
<a id='foo' href="#/some/foo">foo</a></br>
<a id='bar' href="#/some/bar">bar</a></br>
<div id='content'>HOME</div>
</body></html>

adding more than one sources of data to angular

this is what I have in my model
// The contents of individual model .js files will be concatenated into dist/models.js
(function() {
// Protects views where angular is not loaded from errors
if ( typeof angular == 'undefined' ) {
return;
};
var module = angular.module('myModel', ['restangular']);
module.factory('myRestangular', function(Restangular) {
return Restangular.withConfig(function(RestangularConfigurer) {
RestangularConfigurer.setBaseUrl('http://localhost/data');
RestangularConfigurer.setRequestSuffix('.json');
RestangularConfigurer.setRestangularFields({
id: "my_id"
});
});
});
})();
this is fine. but now I have another json that I need to grab data from. How could I change this model to look for that other json as well. I am very very new to angular and still learning how model data binding works!
*This is what I have tired *
my model
var module = angular.module('FloorModel', ['restangular']);
module.factory('FloorRestangular', function(Restangular) {
return Restangular.withConfig(function(RestangularConfigurer) {
RestangularConfigurer.setBaseUrl('http://localhost/data/floor');
RestangularConfigurer.setRequestSuffix('.json');
RestangularConfigurer.setRestangularFields({
id: "floor_id"
});
});
});
**my controller**
myApp.controller('FloorCtrl', function ($scope, $filter, FloorRestangular) {
// Fetch all objects from the local JSON (see app/models/mdpocket.js)
FloorRestangular.all('floor').getList().then( function(floors) {
// Then select the one based on the view's id query parameter
$scope.floor = $filter('filter')(floors, {floor_id: steroids.view.params['id']})[0];
});
// -- Native navigation
steroids.view.navigationBar.show("Floor: " + steroids.view.params.id );
});
*my view *
<div ng-app="myApp">
<div ng-controller="FloorCtrl">
<div class="topcoat-list__container">
<ul class="topcoat-list">
<li class="topcoat-list__item" hm-tap="open(floor.floor_id)" ng-repeat="floor in floors">
Floor Name: {{ floor.name }}
</li>
</ul>
</div>
</div>
</div>

Nothing displayed on-screen and no errors, but JavaScript objects are populated

This is my first trial on backbone + marionette + require + handlebars. I will provide the full explanation on what I did, and I have no clue on why it doesn't work. I removed all possible JavaScript errors, and everything gets properly loaded. So, no errors in the console, but the page stays entirely blank.
What it represents is a simple header menu with buttons (an unordered list of buttons to be displayed in the header).
Index.php
<head>
<meta charset="UTF-8">
<title>Zwoop</title>
<link rel="stylesheet" type="text/css" href="http://www.zwoop.be/dev/css/layout.css">
</head>
<body>
<script id='zwoop_interface' type='text/template'>
<div id="headerRegion">
</div>
<div id="mainRegion"></div>
</script>
<script src="http://www.zwoop.be/dev/js/libs/require/require.js" data-main="js/main"></script>
</body>
main.js
Notes: I don't receive any JavaScript errors and the JS files are properly loaded (I checked this in the browser).
//Require.js
require.config({
baseUrl: 'js',
paths : {
jQuery : '//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min',
jQueryUI : '//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min',
lodash : 'libs/lodash/lodash',
backbone : 'libs/backbone/backbone',
marionette : 'libs/marionette/marionette',
handlebars : 'libs/handlebars/handlebars-v1.1.2',
text : 'libs/require/text',
localstorage : 'libs/backbone/localstorage'
},
shim : {
backbone: {
deps : ['jQuery', 'lodash'],
exports : 'Backbone'
},
marionette: {
deps : ['backbone'],
exports : 'Marionette'
},
handlebars: {
exports: 'Handlebars'
}
}
});
require(["backbone","marionette", "views/main_menuView"], function (Backbone, Marionette, Main_menuView) {
var Zwoop = new Marionette.Application();
//Pass options if required
var options = {
};
//Initialize functions
Zwoop.on("initialize:before", function(options){
console.log("test");
});
Zwoop.addInitializer(function(options){
var Main_Layout = Marionette.Layout.extend({
template: "#zwoop_interface",
regions: {
headerRegion: "#headerRegion",
bodyRegion: "#bodyRegion"
}
});
var main_layout = new Main_Layout();
//Rendering the layout is required before you can show anything within the regions
main_layout.render();
main_layout.headerRegion.show(Main_menuView);
console.log("rendered"); //This console log works
});
Zwoop.vent.on("main_layout:rendered", function(){
//Initialize router
new ZwoopRouter();
Backbone.history.start();
console.log("router started"); //This one is not called; I don't know why
});
//Start the application
Zwoop.start(options);
return Zwoop;
});
3_ main_menuView.js
Notes: I console logged 'Main_MenuCollection.toJSON()' and the object is properly set.
define([
'jQuery',
'marionette',
'handlebars',
'text',
'text!templates/main_menu.html',
'models/main_menuModel'
], function ($, Marionette, Handlebars, Text, Main_menu_tpl, Main_MenuCollection) {
'use strict';
var Main_MenuView = Marionette.ItemView.extend({
initialize: function () {
_.bindAll(this, 'render');
this.render();
},
el: '#headerRegion',
template: Handlebars.compile(Main_menu_tpl),
events: {
'click .main_menu_item':'select_menu'
},
select_menu: function(){
console.log("clicked");
},
render: function () {
this.$el.html(this.template({
models: Main_MenuCollection.toJSON()
}));
return this;
}
});
var main_menuView = new Main_MenuView();
return main_menuView;
});
4_ main_menu.html
This is the template that I used:
<ul id="main-menu">
{{#each models}}
<li><a id="{{models.id}}" href="{{models.href}}" class='main_menu_item'">{{models.label}}</a></li>
{{/each}}
</ul>
4_ main_menuModel.js model + collection
Note: Also here, I console logged the collection before returning it, and it is properly set.
define([
'backbone'
], function(Backbone){
var Menu_ItemModel = Backbone.Model.extend({
initialize: function(){
},
//These are data that are related to the main menu
defaults: {
id: 'undefined',
href: 'undefined',
label: 'undefined'
}
});
var btn_bars = new Menu_ItemModel({id:'btn_bars', href: 'bars', label:'Bars'});
var btn_eat = new Menu_ItemModel({id:'btn_eat', href: 'places_to_eat', label:'Places to eat'});
var btn_events = new Menu_ItemModel({id:'btn_events', href: 'events', label:'Bars'});
var btn_touristic = new Menu_ItemModel({id:'btn_touristic', href: 'touristic', label:'Touristic places'});
var btn_hotels = new Menu_ItemModel({id:'btn_hotels', href: 'hotels', label:'Hotels'});
var btn_shops = new Menu_ItemModel({id:'btn_shops', href: 'shops', label:'Shops'});
var btn_companies = new Menu_ItemModel({id:'btn_companies', href: 'companies', label:'Companies'});
var Main_MenuCollection = Backbone.Collection.extend({
initialize: function(){
},
model: Menu_ItemModel
});
var main_menuCollection = new Main_MenuCollection();
main_menuCollection.add([
btn_bars,
btn_eat,
btn_events,
btn_touristic,
btn_hotels,
btn_shops,
btn_companies
]);
return main_menuCollection;
});
The first attempt, and I'm not quite experienced yet so I really don't see where to find the problem. Do you have any suggestions?
Your main_layout gets rendered, but never shown. This seems to be the main issue.
In addition, console.log("router started") might not get called, because although you define a listened for the "main_layout:rendered" event, I don't see it getting triggered anywhere.
Also, it seems you might be confused about layouts VS regions : regions remain "static" with the application, whereas layouts are removed and redisplayed as the user navigates through the app. So for example, you'd use a region to display the app's header menu, but you'd use a layout to display (e.g.) the user's homepage (so you can organize the various sub-views). In other words, you create application regions to segment areas in your application that will always be displayed (e.g. header, main content, footer), and then you can also use layouts (with declared regions) to organize views that require sub-views (e.g. a "user profile" page with a "last comments" region, a "contact info" region, etc.). they have the same name, but think of application regions as "areas" in the application, and layout regions as "parts of a big, ciomplex view".
Last but not least, you might want to consider using layouts like this https://github.com/davidsulc/marionette-gentle-introduction/blob/master/assets/js/apps/contacts/list/list_controller.js#L43 (from my Marionette book) : note that we use the lyout's "show" event listener to then display the sub-views. This means we don't need to call render manually, which is more in line with Marionette's conventions.

Simple Backbone.js and Google Maps Rendering

I'm having trouble rendering Google Maps (V3) with Backbone.js.
It fails to load when I navigate to map view (/#/map); however, the map somehow loads perfectly fine when I hit refresh in that map view url.
Relevant Code Below:
<body>
Home
<div id="content"></div>
<script type="text/template" id="home_template">
Go !
</script>
<script type="text/template" id="map_template">
<div id="map"></div>
</script>
</body>
var MapView = Backbone.View.extend({
el: '#content',
render: function() {
var template = _.template($('#map_template').html());
var init = function() {
var mapOptions = {
center: new google.maps.LatLng(-34.397, 150.644),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map"),
mapOptions);
}
google.maps.event.addDomListener(window, 'load', init);
this.$el.html(template);
}
});
var Router = Backbone.Router.extend({
routes: {
"" : "home",
"map" : "map"
}
});
var router = new Router;
var homeView = new HomeView();
router.on('route:home', function() {
homeView.render();
});
var mapView = new MapView();
router.on('route:map', function() {
mapView.render();
});
Backbone.history.start();
It seems that 'something' is missing when I'm switching views between home and map, but I'm not sure what that 'something' is. I believe I have combed through relevant questions, but cannot find the missing point.
Any help would be much appreciated.
Thank you!
(P.S The Mapview part is taken from : https://developers.google.com/maps/documentation/javascript/tutorial
)
Problem is here I guess
google.maps.event.addDomListener(window, 'load', init);
you are calling init on window.load, but when you switch between view, it will not refresh the page, and window.load never get triggered. I guess you need to change the way init happening, I could be able to suggest better if I have more information about DOM structure of the page.

router function not triggering

In my backbone function, i am navigating a id to routers, but the function not calling... as well i have given the different sample navigate urls to my links, those are not calling the functions..
mycode :
(function($){
var myRouter = Backbone.Router.extend({
routes:{
"":"defaultRoute", //onload it works
'#/name/:id':"nameData",
// i am calling this function on default Router
'#/project/:id':"projectData"
},
defaultRoute:function(){
console.log('default')
startRoute.navigate("#/name/3"); // i am redirecting
},
nameData:function(id){
console.log(id); // id not consoling not called this func.
},
projectData:function(project){
console.log(project);
}
});
var startRoute = new myRouter();
Backbone.history.start();
})(jQuery);
my url : http://localhost:85/router/web/#/name/3
my html :
<ul class="name">
<li>name1</li>
<li>name2</li>
<li>name3</li>
<li>name4</li>
<li>name5</li>
</ul>
any one find me the wrong this what i do here.. please
All my functions are correct, by mistrake i added the hash on the routes prams.
update function here:
(function($){
var myRouter = Backbone.Router.extend({
routes:{
"":"defaultRoute",
'name/:id':"nameData",
'product/:id':"projectData"
},
defaultRoute:function(){
console.log('i am default');
},
nameData:function(e,id){
console.log(id);
},
projectData:function(project){
console.log(project);
}
});
var startRoute = new myRouter();
Backbone.history.start();
})(jQuery);

Resources