I'm starting a marionette app and I try to structure it. So now I have:
define(["marionette", "handlebars", "routes"], function(Marionette, Handlebars, Route){
var App = new Marionette.Application();
...
App.addRegions({
header: "#header_region",
...
});
App.addInitializer(function(options){
...
new Route();
Backbone.history.start();
});
return App;
});
and my routes looks like:
define(["marionette", "app", "header/view"], function(Marionette, App, headerView){
var Route = Backbone.Marionette.AppRouter.extend({
routes : {
'' : 'home'
},
home: function(){
var header_view = new headerView();
App.header.show(header_view);
...
}
});
return Route;
});
Obviously I have a loop in dependencies here with App.header.show(header_view). What is the common way to solve it? How do you structure your Marionette app?
This was a great example that helped to get me going when building my first Marionette App: https://github.com/BoilerplateMVC/Marionette-Require-Boilerplate/tree/master/public/js/app
The way you currently have your route file set up is the backbone way of doing it. You should create a Marionette Controller that will respond to the App routes.
Also, you'll see that this person creates init files to specify all of the start up logic (specifying global static variables and instantiating the controller and router to be used).
Hope this helps!
Related
I am currently working on a Backbone JS application, and I started using Browserify for the first time. But of course I ran into a few problematics. This is one of them.
I have the following module, /js/views/Home.js.
var $ = require('jquery'),
_ = require('underscore'),
Backbone = require('backbone');
Backbone.$ = $;
module.exports = Backbone.View.extend({
el: '#view',
template: _.template($('#home-template').html()),
initialize: function () {
this.render();
},
render: function () {
this.$el.html(this.template());
},
events: {
'click button': 'searchSubmit'
},
searchSubmit: function () {
// this should be where the magic happens
}
});
When the searchSubmit method is called, I want to do something like router.navigate('search').
My question: If I have a router module, Router.js, do I then need to create a new instance of it in all of my modules every time I want some router functionality?
var Router = require('./Router.js'),
router = new Router();
It just does not seem logical to create a new router in every view, when Browserify bundles them all together.
Is it me who do not understand Browserify properly, and is there a more clever solution? Thanks!
When you call
var Router = require('./Router.js');
Browserify is actually keeping track of a single instance of Router, so it is not a new instance every time. Think of it as a reference or using statement. See this SO post for more details.
But with router = new Router(); you run into a problem of your router being instanced. I suggest that in Router.js you export an instance of your router.
I'm working on my first large front-end application built with Marionette.js framework. By now I have module BlogApp, which is small blog sub-appliaction with only 2 methods list(to list all posts) and show (to display single post by id):
#MainApp.module "BlogApplication", (BlogApplication, App, Backbone, Marionette, $, _) ->
class BlogApplication.Router extends Marionette.AppRouter
appRoutes:
"blog" : "list"
"posts/:id" : "showPost"
API =
list: ->
BlogApplication.List.Controller.list()
showPost: (id, post) ->
BlogApplication.Show.Controller.showPost id, post
App.addInitializer ->
new BlogApplication.Router
controller: API
App.vent.on "blog:post:clicked", (post) ->
App.navigate Routes.post_path(post.id)
API.showPost post.id, post
App.on "blog:list": ->
App.navigate("blog")
API.list()
My folders are organized like this:
--blog
-blog_app.js
--list
--templates
-blog_sidebar.template
-blog_panel.template
-blog_layout.template
-blog_post.template
-list_controller.js
-list_view.js
--show
--templates
-blog_sidebar.template
-blog_panel.template
-blog_layout.template
-blog_post.template
-show_controller.js
-show_view.js
Everything works fine.
The only difference between the show and list pages - is displaying one full post instead of listing them all. Now I have 2 controllers and I'm duplicating my templates for show and list methods, which is totally not a good practice. But I also don't think that I should implement my show method in List.Controller - it will help me to use same templates, because it will break my application infrastructure and in future, when I have to add some features, for example - comments,tags etc, it will mess up everything. How should I organize my blog module the right way?
The way I organise my code has been working overall well without any memory leaks (afaik) until now.
I will share this with you and for any people who might find this useful.
I will also provide some supplementary information on how I manage the memory.
1) For the folder structure I have something like:
folder: apps
folder: app_blog.js
folder: layouts (for views + templates)
folder: views (for views + templates)
folder: => here comes the name of one or more sub-apps
folder: layouts
folder: views
file: ctr_list.js => a Marionette controller
file: app_blog
folder: components
folder: models
folder: vendor
file: main.js
file: app.js
In my application, the app_blog is an app (folder) that uses an app_name.js file to manage the routes, and bootstrap the subapps, and controllers to manage subsections of the app.
When a route is hit:
//1. render layout
var layout = new Layout();
layout.render();
//2. instantiate controller & tell the controller what to do
var ctr_List = new Ctr_List();
ctr_list.showList();
A controller in my application has the following format:
define(["backbone", "marionette", "jquery", "zwoop", "apps/app_blog/list/views/some_view"
],
function(Backbone, Marionette, $, Zwoop, Some_View){
var Ctr_List = Marionette.Controller.extend({
initialize: function(options){
this.events();
this.region = new Marionette.Region({ el: #some-region });
//Define more regions if you need to
},
events: function(){
app.on("reset", _.bind(function(){ this.close(); }, this));
app.on("dosomething", _.bind(function(param){ this._doSomething(); }, this));
this.events();
this.region.on("show", _.bind(function(){ this.activatePlugin(); }, this));
},
showList: function(){
this._showList();
},
_showList: function(){
//Render the list
var some_view = new Some_View();
this.region.show(some_view);
},
_doSomething(param){
},
_activatePlugin(){
//eg. $("#date-input").datepicker();
},
//Unbind all events
onClose: function(){
app.off("doSomething");
this.region.off("show");
}
});
return Ctr_List;
});
Then when another route gets triggered and another app is started, I will call app.trigger("reset") if necessary to close the controller and unbind events that were bound by the controller.
So far, this has worked well for me.
I am generating a static site using Jekyll. I am using backbone.js to do few routings.
Suppose the home page is at localsite.com... I am not sure how to generate routes for the following URLs.
http://localsite.com/hulk &
http://localsite.com/thor
The hulk and thor are the names to be routed.
and my backbone.js router is as follows:
<script>
var AppRouter = Backbone.Router.extend({
routes: {
":name": "nameRoute" // should match http://localsite.com/anything-here
}
});
// Initiate the router
var app_router = new AppRouter;
app_router.on('route:nameRoute', function(name) {
console.log(name);
})
Backbone.history.start({pushState: true});
</script>
I am not able to get this working. Is there something I am missing?
Will I be able to do this routing with Jekyll?
My Jekyll's _config.yml has
permalink: pretty
How do get these routes working?
Are there any other suggestions? My goal is to get a similar routing when hosted on github pages.
As far as the routing goes, it is pretty straight forward. The second part is the name of the function that will be called, which should be defined inside your router. So just change your code to this and it should work:
var AppRouter = Backbone.Router.extend({
routes: {
":name": "nameRoute" // should match http://localsite.com/anything-here
},
nameRoute: function(name){
console.log(name);
}
});
// Initiate the router
var app_router = new AppRouter;
Backbone.history.start({pushState: true});
If you run into trouble with pushState and getting rid of the backbone-default hashtags, check out this SO question BackboneJS - Router issues - how to get clean URL's (particularly important for local links, if you don't want to keep reloading from the server), and here is an example of a site getting rid of their #: http://artsy.github.io/blog/2012/06/25/replacing-hashbang-routes-with-pushstate/
I am just starting to learn backbone js. I am not understanding the router. I have written a simple code. What it should do is to print 'I am working' in the console. But it is not working.
$(document).ready(function(){
var AppView = Backbone.View.extend({
el: 'body',
initialize: function(){
console.log('this is working');
}
});
var AppRouter = Backbone.Router.extend({
routes: {
'': function(){
var a = new AppView();
}
}
});
var ar = new AppRouter();
Backbone.history.start();
});
You almost certainly have a Backbone version problem. The 1.0.0 Change Log entry says:
The routes in a Router's route map may now be function literals, instead of references to methods, if you like.
And you can even find the trivial one line change in the revision history that made this new behavior possible.
Older versions of Backbone wanted route method names in routes and didn't know what to do with functions. Upgrade to the most recent Backbone (and Underscore and jQuery) and your code will work.
Demo: http://jsfiddle.net/ambiguous/sfeCr/1/
When building a relatively large application, how should I define my router? More specifically, if using requirejs I have the following code:
main.js
define('application',['routes/app_router'], function(router){
return Ember.Appcliation.create(
LOG_TRANSITIONS:true,
...
});
requirejs('application',function(application){
var App = window.App = application;
...
}
and in the routes/ I have app_router.js
define('app_router',['ember'],function(){
...
});
So should I pass an app to my app_router to set the App.Router.map... method or should I return a Ember.Router.map(...)? If the first variant is chosen then for sure, the dependencies change.
In other words, should I create an "empty" Ember.Application and pass it to the router so it can define the App.Route.map(... method, since it has reference to this, like this.route\this.resource..., or should I invoke Ember.Router.create() then invoke the map function on it, then return this from the module and set it to App.Router = router.
So should I pass an app to my app_router to set the App.Router.map... method or should I return a Ember.Router.map(...)? If the first variant is chosen then for sure, the dependencies change.
I'd go with the 2nd variant.
In other words, should I create an "empty" Ember.Application and pass it to the router so it can define the App.Route.map(... method, since it has reference to this, like this.route\this.resource..., or should I invoke Ember.Router.create() then invoke the map function on it, then return this from the module and set it to App.Router = router.
Neither. You should let ember create the router itself. All your code should be doing is calling App.Router's map fx. I'm no require.js expert, but something like this should work:
//Define a fx that specifies your applications routes
define('routes',['ember'], function(){
return function() {
this.route("about");
}
});
// Pass that custom routes fx to App.Router.map before routing begins
define('application',['routes'], function(routes){
return Ember.Application.create({
LOG_TRANSITIONS: true,
ready: function() {
this.Router.map(routes);
}
});
Here's a jsfiddle showing the basic concept, without require.js of course.