Marionette LayoutView not rendering - javascript

Here is my LayoutView:
define(["marionette", "lodash", "text!home/template.html"],
function(Marionette, _, templateHTML) {
var HomeView = Marionette.LayoutView.extend({
template: _.template(templateHTML),
regions: {
ad: ".adspace",
products: ".products"
}
});
return HomeView;
});
Here is my app.js:
define(["marionette", "backbone", "router", "home/view"],
function(Marionette, Backbone, Router, HomeView) {
'use strict';
var App = new Marionette.Application();
App.on('start', function() {
Backbone.history.start();
new HomeView();
});
return App;
});
And here is my router.js
define(["backbone", "home/view"], function(
Backbone,
HomeView
){
'use strict';
var Router = Backbone.Router.extend({
routes: {
"": "index"
},
index: function() {
console.log("HEYEEY");
return new HomeView().render();
}
});
return new Router();
});
When I try to view the page in the browser, the layoutview isn't rendered. Not sure what I am doing wrong here

Try to either define an el property on the layoutView:
var HomeView = Marionette.LayoutView.extend({
el: "#dom-element",
template: _.template(templateHTML),
regions: {
ad: ".adspace",
products: ".products"
}
});
or use a region to show the layoutview:
var region = new Marionette.Region({"el": "#container"});
var layoutView = new HomeView();
region.show(layoutView);
This should work because LayoutViews are extended from regular Marionette Itemviews.

Related

How to structure a backbone application?

I am creating a backbone application which deals with user authentication and after successfully authenticating user loads the main app.
In the main app there is a main view which deals with loading menus and basic UI for app then router navigate to a page sub view which loads content dynamically into a container, the issue here is router navigate is called before base view is rendered and base view cannot find container to append content.
here is my appinit.js
/*global App, $*/
(function(){
'use strict';
window.Application = {
Models: {},
Collections: {},
Views: {},
Routers: {},
Configs: {},
init: function () {
var token = Cookies.get("access_token");
var router = new Application.Routers.Approuter;
Backbone.history.start();
//Check token to find if user is logged in or not
if(token!=undefined){
//Load base view for app
var appFrame = new Application.Views.Appframe;
} else {
//If user is not logged in load login view
router.navigate('login', {trigger: true});
}
}
};
$(document).ready(function () {
Application.init();
});
})();
My router file
/*global App, Backbone*/
Application.Routers = Application.Routers || {};
(function () {
'use strict';
Application.Routers.Approuter = Backbone.Router.extend({
routes: {
"login": "login",
"logout": "logout",
"products": "products"
},
login: function () {
new Application.Views.Login();
ReadyLogin.init();
},
products: function () {
var productsView = new Application.Views.Product;
$('#page-content-data').html(productsView.el);
},
logout: function () {
Cookies.remove('access_token');
Application.Configs.Users.token = '';
var router = new Application.Routers.Approuter;
router.navigate('login', {trigger: true});
}
});
})();
My base view file
/*global App, Backbone, JST*/
Application.Views = Application.Views || {};
(function () {
'use strict';
Application.Views.Appframe = Backbone.View.extend({
template: JST['app/scripts/templates/appframe.ejs'],
tagName: 'div',
initialize: function () {
_.bindAll(this, 'beforeRender', 'render', 'afterRender');
var _this = this;
this.render = _.wrap(this.render, function(render) {
_this.beforeRender();
render();
_this.afterRender();
return _this;
});
this.render();
},
beforeRender: function () {
},
render: function () {
var self = this;
var userModel = new Application.Models.Users;
userModel.fetch({ headers: {'Authorization' :'Bearer '+Application.Configs.Users.token} }).done(function () {
self.$el.html(self.template(userModel.toJSON()));
});
return this
},
afterRender: function(){
$('#page-container').html(this.el);
//After appending base load products route
var router = new Application.Routers.Approuter;
router.navigate('products', {trigger: true});
}
});
})();
I have been stuck on this since 3 days, Please help.
If you are using many iife's in a global module pattern:
var router = (function() {
return Backbone.Router.extend({ /** stuff... */ });
})();
var models = (function() {
return Backbone.Model.extend({});
})();
//more stuff
(function(router, models) {
var app = { router: router, models: models };
//init inside the iife
})(router, models);
If you want to keep everything in one iife
(function(router, models) {
var app = {
router: router(),
models: models()
};
//init in here
})(
function router() {
return Backbone.Router.extend({});
},
function models() {
return {
User: Backbone.Model.extend({}),
Foobar: Backbone.Model.extend({})
};
},
//etc...
);
But, this is messy, right? That's why bundlers exist :)
From my experience building backbone apps, I put all the navigation logic inside appRouter.
Try restructuring you app by transferring the various bits that you put in window.Application into the "" route and into appRouter.initialize. It might solve your problem. For instance something like this:
var AppRouter = new (Backbone.Router.extend({
routes: {
"": 'home',
"login": 'login'
},
initialize: function(){
//everything you need to initialize you app
},
start: function(){
Backbone.history.start();
},
home: function(){
//your initial routing logic (navigate to login if token is undefined)
},
login: function(){}
}));
$(function(){
AppRouter.start();
});

Backbone.js - Pass variable from route to view/collection/model

So I'm building a mobile website and I have a directory called 'api' with various php files hat echo JSON formatted data from a remote API. I did this to avoid the cross-domain issue.
But one of the php files needs a GET parameter (i.e. id) so that I can echo the JSON data for a specific object based on it's id.
My collection will need to do this (assuming this will work):
define([
'backbone',
'models/tournaments/single'
], function(Backbone, singleModel) {
var TournamentCollection = Backbone.Collection.extend({
model: singleModel,
url: '/api/tournament.php?id=' + id,
parse: function(response) {
return response;
}
});
return TournamentCollection;
});
I have this in my router, but how do I pass the 'id' value to the view or collection:
define([
'jquery',
'underscore',
'backbone',
'views/home',
'views/tournament'
], function($, _, Backbone, HomeView, TournamentView) {
var AppRouter = Backbone.Router.extend({
routes: {
'': 'home',
'tournament/:id': 'tournament'
}
});
var initialize = function() {
var app_router = new AppRouter;
app_router.on('route:home', function() {
var homeView = new HomeView();
});
app_router.on('route:tournament', function(id) {
var tournamentView = new TournamentView({id: id});
});
Backbone.history.start();
};
return {
initialize: initialize
};
});
Couple of things:
1) Your definition of the url property of the collection will not work as id is likely not defined when defining the TournamentCollection class. You can use a function rather than a property. TournamentCollection will become something like this:
define([
'backbone',
'models/tournaments/single'
], function(Backbone, singleModel) {
var TournamentCollection = Backbone.Collection.extend({
model: singleModel,
initialize: function (options) {
this.id = options.id;
},
url: function () {
return '/api/tournament.php?id=' + this.id
},
parse: function(response) {
return response;
}
});
return TournamentCollection;
});
This way you can initialize the object with an id, and later, when the url is fetched it will include the correct id.
2) I would probably initialize and fetch the collection from the router. Then from the initialize of the view, listen for that fetch to complete and ultimately re-render the view. Something like this:
define([
'jquery',
'underscore',
'backbone',
'views/home',
'views/tournament'
], function($, _, Backbone, HomeView, TournamentView) {
var AppRouter = Backbone.Router.extend({
routes: {
'': 'home',
'tournament/:id': 'tournament'
}
});
var initialize = function() {
var app_router = new AppRouter;
app_router.on('route:home', function() {
var homeView = new HomeView();
});
app_router.on('route:tournament', function(id) {
var tournaments = new TournamentCollection({ id: id });
tournaments.fetch();
var tournamentView = new TournamentView({ collection: tournaments });
});
Backbone.history.start();
};
return {
initialize: initialize
};
});
// Tournament View define stuff
var TournamentView = Backbone.View.extend({
initialize: function () {
this.listenTo(this.collection, 'sync', this.render);
},
render: function () {
//...
}
});
return TournamentView
hope that helps. :)

Backbone.js - 404 jQuery error on navigate

Navigation is not working as I expected, when I trigger goToTournament (see below) the current view just re-renders and I get a jQuery 404 not found error on the console. The URL is changing appropriately and the correct route method is being triggered as well.
// js/views/home.js
define([
'jquery',
'jquerym',
'underscore',
'backbone',
'models/tournaments/featured',
'collections/home',
'text!/templates/home.html'
], function($, JQM, _, Backbone, FeaturedModel, HomeCollection, homeTemplate) {
var HomeView = Backbone.View.extend({
el: $('#site-main'),
events: {
'click .tournament': 'goToTournament'
},
initialize: function() {
this.render();
},
render: function() {
var homeCollection = new HomeCollection();
homeCollection.fetch({
success: function() {
var data = {tournaments: homeCollection.toJSON()};
var compiledTemplate = _.template(homeTemplate, data);
$('#site-main').html(compiledTemplate);
$('.main-content').fadeTo(500, 1);
return this;
}
});
},
goToTournament: function(e) {
this;
var t_id = $(e.currentTarget).data('id');
var router = new Backbone.Router();
router.navigate('tournament/' + t_id, {trigger: true})
}
});
return HomeView;
});
// js/router.js
define([
'jquery',
'underscore',
'backbone',
'views/home',
'views/tournament',
'collections/tournament'
], function($, _, Backbone, HomeView, TournamentView, TournamentCollection) {
var AppRouter = Backbone.Router.extend({
routes: {
'': 'home',
'tournament/:id': 'tournament'
}
});
var initialize = function() {
var app_router = new AppRouter;
app_router.on('route:home', function() {
var homeView = new HomeView();
});
app_router.on('route:tournament', function(id) {
var tournament = new TournamentCollection({ id: id });
tournament.fetch({
success: function() {
var tournamentView = new TournamentView({collection: tournament});
}
});
});
Backbone.history.start();
};
return {
initialize: initialize
};
});
I got it working by completely disabling jquery mobile's loading method. I made a jqm-config.js file and made sure it was caled before jquery mobile itself.

How do I reset all events in the Backbone

I want to restart all JQuery events in Backbone. The problem is this: when you go to the particular view I have the following event:
el: $('#content'),
events : {
'click #stops-drop-down' : 'stopDropDown',
},
stopDropDown: function(ui){
console.log("Event");
$("#stops-drop-down").toggleClass("focus-box");
$("#stops-list").slideToggle();
}
When you return to the previous view from which I've come to current and again go back to current and use the event, it is already running 2 times, if you do the same exercise another way it 3 times and it begins to grow. How can I deal with this problem and open the reset each time events?
Also to mention that use Requirejs. Here's what it looks like my router .js
define([
'jquery',
'underscore',
'backbone',
'views/home/home',
'views/line/line',
], function($, _, Backbone, HomeView, LineView){
var AppRouter = Backbone.Router.extend({
routes: {
'': 'homePage',
'line/:line/:type_transport': 'lineDetails',
'*action': 'errPage'
}
});
var initialize = function(){
var self = this;
var app_router = new AppRouter;
app_router.on('route:homePage', function() {
var homeView = new HomeView();
});
app_router.on('route:lineDetails', function(line, typeTransport) {
var lineDetailsView = new LineView();
lineDetailsView.render(line, typeTransport);
})
app_router.on('route:errPage', function() {
alert("Err Page");
});
Backbone.history.start();
};
return {
initialize: initialize
};
});
SOLUTION:
I decided my problem as follows: I created the close method, which has the following content:
close: function(){
this.undelegateEvents();
$(this).empty;
this.unbind();
},
Also, here's how it seems my router.js now:
define([
'jquery',
'underscore',
'backbone',
'views/home/home',
'views/line/line',
], function($, _, Backbone, HomeView, LineView){
var AppRouter = Backbone.Router.extend({
routes: {
'': 'homePage',
'line/:line/:type_transport': 'lineDetails',
'*action': 'errPage'
}
});
var initialize = function(){
var self = this;
var app_router = new AppRouter;
var lineDetailsView;
var homeView ;
app_router.on('route:homePage', function() {
if(homeView) {
homeView.close();
}
homeView = new HomeView();
});
app_router.on('route:lineDetails', function(line, typeTransport) {
if(lineDetailsView){
lineDetailsView.close();
}
lineDetailsView = new LineView();
lineDetailsView.render(line, typeTransport);
})
app_router.on('route:errPage', function() {
alert("Err Page");
});
Backbone.history.start();
};
return {
initialize: initialize
};
});
var YourView = Backbone.View.extend({
el: $('#content'),
events : {
'click #stops-drop-down' : 'stopDropDown',
},
close : function(){
this.remove(); // removes view from dom
this.unbind(); // unbinds all the events associated with the view
},
stopDropDown: function(ui){
console.log("Event");
$("#stops-drop-down").toggleClass("focus-box");
$("#stops-list").slideToggle();
}
});
// check if view already exists before creating new instance
// if exists call close on that view -- and then create your new view
if(yourView)
yourView.close();
yourview = new YourView();
check this article , there may be other reasons for the view to still exist
EDIT
this is almost the same way i have done in my application make sure you add close function as property in all views
define([
'jquery',
'underscore',
'backbone',
'views/home/home',
'views/line/line',
], function($, _, Backbone, HomeView, LineView){
var AppRouter = Backbone.Router.extend({
routes: {
'': 'homePage',
'line/:line/:type_transport': 'lineDetails',
'*action': 'errPage'
}
});
var initialize = function(){
var self = this;
var app_router = new AppRouter;
app_router.on('route:homePage', function() {
if(homeView)
homeView.close();
var homeView = new HomeView();
});
app_router.on('route:lineDetails', function(line, typeTransport) {
if(lineDetailsView)
lineDetailsView.close();
var lineDetailsView = new LineView();
lineDetailsView.render(line, typeTransport);
})
app_router.on('route:errPage', function() {
alert("Err Page");
});
Backbone.history.start();
};
return {
initialize: initialize
};
});

BackboneJS: getting uncaught type error in backbone.js

I am new to backbonejs. I am facing the following error
Uncaught TypeError: undefined is not a function backbone.js:26
Here is my code
index.php inside script tag
<script>
new App.Router;
Backbone.history.start();
App.contacts = new App.Collections.Contacts;
App.contacts.fetch().then(function () {
new App.Views.App({ collection: App.contacts });
});
</script>
main.js
(function ($) {
window.App = {
Models: {},
Collections: {},
Views: {},
Router: {}
};
window.vent = _.extend({}, Backbone.Events);
})(jQuery);
router.js
App.Router = Backbone.Router.extend({
routes: {
'': 'index'
},
index: function () {
console.log('index page');
}
});
collections.js
App.Collections.Contacts = Backbone.Collection.extend({
model: App.Models.Contact,
url : '/contacts'
});
models.js
App.Models.Appoinment = Backbone.Model.extend({
//validate
});
views.js
//Global App view
App.Views.App = Backbone.View.extend({
initialize: function () {
console.log(this.collection.toJSON());
}
});
What am I doing wrong here?
I found the solution. Here what I did
Inside collections.js I was pointing to App.Models.Contact whereas I did not have this model. I created it and now it works.

Categories