Is there a way to access jQuery object from previous chain? - javascript

Not sure how I could search for these type of question/answer...
This is what I am trying to do...
(function($){
$.fn.helloworld = {
want: function () {
alert("I want" + this + "!");
}
};
})(jQuery);
Now when I call the function this way, and try to retrieve this, it will only give me the helloworld "object".
$("#test").helloworld.want();
Is there a way to access the caller element, #test, from within?

There's no "nice" way. You could do this:
var $test = $('#test');
$test.helloworld.want.call($test);
The problem is that by setting up the structure you've got you're essentially forcing the behavior you say you don't want.
What you could do instead is this:
$.fn.helloworld = function( action ) {
var actions = {
test: function() {
alert("Hi!");
},
// ...
};
if (actions[action])
return actions[action].apply(this, [].slice.call(arguments, 1));
return this;
};
Now you can call it:
$('#this').helloworld("test");

Related

How to store variables: Privileged method, static property

Instead of just saying:
var thing = timeConsumingMethod();
I have my variable hidden in a method like so:
function _thing() {
var thing = timeConsumingMethod() );
return thing;
}
It gets called a number of times. I'm concerned that I'm made things very inefficient. I assume it calls timeConsumingMethod every time (which is unneeded, it's always the same) I call "_thing()" to get my variable.
How do I manage these types of variables in simple efficient way? Is something like this a solution?:
function _thing() {
return _thing.thing
}
_thing.thing = timeConsumingMethod();
Basically, i want the protection of a function and to (ideally0 access my variable using _thing() or something similar, but I only want timeConsumingMethod to run once.
edit: tried this, doesn't work either:
function _thingy() {
var thing = timeConsumingMethod();
}
_thingy.test = function() {
return( _thingy.thing)
}
Why not just:
function SomethingTimeConsuming() { ... }
function LazyThing(sourceFunction) {
this.sourceFunction = sourceFunction;
this.value = null;
this.Value = function() {
if ( this.value == null) this.value = sourceFunction();
return this.value;
}
}
JSFiddle: http://jsfiddle.net/YSAjJ/
Output:
[14:20:20.079] Calling time-consuming function *(1 time)

jquery fn.extend() returning values and call values in object

I need some help in understanding something, that propably is easy for serious jquery and javascript programmers.
Lets say I have a code like this:
jQuery.fn.extend({
myNameSpace: {
myPlugIn: function (o) {
var o = { variable : o.variable || false };
var myfunction = function(v) {
o.variable = v;
};
return {
myfunction : myfunction
};
}
});
and now I am able to call that with:
x = new $.myNameSpace.myPlugIn({variable : 99}) ;
and then I call my function myfunction like this
x.myfunction(20);
I can understand that, now the question: how can I get the value of variable inside my plug in.
I tried something like alert(x.o[variable]); etc. but I just cant get it - It must be easy...
What I try to accomplish is a value I could call if something inside the plugin is finished, or calculated.
You can not get the variables inside with your current code, unless you change it to:
var myfunction = function(v) {
o.variable = v;
return v; //or o.variable
};
//...
x.myfunction(20) //20;
Added
It seems like you are trying to make a plugin for jQuery. To create a plugin, you do not use $.extend. $.extend is only used to preset default settings. [1] Normally this is how you set up a plugin:
(function($) {
var methods = {
getVar: function(){
return $.extend({
data: data,
}, methods);
},
setVar: function(d){
data = d;
return methods;
}
},
data = {};
$.fn.myPlugin = function(options) {
//do stuff
data = $.extend( data , options );
return methods;
};
})(jQuery);
http://jsfiddle.net/DerekL/wv5QH/1/

Overriding a function in jQuery plugin

I have an existing jQuery plugin, now I want to extend it. Consider the below mentioned plugin:
$.fn.x = function(option) {
var def = {
a: 1,
b: 2
};
option = $.extend(def, option);
function abc() {
//do something
}
function def() {
//do something
}
};
Now the above one is the plugin I got from somewhere. I need to have custom behavior for abc method, say
function abc() {
//do something else
}
I don't want to change the existing plugin, Can you tell me how could I achieve the same by extending the same or by making my own custom plugin ?
EDIT:
I tried this too with method mentioned below:
(function($) {
$.fn.x = function(option) {
var defaults = {
a: 1,
b: 2
};
option = $.extend(def, option);
function abc() {
//do something
console.log('Base method called');
}
function def() {
//do something
abc();
}
def();
};
})(jQuery);
(function() {
var x = $.fn.x;
$.fn.x.abc = function() {
console.log('Overidden method called');
//_x.abc();
};
})();
$('<div/>').x();
But I am still getting "Base method called" as the console output.
The best route can vary, but something that I've done in the past is to wrap the extension in my own! This works best when you're trying to operate on something that the plugin does without modifying its underlying code.
(function($){
$.fn.extendedPlugin = function(options) {
var defaults = {
//...
};
var options = $.extend(defaults, options);
//Here you can create your extended functions, just like a base plugin.
return this.each(function() {
//Execute your normal plugin
$(this).basePlugin(options);
//Here you can put your additional logic, define additional events, etc
$(this).find('#something').click(function() {
//...
});
});
};
})(jQuery);
I know this isn't terribly specific (it's hard without a specific scenario), but hopefully it'll get you started down the right path!
This is as far as I got. But when I uncomment _x.abc.apply( this, arguments );, it gets stuck in a recursive loop.
Here's the jsfiddle if someone wants to play with and fix it:
http://jsfiddle.net/TLAx8/
// PLUGIN DEFINITION
(function( $ ){
$.fn.x = function(option) {
var def = {
a: 1,
b: 2
};
option = $.extend(def, option);
function abc() {
console.log( 'Plugin method called' );
}
function def() {
//do something
}
};
})( jQuery );
// OVERRIDING THE PLUGIN METHOD
(function(){
var _x = $.fn.x;
$.fn.x.abc = function() {
console.log( 'Overidden method called' );
//_x.abc.apply( this, arguments );
}
})();
// INVOKING THE METHOD
(function() {
$.fn.x.abc();
});

Is there a Javascript equivalent of Ruby's andand?

In trying to make my Javascript unobtrusive, I'm using onLoads to add functionality to <input>s and such. With Dojo, this looks something like:
var coolInput = dojo.byId('cool_input');
if(coolInput) {
dojo.addOnLoad(function() {
coolInput.onkeyup = function() { ... };
});
}
Or, approximately equivalently:
dojo.addOnLoad(function() {
dojo.forEach(dojo.query('#cool_input'), function(elt) {
elt.onkeyup = function() { ... };
});
});
Has anyone written an implementation of Ruby's andand so that I could do the following?
dojo.addOnLoad(function() {
// the input's onkeyup is set iff the input exists
dojo.byId('cool_input').andand().onkeyup = function() { ... };
});
or
dojo.byId('cool_input').andand(function(elt) {
// this function gets called with elt = the input iff it exists
dojo.addOnLoad(function() {
elt.onkeyup = function() { ... };
});
});
I don't know Dojo, but shouldn't your first example read
dojo.addOnLoad(function() {
var coolInput = dojo.byId('cool_input');
if(coolInput)
coolInput.onkeyup = function() { ... };
});
Otherwise, you might end up trying to access the element before the DOM has been built.
Back to your question: In JavaScript, I'd implement andand() as
function andand(obj, func, args) {
return obj && func.apply(obj, args || []);
}
Your example could then be written as
dojo.addOnLoad(function() {
andand(dojo.byId('cool_input'), function() {
this.onkeyup = function() { ... };
});
});
which isn't really that much shorter than using the explicit if statement - so why bother?
The exact syntax you want is not possible in JavaScript. The way JavaScript executes would need to change in a pretty fundamental fashion. For example:
var name = getUserById(id).andand().name;
// ^
// |-------------------------------
// if getUserById returns null, execution MUST stop here |
// otherwise, you'll get a "null is not an object" exception
However, JavaScript doesn't work that way. It simply doesn't.
The following line performs almost exactly what you want.
var name = (var user = getUserById(id)) ? user.name : null;
But readability won't scale to larger examples. For example:
// this is what you want to see
var initial = getUserById(id).andand().name.andand()[0];
// this is the best that JavaScript can do
var initial = (var name = (var user = getUserById(id)) ? user.name : null) ? name[0] : null;
And there is the side-effect of those unnecessary variables. I use those variables to avoid the double lookup. The variables are mucking up the context, and if that's a huge deal, you can use anonymous functions:
var name = (function() {return (var user = getUserById(id)) ? user.name : null;})();
Now, the user variable is cleaned-up properly, and everybody's happy. But wow! what a lot of typing! :)
You want dojo.behavior.
dojo.behavior.add({
'#cool_input': {
onKeyUp: function(evt) { ... }
}
});
How about something like this:
function andand(elt, f) {
if (elt)
return f(elt);
return null;
}
Call like this:
andand(dojo.byId('cool_input'), function(elt) {
// this function gets called with elt = the input iff it exists
dojo.addOnLoad(function() {
elt.onkeyup = function() { ... };
});
});
As far as I know there isn't a built-in JavaScript function that has that same functionality. I think the best solution though is to query by class instead of id and use dojo.forEach(...) as you will be guaranteed a non-null element in the forEach closure.
You could always use the JavaScript equivalent:
dojo.byId('cool_input') && dojo.byId('cool_input').whateverYouWantToDo(...);
I've never used dojo, but most javascript frameworks (when dealing with the DOM) return the calling element when a method is called from the element object (poor wording, sorry). So andand() would be implicit.
dojo.addOnLoad(function() {
dojo.byId('cool_input').onkeyup(function(evt) { /*event handler code*/
});
});
For a list:
Array.prototype.andand = function(property, fn) {
if (this.filter(property).length > 0) this.map(fn);
}

Can event handler defined within JavaScript object literal access itself?

I know I could do this with closures (var self = this) if object was a function:
click here
<script type="text/javascript">
var object = {
y : 1,
handle_click : function (e) {
alert('handling click');
//want to access y here
return false;
},
load : function () {
document.getElementById('x').onclick = this.handle_click;
}
};
object.load();
</script>
The simplest way to bind the call to handle_click to the object it is defined in would be something like this:
var self=this;
document.getElementById('x').onclick =
function(e) { return self.handle_click(e) };
If you need to pass in parameters or want to make the code look cleaner (for instance, if you're setting up a lot of similar event handlers), you could use a currying technique to achieve the same:
bind : function(fn)
{
var self = this;
// copy arguments into local array
var args = Array.prototype.slice.call(arguments, 0);
// returned function replaces first argument with event arg,
// calls fn with composite arguments
return function(e) { args[0] = e; return fn.apply(self, args); };
},
...
document.getElementById('x').onclick = this.bind(this.handle_click,
"this parameter is passed to handle_click()",
"as is this one");
So, the event handler part wires up just fine (I tested it myself) but, as your comment indicates, you have no access to the "y" property of the object you just defined.
This works:
var object = {
y : 1,
handle_click : function (e) {
alert('handling click');
//want to access y here
alert(this.y);
return false;
},
load : function () {
var that = this;
document.getElementById('x').onclick = function(e) {
that.handle_click(e); // pass-through the event object
};
}
};
object.load();
There are other ways of doing this too, but this works.
I see how to do it with Jason's latest one. Any way to do it without the anonymous function?
We can directly pass an object with a handler method thanks to AddEventListener, and you will have access to its attributes:
http://www.thecssninja.com/javascript/handleevent
Hope this will help those who, like me, will look for this topic some years after!

Categories