Reputation: 2212
Even after reading some nice tutorials and blogposts on how to structure a Backbone Marionette app, I got confused while writing my own. Here is my setup.
I have an app that can easily be structured into different sub-apps (aka Backbone modules) Click on a link in my main navigation bar starts one of these apps. That means it loads the apps starting layout into my #main div.
But these apps have different layouts in themself, so navigating inside the app overwrites regions specified in the main app layout.
e.g.
var myApp = Backbone.Marionette.Application()
...
var layout = myApp.myModule.layout = new Backbone.Marionette.Layout()
...
myApp.main.show(myApp.myModule.layout)
where layout has the following DOM tree each mapped to a region
#app_main
.albums
.artists
Then I do something like
layout.app_main.show(new myView())
and from now on I can not get access to layout.albums or layout.artists even after using the back button (using a Backbone.Router and History)
Should I split my module's main layout to contain only #app_main, and load the opening layout into it at a separate step? Or do you have any other ideas?
Upvotes: 3
Views: 918
Reputation: 561
It would help to know a little bit more about what you're going for, but here's a shot at an answer. Let me know if it helps!
Let's say this is your HTML layout:
<div id="app">
<div id="app_nav">
<a href="#music">Music</a>
<a href="#books">Books</a>
</div>
<div id="sub_app"></div>
</div> <!-- /#app_main -->
For our "Music" sub-app, we'll use this template:
<script id="musicApp-template" type="template/html">
<div class="albums"></div>
<div class="artists"><div>
</script>
For the album item view:
<script id="album-template" type="template/html">
<img src="<%=albumThumbSrc %>" />
<p><%=albumTitle %></p>
</script>
For the artist item view:
<script id="artist-template" type="template/html">
<%=firstName %> <%=lastName %>
</script>
--
For our "Books" sub-app, we'll use this template:
<script id="booksApp-template" type="template/html">
<div class="books"></div>
<div class="authors"></div>
</script>
For the book item view:
<script id="book-template" type="template/html">
<img src="<%=bookThumbSrc %>" />
<p><%=bookTitle %></p>
</script>
For the artist item view:
<script id="author-template" type="template/html">
<%=firstName %> <%=lastName %>
</script>
And to bootstrap the app:
$(document).ready({
myApp.start();
if(!Backbone.history.started) Backbone.history.start();
});
--
Now to set up our Marionette views.
In myApp.js
var myApp = new Backbone.Marionnette.Application();
myApp.addRegions({
subAppRegion: "#sub_app"
});
// Your data
myApp.artists = new Backbone.Collection([...]);
myApp.books = new Backbone.Collection([...]);
In myApp.musicApp.js
myApp.module("musicApp", function(musicApp, myApp) {
/* Setup your Views
================== */
var MusicLayout = Backbone.Marionette.Layout.extend({
template: #musicApp-template",
regions: {
albumsRegion: ".albums",
artistsRegion: ".artists"
}
});
var AlbumView = Backbone.Marionette.ItemView.extend({
template: "#album-template"
});
var AlbumListView = Backbone.Marionette.CollectionView({
itemView: AlbumView
});
var ArtistView = ...
var ArtistListView = ...
/* Create router for app navigation
==================================== */
var Router = Backbone.Marionette.AppRouter.extend({
appRoutes: {
"music" : showMusicApp
},
controller: musicApp
});
new Router();
/* Method to show the music app
================== */
musicApp.showMusicApp = function() {
// Instantiate Views
var musicLayout = new MusicLayout();
var albumListView = new AlbumListView({ collection: myApp.albums });
var artistListView = new ArtistsListView({ collection: myApp.artists });
// Show musicApp layout in subAppRegion of main app
myApp.subAppRegion.show(musicLayout);
// Show albums and artists in musicApp layout
layout.albumsRegion.show(albumListView);
layout.artistsRegion.show(artistListView);
}
});
You can set up your myApp.booksApp
module much the same way:
myApp.module("booksApp", function(booksApp, myApp) {
...
var Router = Backbone.Marionette.AppRouter.extend({
appRoutes: {
"books" : showBooksApp
},
controller: booksApp
});
new Router();
booksApp.showBooksApp = function() {
...
myApp.subAppRegion.show(booksLayout)
...
}
...
});
I haven't tested all this code, so sorry if there are some kinks, and I'm sure it could be improved.
If you haven't already read David Sulc's tutorial, you should take a look - it will give you a better idea of a full fledged application. But I hope this gives you a basic idea of how you use layouts and regions to show different subApp views.
Upvotes: 3
Reputation: 3040
As a general rule in my own projects, I always keep elements defining regions empty and then load them dynamically in the Layout.onRender
method. This has the added benefit in Marionette.Async that if I need to load additional data from the server before displaying the view in the region, I can do so in the view's beforeRender
method.
One exception to my rule is showing an animated "loading..." div in the region's element which gets overwritten as soon as populate the region.
Upvotes: 0