calling chain method in javascript - javascript

I am using the following code but it is constantly giving me errors :
TypeError: container("accounts").atPosition("#left-top") is undefined
the code is :
function container(name, position) {
return {
pos: null,
atPosition: function(position) {
$(position).html(this.newContainer());
//$(position+" .main").html("yes");
this.pos = position;
},
populateData: function(rdata) {
$("#left-top .main").html(rdata);
},
newContainer: function() {
//alert(this.pos);
return '<h3>' + name.toTitleCase() + '</h3>\
<div class="main">\
</div>';
}
};
}
container('accounts').atPosition('#left-top').populateData("yahoo!!!!");​
Why am I receiving this error and how can I fix it?

You supposed to return this from functions for chaining. By default function return undefined (if you dont use new operator) . by returning this from function which don't have any thing to return will help in chaining.
function container(name, position) {
return {
pos: null,
atPosition: function(position) {
$(position).html(this.newContainer());
//$(position+" .main").html("yes");
this.pos = position;
return this;
},
populateData: function(rdata) {
$("#left-top .main").html(rdata);
return this;
},
newContainer: function() {
//alert(this.pos);
return '<h3>' + name.toTitleCase() + '</h3>\
<div class="main">\
</div>';
}
};
}​

The function you assign to atPosition doesn't have a return statement.
So when you call atPosition('#left-top'), you get the default return value of undefined
You need to return the object you wish to call populateData on (which should be this)

function chaining is not a special javascript syntax, if you want, you can implement it in Java, Python or anything that supports OOP.
a.functionX().functionY() works because functionX() returns again an object which has a method called functionY()
in your case, functionX() should return the same object it is invoked on, therefore return this; will fix your problem
But this is not the end of the story!!!
#Rich S mentioned in his answer:
In order to make chaining work, you need to "return this;" at the end of any functions you want to chain.
which is not necessary true, chaining will work as long as you return an object(or any object), here is an example:
var str ="abc";
var strFromChain = str.replace('a','x').toUpperCase();
// use function chainning
document.write(strFromChain+'\n');
// result should be XBC
var str1 = "abc";
str1.replace('a','x');
var str1NotFromChain = str1.toUpperCase();
// if replace() returned this, str1NotFromChain should also be XBC
document.write(str1NotFromChain)
// but is it???????
Obviously replace() method of str did not return this instead it returned a new string with a different value, and this is easy to understand since strings are immutables, no matter what methods you call on str, its value will always be "abc".
I am just making a point here, it's not necessary for chaining method to return this, it can return a new object if it wants to. Even though online tutorials teach you to use this when implementing chaining functions (ie javascript.issexy) you should always pay attention to what is being returned when using a third party library(ie route chainning in expressjs)

Chaining doesn't happen automatically.
In order to make chaining work, you need to "return this;" at the end of any functions you want to chain.
In reality, all you're doing is calling the function on whatever you return. If you do "return this;" then you end up with a nice chaining syntax that affects the same object.
The jQuery developer guide is a good place to get quality JavaScript tips from, given your question, I'd recommend looking at http://docs.jquery.com/Plugins/Authoring#Maintaining_Chainability

Related

After Effects / ExtendScript Function.caller equivalent

Since ExtendScript as implemented in After Effects does not appear to support many of the Function members like "Function.caller", is there another known way that would let you see the calling function's name, that works for AE CS5.5 upwards? Both built-in or external libs would be great.
If you want the running function name(callee), you can do it with:
arguments.callee.name
Example:
function someFuncName() {
$.write(arguments.callee.name);
}
someFuncName();
//Result: someFuncName
In your case(where you need the caller function name), ExtendScript hasn't built-in function that does it, so you need to create one:
function caller() {
var stack = $.stack.split('\n');
return stack.length === 4 ? null : stack[stack.length - 4].slice(0, -2);
}
Now, if we have a function that invoked by the top level code, so we will get null, otherwise we get the caller function name:
Example:
function someFuncName() {
$.write(caller());
}
function callerFuncName() {
someFuncName();
}
callerFuncName(); //Result: callerFuncName
someFuncName(); //Result: null

understanding the code from transit.js

I was just going through the source of transit.js and came across the following fucntion ::
$.cssHooks['transit:transform'] = {
// The getter returns a `Transform` object.
get: function(elem) {
return $(elem).data('transform') || new Transform();
},
// The setter accepts a `Transform` object or a string.
set: function(elem, v) {
var value = v;
if (!(value instanceof Transform)) {
value = new Transform(value);
}
// We've seen the 3D version of Scale() not work in Chrome when the
// element being scaled extends outside of the viewport. Thus, we're
// forcing Chrome to not use the 3d transforms as well. Not sure if
// translate is affectede, but not risking it. Detection code from
// http://davidwalsh.name/detecting-google-chrome-javascript
if (support.transform === 'WebkitTransform' && !isChrome) {
elem.style[support.transform] = value.toString(true);
} else {
elem.style[support.transform] = value.toString();
}
$(elem).data('transform', value);
}
};
I understand the latter part of the function, but its really hard to understand the initial part of the function, the function can be found on git too , HERE .
Initially I see this, $.cssHooks['transit:transform'] what is that line really saying?
After that we have the below line of code I.E. the getter and setter method,
set: function(elem, v) {
But who is passing the elem and v inside the function, I don't see anything being passed?
Read about cssHooks at jQuery cssHooks
Look at the source code (search for hooks.get and hooks.set)
.cssHooks is an array of objects that contains getter and setters tha will be executed by .css(). Thats all.
$.cssHooks['transit:transform'] = {set: function(elem,value){}, get: function(elem){}}
equal:
$.cssHooks['transit:transform'] = {};
$.cssHooks['transit:transform'].set = function(elem, value){};
$.cssHooks['transit:transform'].get = function(elem){};
$(element).css('transit:transform',value)
comes to:
$.cssHooks['transit:transform'].set(element,value)
$(element).css('transit:transform')
comes to:
$.cssHooks['transit:transform'].get(element)
$.cssHooks['transit:transform'] = {set:function(){}, get: function(){} }
{...} is an object creation.get and set not executed at this moment.
They created {set:function(){}, get: function(){} }
So. Simply: .css() will execute set and get functions for hooked property.
If you want to know how real getters and setters works:
Object.defineProperty()
In Javascript, you can add/access to a property with this syntax :
myObject.myProperty
or with this syntax :
myObject['myProperty']
This is the same result
So your line
$.cssHooks['transit:transform']
just mean that we want to store an object (code between {} in your original post) inside the 'transit:transform' property which is inside the cssHooks property which is inside the $ object
This is the same things :
$['cssHooks']['transit:transform']
The reason why they use the [''] syntax is that transit:transform contains the ':' char which is not allowed if you want to access it this way :
$.cssHooks.transit:transform //doesn't work
EDIT:
To answer to your second question, i don't know...the code you are showing is just the 'description' of the "transit:transform' property

javascript: dynamic call of nested function

in an existing implementation (can't change the structure much), i'm trying to call a function which is nested inside another function:
function outer(innerFunction, obj) {
//TODO: call innerFunction here, passing obj as first parameter
function inner1(obj) {
alert(obj.key);
}
}
outer('inner1', {key:'value'});
jsfiddle is here: http://jsfiddle.net/tbyyw/
i've alreay thought about using eval(), but i don't know how to pass an object - and they say 'eval is evil' ;)
another solution i've come up with is checking the innerFunction string, but this means i have to know which inner functions exist (besides, adding new functions would mean having to write extra checks then):
if(innerFunction == 'inner1') inner1(obj);
so is there another way without changing the overall implementation?
Without changing the overall structure eval appears to be the only option:
function outer(funcName, obj) {
var func = eval(funcName);
func(obj);
function inner1(obj) {
alert(obj.key);
}
}
There's nothing particularly "evil" about eval as long as you have full control over the code, but if you want, you can insert an additional security check:
if (funcName.match(/\W/))
throw "invalid function name!";
var func = eval(funcName);
This will raise an exception if someone tries to pass anything else than a simple identifier, i.e. a function name.
Is this what you wanted?
function outer(innerFunction, obj) {
var fn = {
inner1: function (obj) {
alert(obj.key);
}
};
fn[innerFunction](obj);
}
outer('inner1', {key:'value'});
http://jsfiddle.net/tbyyw/1/
A simple switch statement would be least intrusive. Or is the function name completely dynamic?
function outer(innerFunction, obj) {
switch (innerFunction) {
case "inner1": inner1(obj); break;
}
function inner1(obj) {
alert(obj.key);
}
}
outer('inner1', {key:'value'});
​

How to create javascript function lookup object?

I'm attempting to create a function lookup in Javascript essentially mapping a data type to a function that does something for that data type. Right now I have something similar to:
var Namespace = Namespace || {};
Namespace.MyObj = function () {
var stringFunc = function(someData) {
//Do some string stuff with someData
};
var intFunc = function(someData) {
//Do some int stuff with someData
};
var myLookUp = {
'string': stringFunc,
'int' : intFunc
};
return {
PublicMethod: function (dataType, someData) {
myLookUp[dataType](someData);
}
};
} ();
When I invoke Namespace.MyObj.PublicMethod(dataType, someData) I get an error that myLookUp is not defined. I'm assuming I'm not going about setting up the function lookup object correctly, but not sure how to do so. Thanks for any help.
The problem might simply be incorrect case
myLookup[dataType](someData);
should be (notice the capital U)
myLookUp[dataType](someData);
Just looked at my post after I wrote it up, stupid oversight, I'm declaring the properties as strings, instead of just properties.
....
var myLookUp = {
string: stringFunc,
int: intFunc
};
....
Fixes the issue.
Some additional follow up, in my actual code dataType is the result of a jQuery select. Don't know why or if this would be browser dependant (I'm using FireFox), but using double quotes around the property definition works, single quotes does not, and no quotes works as well. :-\

Why does this function return as undefined?

String.prototype.parse = function(f) {
alert(this.replace(f, ""));
};
var a = "Hello World";
parse.apply(a, ["Hello"]);
Is the code correct?
No, that’s not correct. The function is defined as String.prototype.parse, so it is not available as parse (in fact, parse is undefined).
You could run it like the following:
String.prototype.parse.apply(a, ["Hello"]);
But actually, the reason why you add the function to the prototype of String is that you extend String objects with that function. So you actually should just run the function like this:
a.parse("Hello");
edit:
Oh, and in response to your question title “Why does this function return as undefined?”: The function doesn’t return anything, because you don’t tell the function to return anything. You could for example define it like this to return the replaced string (instead of alerting it):
String.prototype.parse = function(f) {
return this.replace(f, "");
};
And then you could alert the return value of the function:
alert(a.parse("Hello"));
There is no such variable parse defined in your code sample. If you really want to apply the function later on, you should do this:
// Capture function as a local variable first
var parse = function(f) { alert(this.replace(f, "")); };
String.prototype.parse = parse;

Categories