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.