Javascript confusing Object function "has no method" error - javascript

So I have a function which looks like this:
function Students(){
// Function add:
// Returns: add page
this.add = function(){
// Get template
$.get('view/students/new.html', function(template){
// Templating
var html = Mustache.to_html(template);
// When document ready, write template to page
$('document').ready(function(){
$('#container').html(html);
});
});
};
};
When I try to call it's add function like so:
Students.add();
I get the error:
Uncaught TypeError: Object function Students(){...}has no method 'add'
What gives?

To use that implementation of Students, you should do this:
var students = new Students();
students.add();
However, that's probably not what you want. You probably meant to define Students like this:
var Students = {
add: function() {
$.get( /* ... */ );
}
};
Then you can call it like this:
Students.add();

Students is intended to be called as a constructor.
var s = new Students();
s.add()
Inside of Students, this will be a new object that inherits from Students's prorotype, and is returned automatically. So saying
this.add = function() ....
is adding the add function onto this object that's being returned. But the function will be created de novo each and every time you invoke this function. Why not add it to the prototype instead, so the function will exist only once, and not have to be needlessly re-created each and every time.
Students.prototype.add = function(){

You're not adding an "add" function to the "Students" function with that code; you're adding it to instances created by using "Students" as a constructor.
var student = new Students();
student.add(); // won't get the error

Well, Students doesn't have an add method.
I think you're assuming you know how this works. It isn't a reference to the function, unless you manually make it so. The value of this will depend entirely on how you call Students.

Related

javascript context changing using jQuery.fn.extend

I try to create a method that can be called from the created DOM element corresponding to my B class, like that:
$("#" + data.selectedId).eventCallback(data);
My eventCallback is defined in a mother class A, as you can see in the following code:
function A (){
this.addToPage = function () {
...
var context = this;
// This call is well overridden
context.onEvent("toto");
jQuery.fn.extend({
// This call uses A's method every time
eventCallback: function (data) {context.onEvent(data);}
});
};
this.onEvent = function (data) {
console.log("to override");
};
}
function B (){
this.onEvent = function (data) {
console.log("overridden");
};
}
B.prototype = Object.create(A.prototype);
The problem is, as commented, that I seem to not being able to use the same context when I enter the block jQuery.fn.extend. Is there a better (and cleaner) way to do it? Do I miss something?
Edit, to clarify:
The A class define the structure of widgets which are set in my html document (so to my mind an A instance is somehow linked to a part of the DOM).
As a user, I want to be able to select a widget that call a method (which definition is depending on B).
So My idea was to implement a callBack in the class and then make it callable from the DOM objects created with an A instance.

Javascript Prototype requires .prototype. Why?

I have some code as part of a javascript weekend project that I'm working on. My problem is in the last line. As far as I can tell, I should be able to just call Floater.create() and not have to call Floater.prototype.create(). Why do I need the extra .prototype? Without it, an error is thrown: Floater() has no method "create"
function Floater(){}
Floater.prototype.create = function(){
//do stuff
}
$(document).ready(function(){
//do stuff
runStartup();
});
function runStartup(){
loginFloater = new Floater;
Floater.prototype.create();
// as far as I know, this should run as just Floater.create(),
// but that throws an error.
}
This part:
Floater.prototype.create = function(){
//do stuff
}
does not add a property to the Floater constructor, but to the [[Prototype]] object of instances created with new Floater(). So, Floater instances will have that method, but the constructor won't.
You may be looking to change your start-up function to:
function runStartup(){
loginFloater = new Floater();
loginFloater.create();
}
But, given the name of your method, you also may want to remove create altogether, and do initialization stuff directly from the constructor:
function Floater(){
// init stuff here
}

How do I make a generic factory in javascript?

A factory class isn't the end product I am looking for but it is basically my problem boiled down. I am looking for a class we'll call foo that can be passed in another class bar as a parameter to its constructor such that when later calling fooInstance.create() it returns a new instance of bar. I can easily figure out how to make a fooInstance.create(bar) create an instance of bar. But that isn't what I need. I need each instance of the factory class to create a specific type of object. so:
fooCar = new foo(Car);
fooTruck = new foo(Truck);
myCar = fooCar.create();
myTruck = fooTruck.create();
This would be something easily handled by Generics in c#. I either get errors or I end up screwing with the prototype of foo which then changes the type created by all instances of foo.
Just return a regular object from your factory, with just one create method:
function foo (Constructor) {
return {
create: function () {
return new Constructor();
}
};
}
Check out the fiddle: http://jsfiddle.net/fR5Gz/1/
Thanks to everyone for your help. #missingno I thought the details of what I was trying to do would cloud the issue but now I think it was the other way around. I'll know better for next time. I wasn't looking for type safety but without it maybe there is no reason to do it this way. Maybe I'm stuck in classical thinking.
I actually figured it out myself this morning because I didn't get any email alerts on this thread like I was supposed to so I thought there weren't any replies yet. This is my solution (relevant code only):
ORM.Repository = (function (){
function Repository(ob){
this.construct = ob;
};
//bunch of other generic repository stuff deleted
Repository.prototype.make = function () { return new this.construct();}
return Repository;
})();
Usage:
var carRepository = new ORM.Repository(car);
var personRepository = new ORM.Repository(person);
var myCar = carRepository.make();
var user = personRepository.make();

jQuery Pattern - is this valid or is there a better way?

I've sort if fell into this organization of javascript and was wondering if I'm missing the point somewhere here, or if there's a more elegant way of doing this.
Basically I'm wrapping everything in a function (object) and then setting up methods on that object, then instantiating an instance of the wrapper object and passing in any options and dependencies.
I have a hunch there's a way to automatically run .init() and a few other tweaks that could be made. Am I doing it right?
function AppModuleCore(){
var AppModuleCore = this; //keep internals sane
// Various global vars, objects
AppModuleCore.defaultOptions = {};
AppModuleCore.init = function(opts) {
// todo: that thing where you extend an options object a la juery
AppModuleCore.bindEvents();
};
AppModuleCore.bindEvents = function() {
// bind events here, send to functions within AppModuleCore.<FUNCTIONNAME>();
// Example:
$("a#clicker").unbind("click");
$("a#clicker").click(function(event){
AppModuleCore.handleClickerClick(event);
});
};
AppModuleCore.handleClickerClick = function(event){
alert("clicker was clicked");
};
}
// --------------------------------------------------------------------
// instantiate AppModuleCore object and initialize with opts,
// dependency injection
// --------------------------------------------------------------------
$(document).ready(function(){
AppModuleCore = new AppModuleCore;
var options = {};
AppModuleCore.init(options);
});
OK, some points
Having your code wrapped in a constructor only really makes sense if
You're going to instantiate more than one
You have "public" methods on the object that you are going to call
Your code doesn't exhibit these characteristics. I say this because your jQuery selectors a#clicker are hard coded so I'm assuming that you wouldn't want to bind the same events to them more than once?
You'd be better off using a function (perhaps your init) or an object literal to limit your scope..
function init( options ) {
var defaultsOptions = {};
var privateVar = 'only in this scope';
//extend your default options with options here
//using jquery
options = $.extend( defaultOptions, options );
// this function is completely private to this scope
function privatefunction() {
//do stuff
}
function handleClickerClick( event ){
alert("clicker was clicked");
}
// you don't need to wrap your handler in an anonymous function unless
// you're doing some work to the event before forwarding:- just give a
// reference to your handler
// the handler has access to other members of this scope, we're in a closure
$(options.selector).click( handleClickerClick );
//etc
}
init( {selector: 'a#clicker'} );
On a stylistic note: when you alias this with the same name as the constructor and then add methods to the alias, it looks at first glance like you are adding static methods to the constructor. This may be confusing to someone who looks at your code later and doesn't notice the alias.
function C() {
// a static method i.e a property of the constructor, C not objects created with it
// it is a bit wierd that it is defined in the constructor but not unheard of
C.staticMethod = function(){};
//quite plainly a method of objects of this type, easy to understand
this.method = function(){};
}

Javascript Prototype not Working

Hi I don't know whether this is my mistake in understanding Javascript prototype object ..
Well to be clear I'm new to the Javascript singleton concept and lack clear cut knowledge in that but going through some referral sites I made a sample code for my system but it's giving out some errors which I couldn't find why so I'm asking for your help. My code is:
referrelSystem = function(){
//Some code here
}();
Prototype function:
referrelSystem.prototype.postToFb = function(){
//Some Code here
};
I get an error saying prototype is undefined!
Excuse me i thought of this right now
EDIT
I have used like this:
referrelSystem = function(){
return{
login:getSignedIn,
initTwitter:initTw
}
};
Is this causing an issue?
A typical way to define a JavaScript class with prototypes would be:
function ReferrelSystem() {
// this is your constructor
// use this.foo = bar to assign properties
}
ReferrelSystem.prototype.postToFb = function () {
// this is a class method
};
You might have been confused with the self-executing function syntax (closures). That is used when you would like to have "private" members in your class. Anything you declare in this closure will only be visible within the closure itself:
var ReferrelSystem = (function () {
function doSomething() {
// this is a "private" function
// make sure you call it with doSomething.call(this)
// to be able to access class members
}
var cnt; // this is a "private" property
function RS() {
// this is your constructor
}
RS.prototype.postToFb = function () {
// this is a class method
};
return RS;
})();
I would recommend that you study common module patterns if you're looking into creating a library.
Update: Seeing your updated code, the return from referrelSystem won't work as expected, since return values are discarded when calling new referrelSystem().
Rather than returning an object, set those properties to this (the instance of referrelSystem that gets constructed):
var referrelSystem = function () {
// I assume you have other code here
this.login = getSignedIn;
this.initTwitter = initTw;
};
I don't think you intend to immediately execute the functions, change them to this:
var referrelSystem = function(){
//Some code here
};
(+var, -())
Same with the prototype function:
referrelSystem.prototype.postToFb = function(){
//Some Code here
};
(Here you don't need the var, because you're assigning to something that already exists.)
A function should return to work as
prototype
property.
Take a look at this example here

Categories