I use a Backbone View to start my application using the code below. All it really does is encapsulate other objects I want to instantiate or load.
Is this O.K. or should I re-factor?
// App
//
//
//
var BVApp = Backbone.View.extend({
Name: 'BVApp',
el: window,
initialize: function () {
this.initIndependentConstructors();
this.initBBViews();
this.initComposite();
this.initBVArc();
},
initIndependentConstructors: function (){
new ImageLoader();
new SiteMorpher();
new AccountUpdater();
new SignOut();
},
initBBViews: function () {
new BVAccountExist();
new BVAccountCreator();
new BVAccountButton();
new BVAccountCode();
new BVFaveCreator();
},
initComposite: function () {
var token = ClientStorage.getToken();
this.CV = new BVComposite();
this.CV.renderCommon();
if (token) this.CV.render(token);
},
initBVArc: function () {
this.BVArcInstance = new BVArc({el: window, collection: new BCArc([], {data: {model: "ArcReader"}})});
}
});
var App = new BVApp();
}());
Related
MyView.js:
define(['app/models/MyModel'],
function (MyModel) {
return Mn.LayoutView.extend({
template: '#my-template',
className: 'my-classname',
regions: {
content: '.content-region',
panel: '.panel-region'
}
initialize: function () {
_.bindAll(this, 'childButtonClicked');
},
onShow: function () {
this.getRegion('content').show(new AnotherView());
},
childEvents: {
'some-child-click': 'childButtonClicked'
},
childButtonClicked: function (view) {
var newView = new MyView({
model: new MyModel({
title: view.model.get('title')
})
});
this.getRegion('panel').show(newView);
}
});
});
I'm trying to nest instances of MyView within itself. This worked correctly when I was building the prototype by dumping everything into one function, like so:
var MyView = Mn.LayoutView.extend({
...
childButtonClicked: function(view) {
var newView = new MyView({
...
Now that I'm trying to separate the Views into their own files and use require.js, I can't figure out the syntax for a self-referential view.
When I run this code as is, I get an error like 'MyView is undefined'.
If I add it to the require header like so:
define(['app/models/MyModel', 'app/views/MyView'],
function (MyModel, MyView) {
I get the error 'MyView is not a function'.
EDIT for solution:
The marked solution works fine, I ended up using the obvious-in-hindslght:
define(['app/models/MyModel'],
function (MyModel) {
var MyView = Mn.LayoutView.extend({
template: '#my-template',
className: 'my-classname',
regions: {
content: '.content-region',
panel: '.panel-region'
}
initialize: function () {
_.bindAll(this, 'childButtonClicked');
},
onShow: function () {
this.getRegion('content').show(new AnotherView());
},
childEvents: {
'some-child-click': 'childButtonClicked'
},
childButtonClicked: function (view) {
var newView = new MyView({
model: new MyModel({
title: view.model.get('title')
})
});
this.getRegion('panel').show(newView);
}
});
return MyView;
});
You can require() in your module: var MyView = require(app/views/MyView);.
So for want of a better place:
childButtonClicked: function (view) {
var MyView = require(app/views/MyView);
var newView = new MyView({
model: new MyModel({
title: view.model.get('title')
})
});
this.getRegion('panel').show(newView);
}
Let's assume that we have testing code like this:
var App = (function () {
var api = {
Router: null,
init: function () {
this.content = $("#content");
Backbone.history.start();
return this;
}
};
var ViewsFactory = {
view1: function () {
var model1 = new model1();
return new api.Views.View1({
model: model1
});
},
view2: function () {
var model2 = new model2();
return new api.Views.View2({
model: model2
});
},
view3: function () {
var model3 = new model3();
return new api.Views.View3({
model: model3
});
},
};
var Router = Backbone.Router.extend({
routes: {
"": "view1",
"2": "view2",
"3": "view3",
},
view1: function () {
var view1 = ViewsFactory.view1();
$(".content").html(view1.render().el);
},
view2: function () {
var view2 = ViewsFactory.view2();
$(".content").html(view2.render().el);
},
view3: function () {
var view3 = ViewsFactory.view3();
$(".content").html(view3.render().el);
},
});
api.Router = new Router();
return api;
})();
And I want to use Require.js. Please don't focus on names, but on the idea.
If I understand it correctly, I have to include in require method every view (View1, View2, View3) and every model (Model1, Model2, Model3). But what is the purpose of using Require.js in such case instead of traditional <script> tags?
Using ViewsFactory is a good practice in backbone projects?
WHy not a view factory. In your case I'm not sure it's really useful though.
requirejs will help to build reusable modules. http://requirejs.org/docs/why.html
The best option in router is using variables like this:
var $ = require('jquery'),
Backbone = require('backbone');
I'm having an issue calling my views from with the router cfunctions besides within initialize.
this is my router code:
var ApplicationRouter = Backbone.Router.extend({
routes: {
"": "home",
//"*actions": "home",
"photo-gallery": "gallery",
"sound-lounge": "sound",
"contact": "contact"
},
initialize: function() {
this.homeView = new window.app.HomeView();
this.homeView.render();
/*
var soundView = new window.app.SoundView();
soundView.render();
var contactView = new window.app.ContactView();
contactView.render();
var galleryCollection = new window.app.GalleryCollection();
var gallery_items = galleryCollection.fetch();
gallery_items.done(function(){
var gallery_item = new GalleryView({ collection: galleryCollection });
});
*/
},
home: function() {
console.log('home');
},
sound: function() {
//var soundView = new window.app.SoundView();
//soundView.render();
console.log('sound');
},
contact: function() {
//var contactView = new window.app.ContactView();
// contactView.render();
console.log('contact');
},
gallery: function() {
console.log('gallery');
}
});
You can see able I have:
var soundView = new window.app.SoundView();
soundView.render();
commented out within the initalize function, this will work but as soon as I put it within the 'sound' function I get this error: Uncaught TypeError: undefined is not a function
It's to do with this part: new window.app.SoundView();
I have it called window.app.SoundView in my code, how do I go about getting this to work (it happens incorrectly for all my sections)
// ADDED soundView Code
// SOUNDVIEW
window.app.SoundView = Backbone.View.extend({
el: $("html"),
events: {
"click #sound-lounge": "render_sound"
},
initialize: function(){
this.render_sound();
},
render: function(model){
return this;
},
render_sound: function(){
this.model=new window.app.Home({id: 2});
var $main=this.$el.find('#content-area');
this.model.fetch().complete(function(data){
$main.html(data["responseJSON"].description);
});
}
});
Thanks
My problem ended up being as simple as removing window.app. from the soundView variable name.
e.g.
window.app.SoundView = Backbone.View.extend({ == SoundView = Backbone.View.extend({
AND
var soundView = new window.app.SoundView(); == var soundView = new SoundView();
I'm having trouble with a Backbone.js tutorial from Treehouse. Here's my code:
var NotesApp = (function () {
var App = {
stores: {}
}
App.stores.notes = new Store('notes');
// Note Model
var Note = Backbone.Model.extend({
//Local Storage
localStorage: App.stores.notes,
initialize: function () {
if (!this.get('title')) {
this.set({
title: "Note at " + Date()
})
};
if (!this.get('body')) {
this.set({
body: "No Body"
})
};
}
})
//Views
var NewFormView = Backbone.View.extend({
events: {
"submit form": "createNote"
},
createNote: function (e) {
var attrs = this.getAttributes(),
note = new Note();
note.set(attrs);
note.save();
},
getAttributes: function () {
return {
title: this.$('form [name=title]').val(),
body: this.$('form [name=body]').val()
}
}
});
window.Note = Note;
$(document).ready(function () {
App.views.new_form = new NewFormView({
el: $('#new')
});
})
return App
})();
And I get the error: Cannot set property 'new_form' of undefined
I've tried to go back and copy the code as close as possible, but I still couldn't get it to work. Any suggestions?
After stores: {} add ,
views: {}.
You need an object to attach your view to - JavaScript has no vivification
I am creating an app that will list the days of an event as buttons, then let you add dates and click each date to get a new "daily calendar".
This is my first real world app using backbone and underscore, so I keep running into road blocks. I would really appreciate anyone helping me out.
I am now at the point where my collection is full of dates, and I can add to those dates. Now what I am trying to figure out it routing the links to switch out the calendar, depending on the selected date.
Heres what I have relating to this part of the app so far:
Collections
var Days = Backbone.Collection.extend({
url: daysURL
});
var Calendar = Backbone.Collection.extend({
url: URL
});
Models
var Header = Backbone.Model.extend();
var header = new Header();
var ConferenceDay = Backbone.Model.extend();
var conferenceDay = new ConferenceDay();
View
var HeaderView = Backbone.View.extend({
el: $(".conf_days"),
template: _.template($('#days').html()),
events: {
'click a.day-link': 'changeDay',
'click #add_day' : 'addDay',
'click #previous_day' : 'prevDay',
'click #next_day' : 'nextDay',
'click #delete_day' : 'deleteDay'
},
initialize: function(){
_.bindAll(this, "render");
this.collection = new Days();
this.collection.fetch();
this.collection.bind("reset", this.render, this);
},
render: function(){
var JSONdata = this.collection.toJSON();
this.$el.html(this.template({days: JSONdata}));
console.log(JSON.stringify(JSONdata))
return this;
},
changeDay: function(e){
AppRouter.history.navigate($(this).attr('href'));
return false;
},
addDay: function() {
newDate = Date.parse($('.day-link:first-child').text()).add(1).day();
var newDay = new ConferenceDay();
newDay.set({date_formatted: newDate});
this.collection.add(newDay)
newDay.save({
success: function(){
alert('yes')
},
error: function(){
alert('no')
}
});
},
deleteDay: function(event){
var id = $('.day-link:last-child').data("id");
$('.day-link:last-child').remove();
},
prevDay: function() {
},
nextDay: function() {
},
loadTimes: function(){
var html = time.get('times');
$('.time_td').append(html);
}
});
var headerView = new HeaderView({ model: header });
ConferenceView = Backbone.View.extend({
el: $(".calendar"),
template: _.template($('#calendar').html()),
events: {
},
initialize: function(){
//this.listTracks();
this.collection = new Calendar();
this.collection.fetch();
this.collection.bind("reset", this.render, this);
},
render: function(){
var JSONdata = this.collection.toJSON();
this.$el.html(this.template({days: JSONdata}));
},
listTracks: function() {
}
});
var conferenceView = new ConferenceView({model:conferenceDay});
My current routing
var AppRouter = Backbone.Router.extend({
routes: {
'' : 'index',
'day/:id' : 'changeDay'
},
initialize: function() {
},
index: function() {
},
changeDay: function(id){
alert("changed");
this.calender.changeDay(id);
this.dayView = new ConferenceView({model:conferenceDay});
$('#calender').html(this.dayView.render().el).text('test');
},
});
var app = {
init: function() {
var routes = new AppRouter();
Backbone.history.start({pushState: true});
}
}
app.init();
Ideally, I would like the user to click the day-link button and have the url update via push state to the day/:id and then the #calender template would update with the correct model info received from the day update.
There's a lot of code in your post, so I'm not 100% sure the below will cover everything you need to do, but it's a start
This event handler might be causing some problems:
changeDay: function(e){
AppRouter.history.navigate($(this).attr('href'));
return false;
}
On a detail level, couple of things are off here:
You don't need to reference history. I'm not sure that the router even has such property. You should call AppRouter.navigate instead.
If you want the router to trigger your changeDay route method, you need to pass an option trigger:true, like so:
AppRouter.navigate($(this).attr('href'), {trigger:true}).
However, the actual solution is still simpler than that. You can remove the HeaderView.changeDay event handler, and the click a.day-link event binding from the events hash entirely. Backbone Router will detect the changed URL, and call the router method which matches the new URL automatically.