i was wondering how to use functions within the Backbone.View code. Can someone advise/show me how this is done properly. I understand that extending is only put into the var. I've looked at extend, prototype, super, parent, baseview and other fancy stuff. But that only confused me even more ;).
var jsHelpers = {
intVar: 300,
sum: function(a, b, callback) {
// do something interesting:
c = a + b;
d = c + intVar;
callback(c);
} //end sum function
} //end jsHelpers
/* somewhere else */
ViewThingy = Backbone.View.extend({
initialize: function() {
this.render();
},
render: function() {
var result = jsHelpers.sum(1, 1, function(callbackData) {
//let's do something with the return stuff:
this.$el.html(callbackData);
}); //end jsHelpers
} // end render
}); //end extend
The error is of course that the function jsHelpers.sum(); is not available in the extend.
TIA ! Vince
var View = Backbone.View.extend({
hello: function() {
console.log('hello');
},
// You can also override Backbone methods here.
initialize: function() {
// Do init code shared by all your views
}
});
// All the views in your app should extend off this view instead of Backbone.View.
var RandomView = View.extend({
initialize: function() {
// Call the parent to do init code.
View.prototype.initialize.apply(this, arguments);
this.hello();
},
// You can override methods too..
hello: function() {
// You can call the parent.
View.prototype.hello.apply(this, arguments);
}
});
Actually it is a good idea to always extend View, Model, Collection and Router when you make an app as there will always be shared functionality you want to do to not repeat the same code everywhere in your app. Typically for a view this would be stuff like the render routine such as rendering the template and rendering sub views - you wouldn't want to do that logic again in every view in your app.
Typically to share other code you would use a dependency manager like RequireJS or Browserify. But you can also have a single global object:
window.app = {};
and attach things to it:
window.app.utils = ....;
That is accessible from anywhere. Having an app object is pretty common - e.g. you would often have a Model that maintained the state of the app at app.state.
You can hook your helpers to some global namespace or make them global.
window.jsHelpers = {...}
Second way :
jsHelpers = {..} //Remove the var, it'll make jsHelpers a global variable.
I use the first one, for similar purposes.
Related
Spring has very useful option, that whey I define a bean, I define a scope. If it's singleton, only one instance is created. By prototype, each time a bean is required, a new instance is created.
RequireJS provides by default singletons, so with such simple module:
Singleton.js
define([], function() {
console.log('Instance initialization')
var items = []
var singleton = {
getItems: function() {
return items
},
setItems: function(newItems) {
items = newItems
},
addItem: function(item) {
items.push(item)
}
};
return singleton;
})
and the usage:
require(["showcase/modules/Singleton"], function(Singleton){
Singleton.addItem('item1')
console.log(Singleton.getItems())
})
require(["showcase/modules/Singleton"], function(Singleton){
Singleton.addItem('item2')
console.log(Singleton.getItems())
})
the output will be:
Instance initialization
["item1"]
["item1", "item2"]
Is it possible to define and use the module in such way, that I could switch in the module definition, if I want to use prototype or singleton scope? So in my case, without changing the usage, I'd get:
Instance initialization
["item1"]
Instance initialization
["item2"]
I'm using RequireJS from Dojo, just in case of syntax differences
Well, first of all the problem is that when you import a module using an AMD loader, you will actually get an instance, but the second time you import the same module, the same instance is actually returned (problem 1).
To overcome this problem you should use the factory design pattern to get your instance and also translate your singleton object to a class that can be instantiated (problem 2). Your factory could have a method called getInstance() that accepts a boolean parameter that can toggle between singleton/prototype.
So without changing your usage you won't be able to do this because of the problems I just addressed. The best solution I can come up with (with a factory) is:
Singleton.js
define([], function() {
console.log('Instance initialization');
// Singleton class
var Singleton = function() {
this.items = [];
this.getItems = function() {
return this.items;
};
this.setItems = function(newItems) {
this.items = newItems;
};
this.addItem = function(item) {
this.items.push(item);
}
};
// Factory
var factory = {
singletonInstance: new Singleton(),
getInstance: function(/** Boolean */ isSingleton) {
if (isSingleton === true) {
return this.singletonInstance;
} else {
return new Singleton();
}
}
};
return factory;
});
Usage (singleton)
require(["app/Singleton"], function(singletonFactory){
var Singleton = singletonFactory.getInstance(true);
Singleton.addItem('item1');
console.log(Singleton.getItems());
});
require(["app/Singleton"], function(singletonFactory){
var Singleton = singletonFactory.getInstance(true);
Singleton.addItem('item2');
console.log(Singleton.getItems());
});
Usage (multiple instances)
require(["app/Singleton"], function(singletonFactory){
var Singleton = singletonFactory.getInstance(false);
Singleton.addItem('item3');
console.log(Singleton.getItems());
});
require(["app/Singleton"], function(singletonFactory){
var Singleton = singletonFactory.getInstance(false);
Singleton.addItem('item4');
console.log(Singleton.getItems());
});
In case you're interested in a full example, it's on Plunker.
Eventually you could wrap the factory as a plugin so that you could actually do something like:
require([ "app/Object!singleton", "app/Object!prototype" ], function() {
});
However I don't know if RequireJS also supports this (and if I'm understanding well it should be a generic story for both AMD loaders).
I am trying create a hashmap in View function having instances of subviews , which I do in init method of View. But it is giving an error that init() of view doesnt exist. Am I doing anything wrong here? Thanks in advance.
http://jsfiddle.net/3fR4R/1/
view = function() {
var subview;
init = function() {
subview['search'] = new searchSubView();
}
}
check = function() {
console.log("clicked");
var view1= new view();
view1.init();
}
searchSubView = function() {
}
You've created a function and assigned it to an implicit global, which has nothing to do with the view function or instances created by it.
You can assign the function either by assigning to this.init within the constructor, or by putting it on view.prototype.
So either:
view = function() {
var subview;
// Note: You need code here to initialize `subview`
this.init = function() {
subview['search'] = new searchSubView();
};
};
or (note that I've made subview a property):
view = function() {
this.subview = /* ...initialize subview... */;
};
view.prototype.init = function() {
this.subview['search'] = new searchSubView();
};
Side notes:
You're falling prey to The Horror of Implicit Globals a lot in that code. You need to declare variables.
The overwhelming convention in JavaScript code is to use initial capitals for constructor functions, e.g., View rather than view.
You're also relying on automatic semicolon insertion, which I wouldn't recommend. Learn the rules and apply them, not least so you can minify/compress/compact your code safely.
all my Backbone.Views are only used once in their final state. (Except item views).
Currently I handle Backbone.Views as Singleton this way:
var Singletonizer = function(Singleton) {
if (Singleton._instance) return Singleton._instance;
Singleton._instance = new Singleton();
Singletonizer(Singleton);
};
Unfortunately it isn't that nice to add this little function as dependency to each amd module in my repository.
Is there another way to handle this? Maybe overwriting the base view class?
Just have your module return a function besides your view constructor, one that returns a single instance of it instead, not unlike the following. This way when you load the module you will not automatically get an instance whether you like it or not. Instead, after loading our "FailedXhrView" module, we then get our singleton by calling FailedXhrView()
'use strict';
define(['jquery',
'underscore',
'backbone',
'text!templates/failedXhr.html'],
function($, _, Backbone, failedXhrTemplate) {
var FailedXhrView = Backbone.View.extend({
el : $('#failedxhr-modal-container'),
template : _.template(failedXhrTemplate),
render : function() {
this.$el.html(this.template({}));
this.$el.find('failedxhr-modal-containee').modal();
return this;
}
});
var instance;
return function() {
if (!instance) {
instance = new FailedXhrView();
}
return instance;
}
});
From the very recommendable book Recipes with Backbone:
From here:
// definition
MyApplication.Views.List = Backbone.View.extend();
// instantiation
$(function() {
MyApplication.ListView = new MyApplication.Views.List({
el: $('#list')
});
})
To here:
$(function() {
MyApplication.ListView = new (Backbone.View.extend({
initialize: function() {
// ...
}
}))({el: $('#list')})
});
We assign an instantiation of an anonymous class to MyApplication.ListView. In this approach, we are doing the typical extension of a top-level Backbone class with custom attributes and methods. The difference, however, is that we do not assign the result to a class name as we did earlier. Instead, we immediately create a new instance of this anonymous class. Lastly, MyApplication.ListView is assigned to the resulting object.
I have to say I've never used techniques like this. It looks to messy for me, I prefer legibility than architecture.
I have a setup of multi level backbone inheritance, but would like to call back of the previous super class. Not sure if is possible.
Scenario:
BasicView -> MediumView -> HardView
Where I would love that when HardView created, it will loops to call previous super class initialize function.
Example is here:
http://jsfiddle.net/mochatony/bwB9W/
There are no implicit references to the superclass in standard JavaScript - you have to explicitly call the supertype's methods
var Basic = Backbone.View.extend({
initialize: function(){
console.log('base');
}
});
var Medium = Basic.extend({
initialize: function() {
console.log(Basic.prototype.initialize.apply(this, arguments));
console.log('medium');
}
});
var Hard = Medium.extend({
initialize:function(){
console.log(Medium.prototype.initialize.apply(this, arguments));
console.log('hard');
}
});
var hard = new Hard();
I have been writing a lot of javascript functions and event listeners and I want to move them into their own namespaced, isolated place that doesn't conflict when I concatenate and minify it with my other javascript files.
I am still new to javascript, so there may be simple solution to this answer. I started by creating a javascript object:
var MySpecialStuff = {
init: function(){
//do everything here
}
};
Then in my html, on the page I want to use it on I can initialize this code:
<script>
MySpecialStuff.init();
</script>
But then the init method started growing and I need to start breaking that code into smaller chunks, but I am stuck on the syntax and how to set private methods/variables and call them from within the init method and other private methods. How can I do this?
Am I headed in the right direction? What other ways can I / should I go about doing this sort of thing?
You are headed in the right direction. You can use the module pattern to create an object with private members and methods like this:
var foo = function(){
var bar = ""; //private
function funk(){
//private function
return "stuff";
}
return{
getBar: function(){
return bar;
},
init: function(){
alert(funk());
},
randomMember: 0 //public member
}
}();
Only what's in the return block is public, but you can call any private methods/access any private methods from within the return block.
Thanks to Joseph for linking to another SO question which explained this approach:
Another way to do it, which I consider to be a little bit less restrictive than the object literal form:
var MySpecialStuff = new function() {
var privateFunction = function() {
};
this.init = function() {
};
};
I like to further segment my code into a more modular approach. So, let's say we have a page that has a list of blog posts, a page menu, and a sidebar. I'd end up with this:
var blog_controller = {
init: function(){
document.getElementById('some_element').addEvent('click', this.handleSomeClick);
this.applySomePlugin();
},
applySomePlugin: function () {
/* do whatever needs to happen */
},
handleSomeClick: function () {
// scope will be element
this.style.color = 'red';
}
};
var page_menu_controller = {
init: function(){
document.getElementById('some_other_element').addEvent('click', this.handleSomeClick);
},
handleSomeClick: function () {
// scope will be element
this.style.color = 'blue';
}
};
... and so on. This keeps code organized by purpose, helps keep scope clear, and allows you to reuse elements of code that might occur frequently (for instance, if you AJAX'd in a new blog post, you could call this.applySomePlugin again).
This of course is a quick-and-dirty example, but I hope you get the idea
Divide responsibility of code you have put inside the init function into subobjects of the main object.
MySpecialStuff = {
// Variables/constants and everything else that needs to be accessed inside the whole MySpecialStuff object
init: function(){
//Do only whats required to be globally initiated.
this.MainMenu.init(); // Main menu stuff usually is.
}
};
MySpecialStuff.MainMenu = {
// Variables / constants that are only important to the MainMenu subobject.
init: function(){
//Just the initiation stuff thats related to the MainMenu subobject.
}
};
MySpecialStuff.SlideShow = {
// Variables / constants that are only important to the SlideShow subobject.
init: function(){
// Same as for the MainMenu with the difference that nonessential objects can be "fired" when required
}
};