So I have the following backbone route:
Nightbird.Routers.Errors = Nightbird.Routers.Core.extend({
routes: {
'server_error': 'serverError',
},
initialize: function(){
console.log('dasddasd');
},
serverError: function() {
console.log('asdasdasd');
var serverErrorView = new Nightbird.Views.ServerError();
serverErrorView.render();
}
});
it does come into this class because the initialize function is being called, when this route loads I see: dasddasd in the console, but I do no see asdasdasd
The url is localhost:9000/#server_error
Can some one explain what I am doing wrong? I am not sure what else I am suppose to provide for further information so please ask for any additional details.
Additional
The following is how the app gets registered:
window.Nightbird = {
Models: {},
Collections: {},
Views: {},
Routers: {},
blogId: 0,
initialize: function() {
if (window.Development === undefined && window.Production === undefined) {
throw 'Production class (Production.config.js) cannot be missing. App Cannot load.';
}
if (window.Development !== undefined) {
this.blogId = window.Development.BLOG_ID;
} else {
this.blogId = window.Production.BLOG_ID;
}
new Nightbird.Routers.Posts();
new Nightbird.Routers.Errors();
if (!Backbone.History.started) {
Backbone.history.start();
} else {
Backbone.history.stop();
Backbone.history.start();
}
}
}
This class extends:
Nightbird.Routers.Core = Backbone.Router.extend({
serverError: function(){
Backbone.history.navigate("server_error", {trigger: true});
}
});
Why such a simple abstraction, because this way any issue getting or posting or what have you can redirect you to a server error route.
Then in my index.html I do:
<!DOCTYPE html>
<html>
<body>
<div id="manage">
</div>
</body>
<script src="js/compiled.js"></script>
<script>
Nightbird.initialize();
</script>
</html>
I guess that the problem is the way that you're instantiating the Backbone Router
Try to create the Backbone Router inheriting from Backbone.Router.
When you check if Backbone.History.started is true, it probably is not. so it will go to else statement, and there at that moment Backbone.History.star() is undefined. So it is never starting the Backbone.History
Hope it helps.
Related
I'm trying to wrap the plugin Justified Gallery in an Ember component. The main problem that I'm facing is that the list of photos in the gallery come from an API, so they're part of the model. What I have so far:
App.JustifiedGalleryComponent = Ember.Component.extend({
_init: function() {
this.$().justifiedGallery({
rowHeight: 150,
fixedHeight: false,
margins: 7
});
}.on('didInsertElement')
});
Template
{{#each photo in items}}
<div>
<img src={{photo.thumbUrl}} />
</div>
{{/each}}
But I can't get that to work, probably because the list of photo is inside an each loop, and when the plugin is applied the photos are still not in the DOM? What would be the approach for this problem?
Thanks!
EDIT:
Taking as a reference the component for Masonry I've got this almost sorted, but the first time that I navigate to the URL nothing shows, if I go to a second route (inside the ember app) and go back to the gallery then it displays fine and justified. This is my component now:
import Ember from 'ember';
var getOptions = function (keys) {
var properties = this.getProperties(keys);
Object.keys(properties).forEach(function (key) {
if (properties[key] === "null") {
properties[key] = null;
}
if (properties[key] === undefined) {
delete properties[key];
}
});
return properties;
};
export default Ember.Component.extend({
classNames: ['justified-grid'],
options: null,
items: null,
setup: Ember.on('didInsertElement', function() {
this.set('options', getOptions.call(this, [
'rowHeight',
'fixedHeight',
'margins'
]));
this.justifyGrid();
}),
justifyGrid: Ember.observer('items.#each', function() {
var _this = this;
imagesLoaded(this.$(), function() {
_this.$().justifiedGallery(_this.get('options'));
_this.set('gridInitialized', true);
});
})
});
The problem wasn't in the component. It was that my model is loading the photos using async (Ember Data). For this reason, in the router, after setting the model, I had to force Ember Data to load my photos:
afterModel: function(model) {
return Em.RSVP.all([model.get('photos')]);
}
I'm having a issue where transitioning is not occurring on a page reload/refresh. When I start the application and click on the links, everything works perfectly, but when I reload the route - I get an empty page (blank). This is happening for me on the MovieIndexRoute below.
// Router
MediaUi.Router.map(function () {
this.resource('movies', { path: '/'}, function() {
this.resource('movie', { path: 'movie/:id' }, function() {
this.route('edit', { path: '/edit' });
});
});
});
// Movies Route
MediaUi.MoviesRoute = Ember.Route.extend({
model: function() {
var media;
media = MediaUi.Media.find();
return media;
}
});
// Movie Route
MediaUi.MovieRoute = Ember.Route.extend({
serialize: function(model) {
return { id: model.get('_id') };
}
});
// Movie Index Route
MediaUi.MovieIndexRoute = Ember.Route.extend({
model: function(params) {
return this.modelFor('movie');
}
});
You can also access the repo here: https://github.com/alvincrespo/media-ui/tree/nested-resources on the nested-resources branch.
I've also added the following screenshot, showing the page and console.
Any help with this would be greatly appreciated. Thank You!
So for some reason navigate won't work in one of my views. I'm doing everything in one file for now, so that may be the problem. Also I know the code is horrible, I'm just messing around with backbone right now.
EDIT: I put a console.log() in MarketingPage's function route and it never gets called, so there must be something wrong with the view.
Also, this is the error I'm getting from chrome dev tools:
Error in event handler for 'undefined': IndexSizeError: DOM Exception 1 Error: Index or size was negative, or greater than the allowed value.
at P (chrome-extension://mgijmajocgfcbeboacabfgobmjgjcoja/content_js_min.js:16:142)
at null.<anonymous> (chrome-extension://mgijmajocgfcbeboacabfgobmjgjcoja/content_js_min.js:18:417)
at chrome-extension://mgijmajocgfcbeboacabfgobmjgjcoja/content_js_min.js:1:182
at miscellaneous_bindings:288:9
at chrome.Event.dispatchToListener (event_bindings:390:21)
at chrome.Event.dispatch_ (event_bindings:376:27)
at chrome.Event.dispatch (event_bindings:396:17)
at Object.chromeHidden.Port.dispatchOnMessage (miscellaneous_bindings:254:22)
Here's my code:
/*global public, $*/
window.public = {
Models: {},
Collections: {},
Views: {},
Routers: {
},
init: function () {
console.log('Hello from Backbone!');
}
};
var App = Backbone.Router.extend({
routes: {
'': 'index',
'register': 'route_register',
},
index: function(){
var marketing_page = new MarketingPage();
},
route_register: function(){
var register_view = new RegisterView();
}
});
window.app = new App();
var User = Backbone.Model.extend({
url: '/user',
defaults: {
email: '',
password: ''
}
});
var MarketingPage = Backbone.View.extend({
initialize: function(){
this.render();
},
render: function(){
var template = _.template($("#marketing-page").html());
$('.search-box').after(template);
},
events: {
'dblclick': 'route'
},
route: function(e){
e.preventDefault();
console.log("In route");
window.app.navigate('register', {trigger: true});
this.remove();
}
});
var RegisterView = Backbone.View.extend({
initialize: function() {
this.render();
},
render: function(){
var template = _.template($("#register-template").html());
$('.search-box').after(template);
}
});
$(document).ready(function () {
Backbone.history.start();
});
When I type host/#register into the browser directly, the register view gets rendered, but no matter what I do the click event won't seem to work...
Since the handler function route isn't being called, it's likely that the event delegation isn't working.
One thing to note is that the event handling that is set up in a Backbone View is scoped to only that view's el. I don't see where yours is set up explicitly, so it might be creating an empty div, then handling events inside that empty div (which you don't want).
One trick I use for quick prototypes is to set the view's el with a jQuery selector pointing to something that exists on the page already, then in the render, show it with a .show().
Since you're not really doing that, here's one thing you could try. What we're doing is setting the $el content and then calling delegateEvents to make sure that the events and handlers are being bound.
var MarketingPage = Backbone.View.extend({
initialize: function(){
this.render();
},
render: function(){
this.$el.html(_.template($("#marketing-page").html()));
$('.search-box').after(this.$el);
this.delegateEvents();
},
events: {
'dblclick': 'route'
},
route: function(e){
e.preventDefault();
console.log("In route");
window.app.navigate('register', {trigger: true});
this.remove();
}
});
Backbone.js views delegateEvents do not get bound (sometimes)
http://backbonejs.org/#View-delegateEvents
I've looked around for a while now and have not been able to find anything that suggests what the cause of this is.
My code:
var faqView = Backbone.View.extend({
tagName: 'div',
id: 'faq-list',
initialize: function() {
var view = this;
this.collection = new faqCollection();
this.collection.fetch({
success: function(collection, response) {
collection.each(function(faq){
view.$el.append(_.template($('script#faq_item').html(),{faq: faq.attributes}));
});
},
error: function(collection, response) {
view.$el.html("<p>Unable to get the FAQ items.<br>Please try again later.</p>");
}
});
},
render: function() {
this.$el.appendTo('div#container');
return this;
},
events: {
'click h3': 'toggleAnswer'
},
toggleAnswer: function(event) {
console.log(this);
console.log(event);
}
});
var router = Backbone.Router.extend({
routes: {
"faq": "faq",
"*other": "defaultRoute"
},
faqView: {},
initialize: function() {
this.faqView = new faqView();
},
defaultRoute: function() {
this.resetPage();
},
faq: function() {
this.resetPage();
$('body').addClass('page-faq');
this.faqView.render();
},
resetPage: function() {
$('body').removeClass('page-faq');
this.faqView.remove();
}
});
The above code is included as the last items in the <body>. The HTML is as follows.
<body>
<div id="container">
</div>
<script type="text/template" id="faq_item">
<h3 class="contracted"><span>{{faq.question}}</span></h3>
<p style="display: none;">{{faq.answer}}</p>
</script>
<script type="text/javascript" src="./js/models.js"></script>
<script type="text/javascript" src="./js/views.js"></script>
<script type="text/javascript" src="./js/collection.js"></script>
<script type="text/javascript" src="./js/router.js"></script>
<script type="text/javascript">
//<![CDATA[
$(function() {
var app = new router;
Backbone.history.start();
});
//]]>
</script>
</body>
All the required elements exist (as far as I can tell) and I'm not manually setting the el attribute of the View. I'm lost as to why the events are not binding/firing when the <h3> is clicked.
Edit No errors thrown and the functionality works if I don't use the router and create the view by it self. e.g.
var app = new faqView();
app.render();
Your problem is in your router. Right here in fact:
resetPage: function() {
$('body').removeClass('page-faq');
this.faqView.remove();
}
View#remove is just jQuery's remove on the view's el by default and that:
[...] method takes elements out of the DOM. [...] all bound events and jQuery data associated with the elements are removed
So once you this.faqView.remove(), the delegate handler that drives the view's events is gone.
The usual approach is to create and destroy views as needed instead of creating a view and caching it for later. Your router should look more like this:
var router = Backbone.Router.extend({
routes: {
"faq": "faq",
"*other": "defaultRoute"
},
defaultRoute: function() {
this.resetPage();
},
faq: function() {
this.resetPage();
$('body').addClass('page-faq');
this.view = new faqView();
this.view.render();
},
resetPage: function() {
$('body').removeClass('page-faq');
if(this.view)
this.view.remove();
}
});
Demo: http://jsfiddle.net/ambiguous/aDtDT/
You could try messing around with detach inside an overridden remove method in faqView as well but there's really no need to have an instance of faqView around all the time: create it when you need it and remove it when you don't.
I have many Views whos work with templates. The Rendering with the Views work perfectly, now into my Router i'm seeking to a way to trigger an Event when all Views rendered!
I used js loader like LAB.js but nothing work!
After all rendered i enter the event into the firebug console and it's work!
How and Here can i place my event so that it's trigger when all views rendered!
**My Event : **
$('div[id ^="solfg_"]').mobilyblocks();
**Router : **
(function () {
window.AppRouter = Backbone.Router.extend({
routes: {
"" : "init"
},
init: function(){
this.solfsmodel = new Solfs();
this.solfsmodel.fetch();
this.solfsView = new SolfsView({model: this.solfsmodel});
}
});
var app_router = new AppRouter;
Backbone.history.start();
}(jQuery));
Thank you
update : same problems
I found the solution just use $.when().then() from jquery, really amazing that i never saw this jquery function.
*My Solution : *
(function () {
window.AppRouter = Backbone.Router.extend({
routes: {
"" : "run"
},
initialize: function(){
this.solfsmodel = new Solfs();
this.solfsView = new SolfsView({model: this.solfsmodel});
},
run: function(){
$.when(
this.solfsmodel.fetch();
).then(function(){
*$('div[id ^="solfg_"]').mobilyblocks();*
});
}
});
var app_router = new AppRouter;
Backbone.history.start();
}(jQuery));
You can use the success callback of fetch method if you just need to wait that the collection is fetched (source: http://backbonejs.org/#Collection-fetch).
It's preferable to use Backbone.js method before use other librairies.
So your code should look like:
(function () {
window.AppRouter = Backbone.Router.extend({
routes: {
"" : "run"
},
initialize: function(){
this.solfsmodel = new Solfs();
this.solfsView = new SolfsView({model: this.solfsmodel});
},
run: function(){
this.solfsmodel.fetch({
success: function () {
$('div[id ^="solfg_"]').mobilyblocks();
}
);
}
});
var app_router = new AppRouter;
Backbone.history.start();
}(jQuery));