Oriented object javascript : initialize an attribute with a self function call - javascript

I have this class made in javascript :
function MyClass(id)
{
this.attribID = this.getID(id);
// ==========================================================================
this.getID = function(id) { return ("tooltip_" + id); }
// ==========================================================================
}
When I call it from my HTML with :
<script>
var a = new MyClass("onecell");
</script>
it generates this error : this.getID is not a function
How may I init my attribute with a generic function defined inside MyClass, function that can also be called from many other places than the init one ?

Just clarifying what was sugested by #RobG
There are two ways of doing it.
Change the order of assignments:
function MyClass(id)
{
this.getID = function(id) { return ("tooltip_" + id); }
this.attribID = this.getID(id);
}
Or using the class prototype:
function MyClass(id)
{
this.attribID = this.getID(id);
}
MyClass.prototype.getID = function(id) { return ("tooltip_" + id); };

Just move the this.getID function like so: JSFiddle
function MyClass(id)
{
// ==========================================================================
this.getID = function(id) { return ("tooltip_" + id); }
// ==========================================================================
this.attribID = this.getID(id);
}

Related

Javascript method is not a constructor

at the company where Im at we use jquery and a lot of the code is very spaghetti haphazard code. So in an effort to organize it better im researching implementing the pub sub model described in this article
So I made a really basic version of it like so:
var topics = {};
jQuery.Topic = function( id ) {
var callbacks, method,
topic = id && topics[ id ];
if ( !topic ) {
callbacks = jQuery.Callbacks();
topic = {
publish: callbacks.fire,
subscribe: callbacks.add,
unsubscribe: callbacks.remove
};
if ( id ) {
topics[ id ] = topic;
}
}
return topic;
};
$(function() {
var testService = new TestService();
testService.subscribe();
var testView = new TestView(testService);
testView.initEvents();
});
/* ---------------------VIEW----------------- */
var TestView = function(testService) {
this.testService = testService;
};
TestView.prototype.initEvents = function () {
this.publishers();
};
TestView.prototype.publishers = function() {
$("#search").on("click", function () {
var isValid = this.testService.validateForm("#container");
if(isValid){
$.Topic( "search" ).publish();
}
})
};
/* ---------------------SERVICE----------------- */
var TestService = function() {
this.testIdea = [];
};
TestService.prototype.validateForm = function (section) {
var referralValid = true;
$(section).find('input,select').filter('[required]:visible').each(function (i, requiredField) {
if(requiredField.value === '') {
//'breaks' the loop out
referralValid = false;
return referralValid;
}
});
return referralValid;
};
TestService.prototype.search = function() {
};
TestService.prototype.subscribe = function() {
var self = this;
$.Topic("search").subscribe( function() {
self.search()
});
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div>
<div id="container">
<input type="text">
</div>
<button id="search">Search</button>
</div>
However when I put that in jsfiddle I get the error that Uncaught TypeError: TestService is not a constructor
in the stackoverflow snippet and on my local version I get a different error of Uncaught TypeError: Cannot read property 'validateForm' of undefined. I cant see what Im doing wrong. Any pointers?
You can declare constructor functions in the way you are doing it (assigning constructor to variable):
var TestView = function(testService) {
this.testService = testService;
};
Like in this simple example:
var myClass = function(name) {
this.name = name;
}
myClass.prototype = {
hello: function() {
console.log('Hello ' + this.name);
}
}
var me = new myClass('Andrew');
me.hello();
But you must remember to declare them before they are used. If you use function statement(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function) as suggested by Chad Watkins it helps only because of hoisting(http://adripofjavascript.com/blog/drips/variable-and-function-hoisting.html) not because of function statement being mandatory for constructors.
The error in your code is in line:
$("#search").on("click", function () {
var isValid = this.testService.validateForm("#container");
you are referencing jQuery object inside a callback not TestView instance, you probably wanted something like this(pun not intended):
...
var self = this;
$("#search").on("click", function () {
var isValid = self.testService.validateForm("#container");
...

JavaScript functions is throwing Uncaught TypeError

I have a web page. In my web page I'm referencing some JavaScript I've written in a file called "spacer.js". spacer.js is more complicated, but the general setup is like this:
function spacer() {
// do stuff
console.log(spacer.options);
}
spacer.initialize = function(options) {
spacer.options = options;
};
Then, in my web page, I have:
<script type="text/javascript" src="./spacer.js"></script>
<script type="text/javascript">
spacer.initialize({ id:1 });
window.onresize = spacer();
</script>
When I load my web page, I get an error that says:
Uncaught TypeError: spacer.initialize is not a function.
I don't understand. What am I doing wrong.
function spacer() {
// do stuff
console.log(spacer.options);
}
spacer.initialize = function(options) { // needed an assignment operator and function keyword
spacer.options = options;
}
To create a method you need to use the function keyword.
To the browser, this
spacer.initialize(options) {
spacer.options = options;
}
is interpreted like this
spacer.initialize(options); // method evocation
{spacer.options = options;}; // anonymous object
Change the way it is defined
//from
spacer.initialize(options) {
spacer.options = options;
}
//to
spacer.initialize = function(options) {
spacer.options = options;
}
In your JS remove the () from window.resize call
spacer.initialize({ id:1 });
window.onresize = spacer;
As an aside it looks like you're trying to do one of two things and sitting uncomfortably in the middle. I'd personally go for 1) in this instance, but probably best to stick with one or the other.
1) Creating an object with methods
var spacer = {};
spacer.initialize = function (options) {
this.options = options;
}
spacer.getOptions = function () {
return this.options;
}
spacer.initialize({ name: 'spacer' });
spacer.getOptions(); // { name: spacer });
DEMO
2) Using a constructor function to build an space object instance:
function Spacer() {}
Spacer.prototype.initialize = function (options) {
this.options = options;
return this;
}
Spacer.prototype.getOptions = function () {
return this.options;
}
var spacer = new Spacer().initialize({ name: 'spacer' });
spacer.getOptions(); // { name: 'spacer' }
DEMO

How to return a object method in a jquery event

I am trying to return an object method on the event jQuery.change() of a text field,
here is the code:
var Utente = function(indice){
this.Indice = indice;
this.Dati = new Array();
this.initialize = function() {
this.Dati['stato_civile'] = this.getField('stato_civile').val();
this.onChange('stato_civile',this.checkObbligatorieta);
}
this.getField = function(name) {
return $('#'+indice+name);
}
this.onChange = function(field, func) {
this.getField(field).live('change',function() {
return func.apply();
});
}
this.checkObbligatorieta = function() {
this.Dati['stato_civile'] = this.getField('stato_civile').val();
[...]
}
this.initialize();
}
Using this I get the field "#stato_civile" returns the function this.checkObbligatorieta correctly but it gives me an error:
** this.getField('stato_civile').val() is not a function
I think it's something strictly related with the scope, but I can't figure it out.
That's because you're not invoking func() in the same context as the caller, so this is not bound to the same object.
You can fix the problem by passing this to apply():
this.onChange = function(field, func) {
this.getField(field).live("change", function() {
return func.apply(this);
});
};

Deep nesting functions in JavaScript

I cannot find an proper example for the love of my life on how to do this or even if this is possible. Based on my pieced together understanding from fragments of exmaples, I have come up with the following structure
var t = function()
{
this.nestedOne = function()
{
this.nest = function()
{
alert("here");
}
}
}
t.nestedOne.nest();
However this is not working (obviously). I would greatly appreciate if someone could point me in the right direction!
That is simply done with:
var t = {
nestedOne: {
nest: function() {
alert('here');
}
}
};
Your code otherwise doesn't make sense. this inside function doesn't refer to the function itself, it refers to the object context that the function is invoked in. And you are not even invoking the functions in your code.
If I say obj.func() then this inside func will be obj for that call. So assigning this.asd = true will assign true to that object's "asd" property.
If you wanted to do a nested class, it looks very different:
ClassA = (function() {
function ClassA() {
}
ClassA.prototype.method1 = function() {
};
function ClassB() {
}
ClassB.prototype.method1 = function() {
};
return ClassA;
}())
only ClassA can now make instances of ClassB. This should achieve same goals as nested classes in java.
See http://jsfiddle.net/CstUH/
function t(){
function f(){
this.nest = function()
{
alert("here");
}
}
this.nestedOne = new f();
}
var myt=new t();
myt.nestedOne.nest()
Edit 1:
You can also use
new t().nestedOne.nest()
instead of
var myt=new t();
myt.nestedOne.nest()
(http://jsfiddle.net/CstUH/1/)
Edit 2:
Or even more condensed:
function t(){
this.nestedOne = new function(){
this.nest = function(){
alert("here");
}
}
}
new t().nestedOne.nest()
http://jsfiddle.net/CstUH/2/
In JS functions are prime class objects, and you can access them directly in the code [i.e. without using reflection or so].
The code you put inside t body would be performed when actually executing t:
t();
You wrote t.nestedOne,nest(), but t has no nestedOne property - you should do like this:
var t = {
nestedOne : {
nest : function()
{
alert("here");
}
}
};
t.nestedOne.nest(); ​
I advice you to have a trip on John Resig's Learning Advanced JavaScript tutorial, it was very enlightening for me.
A simple callback handler I wrote today as an example of how I do deep nesting. I apologize if it's not the bees knees when it comes to code style, it made the concept a little clearer for me.
function test () {
this.that = this;
this.root = this;
this.jCallback = new Array(new Array()); // 2d
this.jCallbackCount = -1;
this.str = "hello";
// Callback handler...
this.command = {
that : this, // let's keep a reference to who's above us on the food chain
root : this.root, // takes us back to the main object
// add : function() { var that = this; console.log(that.that.str); },
add : function(targetFnc, newFunc) {
var that = this;
var home = that.that; // pretty much root but left in as an example of chain traversal.
var root = this.root; // useful for climbing back up the function chain
// console.log(that.that.str);
home.jCallbackCount++;
// target, addon, active
home.jCallback[home.jCallback.length] = { 'targetFunc' : targetFnc, 'newFunc' : newFunc, 'active' : true, 'id': home.jCallbackCount};
console.log('cbacklength: ' + home.jCallback.length);
console.log('added callback targetFunction:[' + targetFnc + ']');
return home.jCallbackCount; // if we want to delete this later...
},
run : function(targetFnc) {
var that = this;
var home = that.that;
console.log('running callback check for: ' + targetFnc + ' There is : ' + (home.jCallbackCount + 1) + 'in queue.');
console.log('length of callbacks is ' + home.jCallback.length);
for(i=0;i < home.jCallback.length - 1;i++)
{
console.log('checking array for a matching callback [' + targetFnc + ']...');
console.log('current item: ' + home.jCallback[i]['targetFunc'] );
if( home.jCallback[i]['targetFunc'] == targetFnc )
{
// matched!
home.jCallback[i]['newFunc']();
}
// console.log(that.that.jCallback[i].targetFunction);
}
}
};
}
test.prototype = {
say : function () {
var that = this;
console.log('inside');
// that.command('doSay');
that.command.run('doSay');
console.log(that.str);
}
} // end proto
// BEGIN TESTING **************************************************************************
// BEGIN TESTING **************************************************************************
// BEGIN TESTING **************************************************************************
var testing = new test();
testing.command.add('doSay', function () { console.log('213123123'); } );
testing.command.add('doSay', function () { console.log('12sad31'); } );
testing.command.add('doSay', function () { console.log('asdascccc'); } );
testing.say();
live:
http://jsfiddle.net/Ps5Uf/
note: to view console output, just open inspector in chrome and click on the "console" tab.

javascript function does not get called

I am writing javascript code with revealing prototype pattern for the first time. I am having problems. When I call add function when user clicks add button then it shows me this error in the console.
Uncaught TypeError: Cannot call method 'add' of undefined
How can I solve this problem?
here is my script.js code
$(function () {
var todo = Todo('contents');
$('.addBtn').on('click', function() {
var name = $(this).parent().find('input[type="text"]').val();
todo.add(name);
});
$('.contents').on('click', '.remove', function() {
var el = $(this).parent();
todo.remove(el);
});
$('.contents').on('click', '.update', function() {
var dom = $(this);
todo.addUpdateField(dom);
});
$('.contents').on('click', '.updateBtn', function() {
var el = $(this);
todo.update(el);
});
});
here is my todo.js code
var Todo = function(c) {
this.contents = $('.' + c);
};
Todo.prototype = function() {
var showel = function (d) {
this.contents.prepend(d);
},
add = function (name) {
if(name != "") {
var div = $('<div class="names"></div>')
.append('<span>' + name + '</span>')
.append("<button class='update' class='update'>Edit</button>")
.append("<button class='remove' name='remove'>Remove</button>");
}
return showel(div);
},
addUpdateField = function (dom) {
var name = dom.parent().find('span').text(),
field = $('<input type="text" value="' + name + '" />'),
update = $('<button class="updateBtn">Update</button>');
dom.parent().html('').append(field).append(update);
return;
},
update = function(el) {
var val = el.parent().find('input').val();
el.parent().html('<span>' + val + '</span>')
.append('<button class="update" class="update">Edit</button>')
.append('<button class="remove" class="remove">Remove</button>');
return;
},
remove = function (el) {
return el.remove();
};
return {
add : add,
update : update,
remove : remove,
addUpdateField : addUpdateField
};
}();
Update
After changing
var todo = Todo('contents');
to
var todo = new Todo('contents');
I get this error
Object [object Object] has no method 'add'
update 2
here is my on jsfiddle
You're not properly constructing your object, so it does not have any of the prototypes:
var todo = Todo('contents');
should be:
var todo = new Todo('contents');
Here is an SO question explaining what is happening when you forget the new.
Edit: the way you are defining your prototype functions is messing up the context (what this points to). Try a pattern like this instead:
Todo.prototype = {
method1: function () { ... },
method2: function () { ... }
};
fixed fiddle: http://jsfiddle.net/BagmY/3/
You're trying to assign Todo's prototype to a self-calling function. However, the prototype is just getting assigned to a function and not the expected return object.
Here's your working fiddle. I assigned the prototype directly to an object with your methods.
Also, JS parses from top to bottom. Therefore, define your new instance of Todo after you declare what Todo is.
This is what a self-calling function should look like:
Todo.prototype = (function() {
// ...
return {
add: add,
update: update,
remove: remove,
addUpdateField: addUpdateField
};
})();​

Categories