Pass function to javascript class - javascript

On my index.html, I have this code,
$(document).ready(function() {
var self = this;
var submit = function() {
alert("Test");
}
const form = new Form(self.submit);
})
In my Form.js, I have this code,
class Form() {
constructor(func) {
var self = this;
// ...
$("submitBtn").click(function(e) {
e.preventDefault();
self.func();
});
// ...
}
}
Why my function is not executing after the submitBtn is clicked?
I used self to get the "this" value. I cant use "new Form(self.submit())" because It will execute the function once the line is read.

Your submit function is a local variable, not a property of this. Thus you need:
const form = new Form(submit);
Similarly, in your constructor, func doesn't have anything to do with self; it should just be
func();

Pointy answers the question. I just want to add that constructor is a place where you usually declare and initialize instance properties, and it's better to register click event in a class method, something like:
class Form{
constructor(){}
click(func){
$("submitBtn").click((e)=>{
e.preventDefault();
func();
});
}
}
Also you dont need to cache the scope var self = this as long as you use arrow function. This answer could be useful Advantages of using prototype, vs defining methods straight in the constructor?

Related

Change private class methods

I am attempting to change the behavior of a jquery plugin without actually changing the source. For the purposes of this question, I constructed a simple example that illustrates my problem. If a have script file that attaches a class instance generator to a global variable like this:
(function(){
window.newMyClass = function(){
return new myclass();
}
function myclass(){
var privateMethod = function(){
return "private";
}
this.publicMethod = function(){
return privateMethod();
}
}
})()
If I then get new instance of myclass with var instance = window.newMyClass(), is there any way to override the behavior of privateMethod on instance, such that instance.publicMethod() would call my overridden function? I was thinking I could subclass myclass, but since the myclass constructor is scoped to the immediately invoked function expression, I don't know how to do that.
Is it better just to change the plugin source? The problem with that is I'd have to host it myself instead of using a CDN, as well as re-implement the change every time an update is released.
I don't know if I understood well this. Probably not, because there is no mistery with that:
(function(){
window.newMyClass = function(){
return new myclass()
}
function myclass(){
var privateMethod = function(){
return "private";
}
this.publicMethod = function(){
return privateMethod();
}
}
})();
var instance = window.newMyClass();
instance.publicMethod = function(){
return "new method";
}
console.log(instance.publicMethod());
FIDDLE: http://jsfiddle.net/r9evbzd2/1/

Javascript equivalent of PHP's :: (Scope Resolution Operator)

In PHP, you can do something like that:
class myClass() {
function doSomething(someVar) {
// do something here
}
// etc... (other methods and properties)
}
Then, of course, you could call that method after instanciating the class, like that:
$myObj = new myClass();
$myObj->doSomething();
But you would also have the option to call the method as a standalone function, without instantiating the class (but you'd have to pay attention to dependencies in that function), like that:
myClass::doSomething();
I believe it's something borrowed for C++...
It's known as a Scope Resolution Operator (Paamayim Nekudotayim in the PHP code...)
http://en.wikipedia.org/wiki/Scope_resolution_operator#PHP
http://www.php.net/manual/en/language.oop5.paamayim-nekudotayim.php
How would you do something like that in JavaScript? It doesn't seem to be possible.
Maybe I am approaching this the wrong way, I should disclose what I'm trying to achieve...
I simply have a function, which goes like this:
function submitContactForm(form) {
// pretty JavaScript...
}
And I'm happy with it being a function. But I'd like to implement a "resetContactForm()" but would like to have it attached somehow to the submitConatctForm function.
I know I could probably do this:
var contactForm = {
"submit" : function(form) {
//...
},
"reset" : function(form) {
//...
}
}
And I'd have answered my own question like that...
But, besides the fact that I don't like this syntax, and would like to avoid it, there is also the fact that the above structure cannot be used as a class definition, it is not the same than in PHP... so going back to the original question: is there a way to have a JavaScript structure that can be used as a class definition and a collection of stand-alone functions at once?
You are mis-understanding prototypal inheritance - you actually can use your second example as a "class" definition and the methods can be invoked either from the "class" or from the "instance":
// This is a normal JavaScript object
// not JSON as another commenter pointed out.
var ContactForm = {
submit: function(form) {
form = form || this.form;
// general contact form submission implementation
},
reset: function(form) {
form = form || this.form;
// general contact form reset implementation
},
setForm: function(form) {
this.form = form;
}
};
// Now we will create an instance of the contactForm "class"
// We are setting the prototype of `firstContactForm`
// to point at the `contactForm` object.
// If we wanted to we could create a function on the
// ContactForm object (e. g. `create`) that would invoke
// Object.create for us. (i. e. `ContactForm.create()`)
var firstContactForm = Object.create(ContactForm);
firstForm.setForm(document.getElementById("someForm"));
firstForm.reset();
// But, we can also use the function as a "static":
ContactForm.reset(document.getElementById("someForm"));
In answer to the other part of your question, if you want to make it something that is invokable "stand-alone" you can also allow the data to be passed in directly, as we are doing in the example with our form = form || this.form; checks in submit and reset.
Alternately, you can use call and apply (as #elclanrs points out in his answer) and always use this.form:
ContactForm.reset.call({form: document.getElementById("someForm")});
In JavaScript's object syntax you don't need quotes if there aren't any special characters:
var obj = {
key: function() {
...
},
...
}
Paamayim Nekudotayim has no place in JavaScript as there are no classes, no static methods. But JavaScript has a dynamic context, what we call this. It is not in any way similar to this in PHP or other classical inheritance languages, other than the name of the keyword.
A typical JavaScript "class" looks like:
// A "Class"
var Person = (function(){
// Private stuff, shared across instances
var instances = [];
// The constructor AKA "__construct"
function Person(name) {
this.name = name;
instances.push(this); // keep track of instances
}
// Static methods, attached to the constructor
// don't need an instance
Person.instances = function() {
return instances;
};
// Public methods
Person.prototype = {
say: function() {
return this.name +' says hello!';
}
};
return Person;
}());
Now, how you use this:
var mike = new Person('Mike');
mike.say(); //=> Mike says hello!
Person.instances().length; //=> 1
So good so far. As for "scope resolution" in JavaScript, you can pass the context explicitly; knowing that this is dynamic, you can borrow the Person's say method and invoke it in any other context, for example:
Person.prototype.say.call({name:'John'}); //=> John says hello!
You can make it a class like this:
function ContactForm(form) {
this.form = form;
}
ContactForm.prototype.submit = function() {
console.log('submiting: ' + this.form);// do something with the form
}
ContactForm.prototype.reset = function() {
console.log('reseting: ' + this.form);
}
var someForm = ...;
var form = new ContactForm(someForm);
form.submit();
form.reset();
Or if you want to use them statically you can do as following:
var ContactForm = (function() {
var reset = function(form) {
console.log('reseting' + form);
};
var submit = function(form) {
console.log('submiting' + form);
}
return {
submit: submit,
reset: reset
}
}()); // note that this is self-executing function
and use it like
ContactForm.submit(form);
ContactForm.reset(form);
Reading Sean Vieira and elclanrs' answers gave me better insight.
I've come up with this code as a proof of concept, and to make sure I understood what I was reading. This is essentially a simplified version of elclanrs' answer:
function contactForm(form) {
this.form = form;
}
contactForm.prototype.submit = function() {
alert("submit "+this.form);
}
contactForm.prototype.reset = function() {
alert("reset "+this.form);
}
// Without instanciating:
contactForm.prototype.submit.call({form:'form2'});
// With instance:
myForm = new contactForm('form1');
myForm.reset();
So it seams this "functionality" is already available in JavaScript, albeit in a different, less straightforward form.
Also, Sean Vieira's approach, completed:
var ContactForm = {
submit: function(form) {
form = form || this.form;
alert("submit "+form);
},
reset: function(form) {
form = form || this.form;
alert("reset "+form);
},
createForm: function(form) {
var myForm = Object.create(this);
myForm.setForm(form);
return(myForm);
},
setForm: function(form) {
this.form = form;
}
};
// instanciated
myContactForm = ContactForm.createForm('Me Form');
myContactForm.submit();
// no instance
ContactForm.submit("Some Form");
Also (my contribution), how about using wrapper functions, like that? Looks like a decent option to me.
function contactForm(form) {
this.form = form;
this.submit = function() {
submitContactForm(this.form)
}
this.reset = function() {
resetContactForm(this.form);
}
}
function submitContactForm(form) {
alert("submit "+form);
}
function resetContactForm(form) {
alert("reset "+form);
}
// Without instanciating:
submitContactForm('form2');
// With instance:
myForm = new contactForm('form1');
myForm.reset();
There is no perfect solution...

Basic javascript code layout

I have what I think is a fairly simply question but it's one that I can not find the answer to. I have a objects literal that I have created that groups functions, I want to know how I can create a variable that is inside the objects literal and editable/accessable by all the functions within that objects literal. At the moment the only way I know how to do this is create a global variable but I want to stop populating the global in this way. To better describe what I'm looking fiddle
http://jsfiddle.net/aT3J6/
Thanks, for any help.
var clickCount = 0;
/* I would like to place clickCount inside hideShowFn Object but all function inside need access to it, so global within hideShowFn */
hideShowFn = {
init:function(){
$('.clickMe').click(this.addToCount);
},
addToCount:function(){
clickCount++;
$('<p>'+ clickCount + '</p>').appendTo('body');
}
}
hideShowFn.init();
Create a function which is invoked immediately and returns the object, with the private variable inside the function, like this:
var obj = (function () {
var privateStuff = 'private';
return {
func1: function () {
//do stuff with private variable
},
func2: function () {
//do stuff with private variable
}
};
}());
http://jsfiddle.net/BE3WZ/
This is the way to have private variables in Functional Programming.
http://jsfiddle.net/mattblancarte/aT3J6/10/
Another option would be the pseudo-classical style:
function Constructor(){
var private = 'private';
this.public = 'public';
this.methods = {
//your methods here...
};
}
var obj = new Constructor();
Don't forget to use the 'new' keyword, or else you are going to be globally scoped.
Your code translated to this style would be:
function Test(){
var that = this,
clickCount = 0;
this.init = function(){
$('.clickMe').click(this.addToCount);
};
this.addToCount = function(){
clickCount++;
$('<p>'+ clickCount + '</p>').appendTo('body');
};
}
var test = new Test();
test.init();
You can make a closure as Cokegod says or you can simply add the variable to the object and access it using this
hideShowFn = {
clickCount: 0,
init:function(){
$('.clickMe').click(this.addToCount);
},
addToCount:function(){
this.clickCount++;
$('<p>'+ this.clickCount + '</p>').appendTo('body');
}
}
hideShowFn.init();
This dosn't work as Musa says the scope in addToCount will be the dom node clicked.
But see Cokegod's answer.

Javascript seting dom event to prototype method in constructor

I'm having some Javascript woes, lets say we have a constructor
function test(element) {
this.element = element;
this.element.onfocus = function() { this.onfocus(); }
}
test.prototype.onfocus = function() {
alert("focused");
}
new test(document.getElementByID("E1"));
So I am trying to dynamically set the focus event inside the constructor, but it doesn't seem to work, and I can't figure it out.
Anyone help?
Thanks,
AJ
In JavaScript, and in the context of this.element.onfocus = function() {this.onfocus(); }, second this is the element who fired the event.
In other words, your code should be like this if you want to work in a proper way:
function test(element) {
this.element = element;
var currentObject = this;
this.element.onfocus = function() {currentObject.onfocus(); }
}
Don't think JavaScript is a decent object-oriented programming language, as it's prototype-oriented and it has some weak things like one that's affecting your code.
Why don't you read this article? I belive it'll clarify this keyword for you:
http://www.switchonthecode.com/tutorials/javascript-tutorial-why-the-this-keyword-breaks
You must store a reference to 'this', because the onfocus function is in another context and the 'this' refers to something else:
function test(element) {
this.element = element;
var that = this;
this.element.onfocus = function() { that.onfocus(); }
}

issues with 'this' when using within jquery code block

I want to use values of the calling object within the jquery code block, but 'this' is mapped to the jquery object and not eh caller! How to solve this PLEASE?
// class
myClass = function (){
// member object
this._localVars = {
_elementClass:'.elem-class',
_dots:null,
_dotStatus:null
};
// member function
this.func1 = function() {
$(this._elementClass).each(function(_index, _element){
// this._localVars._dots[_index] = _element; ... this line throws an error 'this._localVars' is undefined ... as 'this' is html element here and not an object of the calling class
});
};
};
Please suggest how can I use the 'this' inside the jquery code block to refer the variables/objects of the class and not HTML/jQuery.
Thanks
Try saving this object into a local variable
var myObject = this;
$(this._elementClass).each(function(_index, _element){
myObject._localVars._dots[_index] = _element;
});
You can use the jQuery.proxy method to set the value of this that you want.
You pass your function as the first parameter, and the current this as the second.
myClass = function (){
this._localVars = {
_elementClass:'.elem-class',
_dots:[],
_dotStatus:null
};
this.func1 = function() {
$(this._localVars._elementClass).each( $.proxy(function(_index, _element) {
this._localVars._dots[_index] = _element;
}, this));
};
};
var cl = new myClass();
cl.func1();
console.log(cl._localVars._dots);

Categories

Resources