Referencing an object with through methods, events, and whatnot - javascript

Set-Up
I'm trying to make an object based validation code for my site where you can define an input as an object and attach properties to it kinda like this
function input(id,isRequired) {
this.id = id
this.isRequired = isRequired
this.getElement = getElem;
this.getValue = getValue;
this.writeSpan = writeSpan;
this.checkText = checkText;
this.isText = true
this.checkEmpty = checkEmpty;
this.isEmpty = true
this.isValid = false
}
I currently have an event handler set up like this
firstName.getElement().onblur = function() {validate(firstName)}
where firstName is the input object and the getElement() method executes the following:
function getElem() {
return document.getElementById(this.id)
}
The Issue
What I would like to do is be able to reference the firstName object with the validate function by using a something similar to .this and effectively remove the anonymous function. I want to do this mainly because I'm working with team members who aren't very familiar with javascript and the less code the better.
I'm guessing the code I'm looking for would look something like this:
firstName.getElement().onblur = validate
function validate() {
object = "your code here"
}
Is this possible?

Have a look at .bind():
firstName.getElement().onblur = validate.bind(firstName);
This will make this inside the validate function refer to firstName (so it is not passed as parameter).
It is not supported by all browsers (it is part of ECMAScript5) but the link shows a custom implementation.
Alternatively, you could create a new function which generates the anonymous function for you:
firstName.getElement().onblur = get_validator(firstName);
where get_validator is:
function get_validator(obj) {
return function() {
validate(obj);
}
}
Or you could do the same but as a method of the input object, so that one only has to do:
firstName.getElement().onblur = firstName.getValidator();

Related

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...

Javascript class member becomes empty in Firefox

I have a class in JS with field
Widget = function ()
{
this.Attributes = []; // key=value
}
and another class iherited from Widget
BusinessStatisticWidget = function ()
{
// some code
};
BusinessStatisticWidget.prototype = new Widget();
At initialization stage I have assigned this Attributes field with values (only once) and at some point Atttibutes field becomes empty:
BusinessStatisticWidget.prototype.SetEventsOnControls = function ()
{
var dropDown = document.getElementById(this.DropDownName + this.type + "Id");
var _this = this; // **Not empty here**
dropDown.addEventListener("change", function (event)
{
// **Not empty even here**
_this.CalculateAndSetTimeRangeForTimeSpan(event.target.value);
}, false);
}
BusinessStatisticWidget.prototype.CalculateAndSetTimeRangeForTimeSpan = function (val)
{
// **Empty here**
if (this.Attributes["fromDate"].value != '' && this.Attributes["toDate"].value != '')
{}
}
The code above works fine in Chrome and IE10 (I mean that array is not empty) but dont work in Firefox(20.0.1)
As array is empty I get TypeError: this.Attributes.fromDate is undefined.
And I dont know why it is empty and how to fix this.
There are multiple problems with your code:
Don't use arrays for arbitrary key, value pairs. Use only numerical keys for arrays.
Each instance will share the same Attributes array. This is usually not the desired behaviour.
Solutions:
Use an object instead.
Setup inheritance properly and call the parent constructor in the child constructor.
Code:
Widget = function () {
this.Attributes = {}; // use an pbject
};
var BusinessStatisticWidget = function () {
// call parent constructor
Widget.call(this);
// some code
};
// set up inheritance
BusinessStatisticWidget.prototype = Object.create(Widget.prototype);
More information (and polyfill) about Object.create.
Now, I don't know if that fixes your problem, but it makes your code at least more correct so that finding the issue becomes easier. I recommend to learn how to debug JavaScript.

Adding a property to a "Class" in JavaScript

There are no actual classes in javascript. But you have to work with what you get.
Lets take this example "Class":
var example = function (string) {
this._self = string;
}
With the above, you could do something like:
var ex = new example("Hello People."),
display = ex._self; // returns "Hello People."
I thought that by using something like example.prototype.newFun = function(){} would add a new property to that "Class". But it isn't working in my code.
Here is the full code i'm testing:
var example = function (string) {
this._self = string;//public, var like, storage
}
var showExample = new example("Hello People");
showExample.prototype.display = function (a) {//code stops here, with error "Uncaught TypeError: Cannot set property 'display' of undefined"
return a;
}
console.log(showExample._self);
console.log(showExample.display("Bye"));
What i'm trying to do is add the display function to the example function as a "public function". I might be doing something wrong.
It's not the object that has the prototype, it's the function that you use to create the object:
var example = function (string) {
this._self = string;
}
example.prototype.display = function (a) {
return a;
};
Because there's no prototype for showExample - it's only an instance of example. Try to do this: example.prototype.display = function (a) {} and it will work.
Here's a bit more on classes in JavaScript:
3 Ways to "define" classes
This lovely SO question
I like the way Classy handles this and also how classes are implemented in CoffeeScript.
You can modify to the constructor of showExample ..
ex.
showExample.constructor.prototype.display = function (a) {
return a;
}
You try to add a method to the prototype of the instance of example (showExample). The instance has no prototype. Try example.prototype.display = function() {/*...*/}; (in other words, add the method to the prototype of the constructor of showExample, that is example) and check again. After that, all instances of example 'know' the display method, or in your words, display is 'public' to all instances.
You can add the method to the instance using showExample.display = function() {/*...*/};. Using that, only showExample knows the the display method.
in your case showExample is an object of example...
use
example.prototype.display = function(a)...

Locate variable of my prototype

I have an object in Javascript:
function MyObject(aField) {
this.field = aField;
}
MyObject.prototype.aFunction = function() {
return this.field;
}
Then
var anInstance = new MyObject("blah");
var s = anInstance.aFunction();
this works fine, but if I pass the function to another function:
callLater(anInstance.aFunction);
I don't control callLater and it's minified, but it seems that it's calling aFunction using call() or apply(). Therefore, this points to another object and field is undefined.
What's the best practice to avoid this situation I'm facing?
That's because you lost the value of this Try this instead:
callLater(function() { anInstance.aFunction() });
Explaination, Think of it this way
function MyObject(aField) {
this.field = aField;
}
function MyObject2(aField) {
this.field = aField;
}
MyObject.prototype.aFunction = someFunct;
MyObject2.prototype.aFunction = someFunct;
Now what does someFunct belong to?
Well try doing MyObject.prototype.aFunction === MyObject2.prototype.aFunction it'll be true!
You see the problem Therefore it needs to be called from the class and not just referenced by value.

javascript is it possible to use a string to call a object function

I have a generic function which can speak to multiple other functions in appropriate objects is it possible to use a string to call the appropriate function.
var string = "save";
var generic = (new function (string) {
string."alert()";
return this;
})
var save = (new function (string) {
this.alert = (function () {
alert("your document has been saved")
return this
})
return this
})
var notSaved = (new function (string) {
this.alert = (function () {
alert("your document has not been saved")
return this
})
return this
})
I am using it for a far more complex set up but here is an example. Is this possible?
Sure you can. Try something like this:
window[string].alert();
Looking at your code it's hard to tell what you're actually trying to achieve. Nonetheless, here are a few ideas that may be relevant.
First, let's make a couple of objects:
var rabbit = {
name: 'Peter',
hop: function () {
return this.name + ' hopped!'
},
jump: function () {
return this.name + ' jumped!'
}
}
var hairy_maclary = {
name: 'Hairy Maclary',
jump: function () {
return this.name + ' jumped over the fence!'
}
}
Now, you could define a function which invokes the hop method on whichever object is passed to it:
function hop(object) {
return object.hop()
}
hop(rabbit) // 'Peter hopped!'
I'm not sure why you'd do this rather than invoking hop directly, but perhaps you want to do extra stuff before or afterwards.
If you wanted to you could create a completely generic function which would invoke a given method on a given object:
function invokeMethod(object, method) {
object[method]()
}
invokeMethod(hairy_maclary, 'jump') // 'Hairy Maclary jumped over the fence!'
This is a really strange thing to want to do, though. Perhaps you could provide more of an idea of what you're actually trying to do, since your example code is rather odd.
You can enclose your functions within some object so you can access by passing name of the property using some variable (in this case named string), eg. like that:
var string = 'notSaved';
var funcs = {};
funcs.save = new function(){
this.alert = function(){
alert('called save.alert()');
};
return this;
};
funcs.notSaved = new function(){
this.alert = function(){
alert('called notSaved.alert()');
};
return this;
};
funcs[string].alert();
See working example on jsfiddle.
If your variables are global (they should not), they are also automatically enclosed within window object, so you can call them also like that: window[string].alert(). This will not work for non-global functions (in this case my solution seems to be the only one not using eval()).
eval("alert('test');");
You can call functions with eval. Even you can declare functions.
eval("function test(){ alert("test");}");
test();

Categories

Resources