I have several objects and all of them have some methods that are called the same but do different things.
When I click a button, I want to call the init() method, but the
object is different based on what button I clicked.
Here is a snippet
$btn.on('click', function(e){
e.preventDefault();
var $trigger = $(this);
var objectName = $trigger.data('object');
/*
if objectName is 'user', I want to call user.init(),
if it's 'product' I want to call product.init() and so on...
right now i get an error if I call like his
*/
objectName.init($trigger);
});
Is it possible to dynamically call an object like this ? I know it is for its properties and methods, but I din't find anything about this issue.
Thank you.
It's better to do mapping
var entities = {
user: user,
entity: entity
}
var objectName = $trigger.data('object');
entities[objectName].init($trigger);
In case your objects (or functions) defined in the global scope, you can access them using the window object:
var funcT = function() {
console.log('funcT was called');
}
var objT = {
'a': 1,
'b': 2
}
function a() {
var funcName = 'funcT'
window[funcName]();
var objName = 'objT'
console.log(window[objName]);
}
a()
With window[variable] you can access variables based on another variable.
So all that you need to do is to replace objectName.init($trigger); with: window[objectName].init();
Related
I am trying to make a parent data access layer class that is inherited by multiple classes.
parent class:
var DataAccess = function() {
this.Save = function(){
alert(this.ListName); //works
SaveLogic(this.Id); //doesnt work
}
}
Child Class:
var Job = function(){
Job.prototype.ListName = 'MyList'; //works
this.Save = function(){
Job.prototype.Save().call(this);
//specific Job Save logic
}
}
Job.prototype = new DataAccess();
Now in my main class:
var aJob = new Job();
aJob.Id = 1;
aJob.Save(); //Does not work. Prototype can not see aJob.Id..
As you can see, I need to create a parent function with shared variables such as ID, so when I inherit the parent class, I can assign values to these variables so the shared logic of hte parents class work, then my extended class's can have specific logic
You can start with construction like this:
var DataAccess = function() {
this.Save = function(){
console.log('DataAccess Save call', this.ListName, this.Id);
}
}
var Job = function(){
this.ListName = 'MyList';
}
Job.prototype = new DataAccess();
/**
* Delete me to use parent's Save method.
*/
Job.prototype.Save = function(){
console.log('Job Save call', this.ListName, this.Id);
}
var aJob = new Job();
aJob.Id = 1;
aJob.Save();
#stivlo described how it works in his answer here: https://stackoverflow.com/a/4778408/1127848
The problem I had was I wanted to reuse the same code. I think I have worked it out this way, im still not 100% its the right way to go with prototype programming :
function DataAccess() {
//setup common variables
}
DataAccess._Save_(listname, id){
commonSaveLogic(id);
doStuff(listname);
}
function Job() {
this.ListName = 'Jobs';
DataAccess.call(this); //call DataAccess Constructor
}
Job.prototype = DataAccess;
Job.prototype.constructor = Job;
Job.ProtoType.Save = function(){
this._Save_(this.ListName, this.Id);
}
function AotherList() {
this.ListName = 'AnotherList';
DataAccess.call(this);
}
//same as above. Job and Another list both inherit off DataAccess.
Dont use .prototype inside the constructor. We define .prototype for sharing same copy to all objects.
You are missing here many things. I'm explaining one by one:
First : SaveLogic(this.Id); //doesnt work
Because You don't use this with the function so it's a global function not a constructor function. And you don't have defined it any where so there will be an error like function SaveLogic not defined
To prevent this error, define the function somewhere.
Second : You have passed this.Id as a parameter. Id using the line aJob.Id = 1; will not be accessible within the SaveLogic(this.Id); because Id is a property of aJob not of ajob.prototype. this.ListName will be available here because it's a property of prototype.
So it you want to get Id inside SaveLogic() function, define it as prototype property.
Third : when this line aJob.Save(); will be invoke it will call
this.Save = function(){
Job.prototype.Save().call(this);
//specific Job Save logic
}
Job.prototype.Save() will search for a function named as Save(). Which is not defined in Job's prototype so function not defined error will occur.
Fourth : call() can not be called anyhow excepts either DataAccess.call() or Job.call();
call() is just like the constructor call excepts it's first parameter get assigned to the constructor's this object.
Here i have improved your code. Just copy and paste it in your editor and see what is going here.
Try this :
function SaveLogic(Id)
{
alert(Id);
}
var DataAccess = function() {
this.Save = function(){
alert(this.ListName); //works
SaveLogic(this.Id);
return this; //doesnt work
}
this.call = function() {
alert('call is called here');
}
}
var Job = function(){
Job.prototype.ListName = 'MyList'; //works
this.Save = function(){
//console.log(Job.prototype.Save());
Job.prototype.Save().call(this);
//specific Job Save logic
}
}
Job.prototype = new DataAccess();
var aJob = new Job();
Job.prototype.Id = 1;
aJob.Save(); //Does not work. Prototype can not see aJob.Id..
For better code structure, I want to use a javascript object holding all properties instead of using multiple vars:
// 1. WAY
// This returns an error, as _inp cannot be accessed by input_value
// Uncaught TypeError: Cannot read property 'value' of undefined
var ref = {
_inp: input.target,
input_value: _inp.value,
....
};
// 2. WAY
// When using this, it works
var ref = {
_inp: input.target,
input_value: input.target.value,
....
};
// 3. WAY
// This obviously works, too.
var
_inp = input.target,
input_value = _inp.value,
My Question is, why does 3. Way works and 1.Way doesnt?
In example 1, _inp will be a property of an object. It isn't a variable. You can only access it from a reference to the object (and it won't be a property of the object until the object exists, which will be after the object literal has been evaluated, see also Self-references in object literal declarations).
Because _inp will only be filled in with the input.target value after passing through the entire var ref = { ... }; statement. This means that when you try to use it, it doesn't exist yet.
The 1st way don't work because you refers to "_inp" which is not an existing var. and the ref object is not fully created (that's why input_value: this._inp.value won't work either)
To create objects and assigning values to its properties, you can use a function (I keep most of your code):
var ref = {
_inp: input.target,
input_value: null,
init: function()
{
this.input_value = this._inp.value;
}
};
ref.init();
console.log(ref.input_value); // will contains the same as input.target.value
but usually, people create objects with all property with default values, and pass an argument to their init function:
var ref = {
_inp: null,
input_value: null,
init: function(input)
{
if (input)
{
this._inp = input.target;
this.input_value = input.target.value;
}
}
};
var input = {target:{value:"foo"}};
ref.init(input);
I am new to pseudo classes and prototypes in JavaScript and I am having a bit of difficulty implementing it properly. What I am trying to do is have a base 'class' with some fields then create a prototype of that base class with my methods defined as object literals. I am torn between doing it this way and just using singletons inside my base class for my methods. I think though that doing it this way is a little more elegant and I think I am actually not creating every method every time I create a new object.
Anyways, the small issue I am having is referencing the fields of my base class in my methods. Because when I try to reference them as this.field this is referring to the current function/ scope but I want it to reference the newly create object. Is there a work around for this or should I change the way I am creating my methods.
Below is some code that I think will make it more clear what I am doing and the problem I am having.
function BaseClass() {
this.items[];
this.fieldOne = "asdasd";
}
BaseClass.prototype = {
methodOne: function (input) {
function addElement(a. b) {
var element = {};
element.prop1 = a;
element.prop2 = b;
//The issue I am having is that items is undefined, how can I refernce the parent class object.
this.items.push(element);
}
function traverse() {
//go through a list and add a bunch of elements
addElement("ASdasd", 324);
}
},
methodTwo: function () {
//see now fieldOne is asdasd
console.log("fieldOne" + fieldOne);
}
}
var forTest = new BaseClass();
forTest.methodTwo();
So yeah I want to have some fields in the parent class that I can access from any method, but I would rather not just put the functions in my base class so that I do not create every method everytime I create a new object from BaseClass. Is there a work around or a better way to implement this?
Thanks in advance for the help.
You're losing the reference to this inside your nested functions. You can solve that with:
methodOne: function (input) {
var self = this;
function addElement(a. b) {
var element = {};
element.prop1 = a;
element.prop2 = b;
//The issue I am having is that items is undefined, how can I refernce the parent class object.
self.items.push(element);
}
function traverse() {
//go through a list and add a bunch of elements
addElement("ASdasd", 324);
}
// You never called anything?
// is traverse() what you wanted?
traverse();
},
methodOne: function (input) {
function addElement(a. b) {
var element = {};
element.prop1 = a;
element.prop2 = b;
//The issue I am having is that items is undefined, how can I refernce the parent class object.
this.items.push(element);
}
The issue here is that you've encountered javascript design error which is that this in subfunction is bound to wrong object. The ususal workaround for this looks like:
methodOne: function (input) {
var that = this;
function addElement(a, b) {
...
that.items.push(element);
}
}
In fact it's bound to the global object:
var o = {
f : function(){
var g = function(){
this.name = "test";
};
g();
}
};
o.f();
console.log(name); // "test"
I am developing a JQuery plugin that stores private data in the object's data field (as was recommended in an article I found):
$.fn.awesomify = function (schema, data) {
$(this).data('schema', schema);
}
I can then retrieve this value in a private method:
function rebuild() {
var schema = $(this).data('schema');
}
Now the problem I have is that the value of $(this) is different when the method gets called from a different object. For example, the onclick event of an href:
var a = ...;
a.click(function () {
rebuild(); // Now $(this) is the a-object
});
How should I solve this?
Thanks!
This is because the value of this is determined at invocation time, and is set to the object which the method belongs to, or window if the method is not attached to an object*; rebuild() is not attached to an object, so this is window.
You can either pass the value of this in as an argument, or use the Function.prototype.call/Function.prototype.apply methods;
rebuild.call(this);
or:
rebuild(this);
function rebuild(that) {
var schema = $(that).data('schema');
}
* -> Exception is if you're in strict mode, where its undefined, but this isn't relevant here.
You can store "this" object to some variable and then use it from everywhere where this variable is visible
var currentObj = $(this);
function rebuild() {
var schema = currentObj.data('schema');
}
How come in the code below, the second line is giving me an undefined error?
function DAO()
{
this.arrVariable = new Array();
this.getItem = getItem;
this.getItemQuery = getItemQuery;
}
function getItem(key)
{
dao.arrVariable[key]();
}
function getItemQuery(key, url, options, pollfrequency)
{
alert('hey');
}
var dao = new DAO();
dao.arrVariable['var1'] = function() { this.getItemQuery('a','b','c','d'); };
dao.arrVariable['var1']();
I want to be able to access the dao's getItemQuery as an object call. How do I do this?
In that context, this refers to arrVariable. You can instead refer to it as dao.getItemQuery() inside the function:
dao.arrVariable['var1'] = function() { dao.getItemQuery('a','b','c','d'); };
You can use apply or call here.
So, instead of
dao.arrVariable['var1']();
Use either
dao.arrVariable['var1'].apply(dao, /* array of arguments here */);
or
dao.arrVariable['var1'].call(dao, /* arguments here, separated by commas */);
dao.getItemQuery can access dao's property
THe this in function() { this.getItemQuery('a','b','c','d'); }; refers to function() not to DAO. You need to access DAO by:
dao.arrVariable['var1'] = function() { dao.getItemQuery('a','b','c','d'); };