using Backbone JS boilerplate & code navigation - javascript

a newbe question:
I've downloaded the backbone boilerplate from https://github.com/david0178418/BackboneJS-AMD-Boilerplate it uses require.js and I wonder about the code navigation during development.
Here is my question:
let's say I have 2 views one extend the other like so:
View 1:
define([
'underscoreLoader',
'backboneLoader',
'text!templates/main.html'
],
function (_, Backbone, MainTemplate) {
"use strict";
return Backbone.View.extend({
template:_.template(MainTemplate),
initialize:function () {
this.render();
},
log:function(msg){
console.log(msg);
},
render:function () {
this.$el.append(this.template({}));
return this;
}
});
}
);
View 2:
define([
'underscoreLoader',
'backboneLoader',
'text!templates/other.html',
'views/main-view'
],
function (_, Backbone, MainTemplate,MainView) {
"use strict";
// how would you navigate to MainView (main-view.js)
return MainView.extend({
template:_.template(MainTemplate),
initialize:function () {
this.render();
},
render:function () {
this.log("my message");
this.$el.append(this.template({}));
return this;
}
});
}
);
Now when I develop (I use IntelliJ) I would like to middle click MainView on the extended view and navigate to the code without having to browse the project tree.
Is that possible using this boilerplate? is there a better approach or a better boilerplate?

I would really like Netbeans's navigator to show me all the methods:
var New_Controller = Backbone.View.extend({
el : null, ...
}
But I can't seem to get it to work. Google came up with something for #lends, but I can't even get Backbone.js to get loaded to the code hint cache.
I ended up installing WebStorm (I saw the IDE in all the egghead.io tutorials) to get the navigator to list all methods and properties.
FYI, Aptana Studio and Zend Studio showed nothing like Netbeans. And Eclipse IDE for JavaScript Web Developers only partially (impractical in real life) works; it flattens the entire hierarchy.

I found this to work fine for me:
the Backbone Objects are wrapped with my custom objects, which allows me to navigate code, extend objects and keep multiple files easily.
Here is how:
Object 1
function ItemModel() {
ItemModel.model = (
Backbone.Model.extend({
initialize:function () {
},
defaults:{
name:"item name"
},
log:function(){
console.log("inherited method");
}
})
);
return new ItemModel.model();
}
Object 2
function ItemModel2() {
ItemModel2.model = (
ItemModel.model.extend({
initialize:function () {
},
defaults:{
name:"item name2"
}
})
);
return new ItemModel2.model();
}
and in my app:
var App = {
item:new ItemModel(),
item2:new ItemModel2()
};

Related

Browserify+Backbone.js "ApplicationState" shared module

I don't understand how to share some sort of "singleton" application-state holding object model, between different views, using browserify.
Books and tutorials often use a global namespace such as:
var app = app || {};
I have a simple example app which consists of:
app.js
var $ = require('jquery');
var Backbone = require('backbone');
Backbone.$ = $;
var MenuView = require('./views/MenuView');
var ContainerView = require('./views/ContainerView');
new MenuView();
new ContainerView();
MenuView.js
var Backbone = require('backbone');
var ApplicationState = require('../models/ApplicationState');
module.exports = Backbone.View.extend({
el: '#menuView',
events: {
'click .menuLink': 'changePage'
},
changePage: function(event) {
event.preventDefault();
var viewName = $(event.target).attr('data-view');
ApplicationState.set('currentView',viewName);
}
});
ContainerView.js
var Backbone = require('backbone');
var ApplicationState = require('../models/ApplicationState');
module.exports = Backbone.View.extend({
el: '#containerView',
initialize: function() {
this.listenTo( ApplicationState, 'change', this.render );
this.render();
},
render: function() {
this.$el.html( ApplicationState.get('currentView') );
},
close: function() {
this.stopListening();
}
});
This seems working using this approach:
ApplicationState.js
var Backbone = require('backbone');
var ApplicationState = Backbone.Model.extend({
defaults: {
currentView: 'TransactionListView'
}
});
module.exports = new ApplicationState();
Is the ApplicationState module really created only once (caching) ?
Or is there the risk of recreating / resetting the module?
What is the best practice for my use case? Thank you a lot.
Yes, there will only be one ApplicationState in the example you gave. Browserify executes anything following module.exports = as soon as the js file is run and then anything that requires that file is passed a reference to the result.
However it’s generally better practice to avoid sharing state this way between views and instead use a parent view that delegates to subviews. There are a number of ways to set this up. For ideas on best practices for organizing a backbone app, check out this talk: https://www.youtube.com/watch?v=Lm05e5sJaE8
For the example you gave I would highly consider using Backbone's Router.
In your example you have a nav that changes the "main" view. Backbone.Router intercepts navigation and checks it against your specified routes calling your view method. For instance:
router.js
module.exports = Backbone.Router.extend({
initialize: function(options){
this.ContainerView = new ContainerView();
},
routes: {
'transactions': 'showTransactionListView',
'transaction/:id': 'showTransactionDetailView'
},
showTransactionListView: function() {
this.ContainerView.render('TransactionListView');
},
showTransactionDetailView: function(id) {
this.ContainerView.render('TransactionDetailView', id);
}
});
Then any link to #transations (or just transactions if you're using Backbone History) will call your ContainerView.render('TransactionListView'). And, as a bonus, if you reload the page you'll still be looking at TransactionListView.
Other notes:
You'll want to make sure you discard old views when you replace them (by calling .remove() on them) so as to avoid memory leaks. Further Reading
You can add some flexibility to your router and use a controller pattern to render subviews with this nifty plugin

Adding new feature to discourse

I am trying to add an WatchList feature in the existing code discourse ember rails application
I have addded the following code
Discourse.Route.buildRoutes(function() {
var router = this;
this.resource('watchLists', { path: '/watch_lists' }, function() {
this.resource('watchList', {path: ':watch_list_id'});
});
});
In the ember Controller
Discourse.WatchListsController = Discourse.ObjectController.extend({});
In the ember model
Discourse.WatchList = Discourse.Model.extend({});
Discourse.WatchList.reopenClass({
find: function() {
jQuery.getJSON("watch_lists").then(function(json) {
var watch_lists = json.watch_lists.map(function(attrs) {
return Discourse.WatchList.create(attrs);
});
});
In the ember view js
Discourse.WatchListsView = Ember.View.extend({});
In ember route js
Discourse.WatchListsRoute = Discourse.Route.extend({
model: function() {
return Discourse.WatchList.find();
}
});
When i renderring the handlebars template I am getting an WatchListsController object withot the data we have got from the ajax.
Can any body point out where i am doing wrong.
I see two possible problems.
First, you probably want WatchListsController to extend Discourse.ArrayController, not Discourse.ObjectController.
Second your reopen block is not valid JavaScript in the example code that you posted. I count four { but only two }. You probably want something kind of like this:
Discourse.WatchList.reopenClass({
find: function() {
return jQuery.getJSON("watch_lists").then(function(json) {
return json.watch_lists.map(function(attrs) {
return Discourse.WatchList.create(attrs);
}
});
}
});

Marionette, layout within layout

I have a page that uses marionette layout to bind views to #content.
My landing page in my app is many views drawn together, so I planned to use another layout view instead of a composite view.
However currently with the code below I get:
TypeError: object is not a function
My controller.js calls views based on routes like this:
app.addRegions({
content: "#content"
});
define([], function() {
"use strict";
return {
landing: function() {
return require(["app/views/index"], function(View) {
return MyApp.content.show(new View()); ////LINE THROWING THE ERROR
});
}
};
});
The sub layout causing the issue
define([
"marionette",
'app/views/images/collection',
"tpl!app/templates/index.html"
],
function(Marionette, ImagesView, template) {
"use strict";
var AppLayout, layout;
AppLayout = void 0;
layout = void 0;
AppLayout = Backbone.Marionette.Layout.extend({
template: template(),
regions: {
collection1: "#images",
}
});
layout = new AppLayout();
layout.collection1.show(new ImagesView());
return layout;
})
Any help greatly appreciated
It looks like you're returning a new layout object from your index, and then trying to use it as a function in your controller.
In your index:
layout = new AppLayout();
...
return layout;
and then in your controller:
return MyApp.content.show(new View());
You probably just need to do
return MyApp.content.show(View);
UPDATE
After working on this some more, we found another issue. The ordering of rendering the views was wrong. The statement layout.collection1.show(new ImagesView()); won't actually render anything because layout itself hasn't been rendered yet. The solution to this was to move that statement into the onRender method of the AppLayout. This way, when MyApp.content.show(View) is called, it will automatically render the ImagesView at the correct time.

Cross referencing of 2 models

I have 2 models which are cross referencing each other. This could look like this:
MainModel:
define(
[ 'durandal/app', 'durandal/plugins/router', 'models/Shell', 'models/EditModel' ],
function (app, router, shell, editModel) {
//...
return {
//...
// This function should be accessible by the EditModel
update: function() {
//...
},
showEditView: function() {
// Initialise the EditModel with some data and show the according view afterwards
editModel.init('set some important stuff here...');
router.navigateTo('#/EditView');
}
//...
};
}
);
EditModel:
define(
[ 'durandal/app', 'durandal/plugins/router', 'models/Shell', 'models/MainModel' ],
function (app, router, shell, mainModel) {
//...
return {
//...
// This function should be accessible by the MainModel
init: function() {
//...
},
showMainView: function() {
// Update the the MainModel with some data and show the according view afterwards
mainModel.update('set new data here...');
router.navigateTo('#/MainView');
}
//...
};
}
);
Unfortunately this is not working. If I load my page on the MainView and call showEditView, the variable editView is known and everything works fine but then the variable mainModel in the EditModel is undefined and therefore the call mainModel.update(...) fails.
Same thing happens if I load my page on EditView but in the "opposite direction" (var mainModel in the EditModel is known, but editModel in the MainModel is undefined).
Is this a known issue and if so: How can i circumvent it?
I also posted this question in Durandals Google Group
Thanks
Check requierejs documentation for circular dependencies http://requirejs.org/docs/api.html#circular.
Circular dependencies are rare, and usually a sign that you might want
to rethink the design. However, sometimes they are needed, and in that
case, use require() as specified above.
For main.js add require as dependency and then explicitly require models/EditModel should do the trick. Either replicate that for the other modules or rethink the design ;-).
define(
[ 'require', 'durandal/app', 'durandal/plugins/router', 'models/Shell', 'models/EditModel' ],
function (require, app, router, shell, editModel) {
//...
return {
//...
// This function should be accessible by the EditModel
update: function() {
//...
},
showEditView: function() {
// Initialise the EditModel with some data and show the according view afterwards
require('models/EditModel').init('set some important stuff here...');
router.navigateTo('#/EditView');
}
//...
};
}
);

Keep getting undefined

I am working on javascript backbone project. I declared a global object like follow
window.App = { Vent: _.extend({}, Backbone.Events) }
I did above in initialize function like following
initialize: function () {
window.App = { Vent: _.extend({}, Backbone.Events), hello: 'yes' };
console.log(App); // This is ONE. see explanation below for ONE
console.log(App.Vent); // This is TWO. see explanation below
}
ONE
This log line shows following
function (){return parent.apply(this,arguments)} app.js:22
TWO
This log line show
undefined
Also if I do console.log(App.hello) it still says undefined
Please help me what am I doing wrong in this code?
Update
Here is all the related code to my problem. I am using requirejs and backbone
here is my main.js
require(['domReady', 'views/app', 'jqm'], function (domReady, AppView) {
domReady(function () {
window.App = { Vent: _.extend({}, Backbone.Events) };
new AppView();
});
});
here is views/app.js file
define(['backbone', 'views/home/homes', 'collections/homes'], function (Backbone, HomesView, HomesCollection ) {
var App = Backbone.View.extend({
el: 'div#page',
events: {
'swipeleft': 'nextView',
'swiperight': 'preView'
},
nextView: function (e) {
console.log(App.Vent);
//App.Vent.trigger('changeView', { direction: 'next' });
},
preView: function (e) {
console.log(App.Vent);
//App.Vent.trigger('changeView', { direction: 'prev' });
}
});
return App;
});
What I am doing in this file is when user swipes left or right then it calls nextView and preView functions. In these functions I want to trigger and Event which I listen to them in another view. But right now I want to console it. But it says undefined
Try to change:
var App = Backbone.View.extend({
to something else. Like this:
var iApp = Backbone.View.extend({

Categories

Resources