call jQuery lib function identified with variable - javascript

I build recurring html with jQuery functions.
I'd like to give my functions more flexibility with $.append(), $.before(), and $.after(), etc.
Currently, I do something like
$.fn.appendRecurringHTML = function(domInsertMethod, domInsertID, htmlToInsert) {
if(domInsertMethod == 'append'){
$(domInsertID).append(htmlToInsert);
}
else if(domInsertMethod == 'before'){
$(domInsertID).before( ...
}
but I'd prefer (pseudo)
$.fn.appendRecurringHTML = function(domInsertMethod, domInsertID, htmlToInsert) {
$(domInsertID).window[domInsertMethod](htmlToInsert);
}
but that doesn't work for me.
Is this possible? If so, how?

Just use
$(domInsertID)[domInsertMethod](htmlToInsert);
DEMO: http://jsfiddle.net/UZKLY/
This works because the result of $(domInsertID) (or any $()) is a jQuery object, so it has properties and methods you want to call. Normally, you use dot notation to access them, but bracket notation is just as valid to use. Bracket notation is the only way to dynamically get a property/method (and allows for invalid identifier characters).
But be careful, because technically any method name could be provided, and therefore called. So it's up to you if you want to allow it or not.
As it stands, it doesn't make sense to add to $.fn, because you're not actually using the selected elements from the selector. It makes more sense to me to use this setup:
$.appendRecurringHTML = function(domInsertMethod, domInsertID, htmlToInsert) {
$(domInsertID)[domInsertMethod](htmlToInsert);
};
And you would call it like:
$.appendRecurringHTML("after", "#id", "html");
But if you wanted to use the selected element(s) as the target(s), you could use:
$.fn.appendRecurringHTML = function(domInsertMethod, htmlToInsert) {
return this.each(function () {
$(this)[domInsertMethod](htmlToInsert);
});
};
And call it like:
$("selector").appendRecurringHTML("after", "html");
DEMO: http://jsfiddle.net/UZKLY/1/
It preserves chaining, and will be applied to all matched elements.

Try this:
$(domInsertID)[domInsertMethod](htmlToInsert);
This approach creates jQuery object with your domInsertID first. Than selects domInsertMethod from that object's prototype chain and executes the method using htmlToInsert.

Related

jQuery - Utility Vs QuerySelection - methods

Utility methods
> Object.getOwnPropertyNames(jQuery).toString();
"prototype,fn,extend,expando,isReady,error,noop,isFunction,isArray,isWindow,isNumeric,isEmptyObject,isPlainObject,type,globalEval,camelCase,nodeName,each,trim,makeArray,inArray,merge,grep,map,guid,proxy,now,support,find,expr,unique,text,isXMLDoc,contains,filter,dir,sibling,Callbacks,Deferred,when,readyWait,holdReady,ready,acceptData,cache,noData,hasData,data,removeData,_data,_removeData,queue,dequeue,_queueHooks,access,event,removeEvent,Event,clone,buildFragment,cleanData,swap,cssHooks,cssNumber,cssProps,style,css,Tween,easing,fx,Animation,speed,timers,valHooks,attr,removeAttr,attrHooks,propFix,prop,propHooks,parseJSON,parseXML,active,lastModified,etag,ajaxSettings,ajaxSetup,ajaxPrefilter,ajaxTransport,ajax,getJSON,getScript,get,post,_evalUrl,param,parseHTML,offset,noConflict,length,name"
Query selection methods
> Object.getOwnPropertyNames(jQuery.prototype).toString();
"jquery,constructor,selector,length,toArray,get,pushStack,each,map,slice,first,last,eq,end,push,sort,splice,extend,find,filter,not,is,init,has,closest,index,add,addBack,parent,parents,parentsUntil,next,prev,nextAll,prevAll,nextUntil,prevUntil,siblings,children,contents,ready,data,removeData,queue,dequeue,clearQueue,promise,on,one,off,trigger,triggerHandler,text,append,prepend,before,after,remove,empty,clone,html,replaceWith,detach,domManip,appendTo,prependTo,insertBefore,insertAfter,replaceAll,css,show,hide,toggle,fadeTo,animate,stop,finish,slideDown,slideUp,slideToggle,fadeIn,fadeOut,fadeToggle,delay,val,attr,removeAttr,prop,removeProp,addClass,removeClass,toggleClass,hasClass,blur,focus,focusin,focusout,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error,contextmenu,hover,bind,unbind,delegate,undelegate,wrapAll,wrapInner,wrap,unwrap,serialize,serializeArray,ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend,offset,position,offsetParent,scrollLeft,scrollTop,innerHeight,height,outerHeight,innerWidth,width,outerWidth,size,andSelf"
From the documentation, I learnt that,
Methods called on jQuery selections are in the $.fn namespace, and automatically receive and return the selection as this.
Methods in the $ namespace are generally utility-type methods, and do not work with selections; they are not automatically passed any arguments, and their return value will vary.
From the above statement, I infer that,
1) Methods applied on query selections[ex- jQuery('ul li')] come from jQuery.prototype.
2) Methods coming from jQuery are utility methods.
Is my understanding correct?
Note: beginner
Your understanding is correct.
jQuery.fn is a reference to jQuery.prototype. When you define a function using jQuery.fn.myFunction = function() { }, you can access it using jQuery("div").myFunction(). Within this function, you can access the selected elements using this, so you can for example run this.html("newcontent"), which would in this example equal jQuery("div").html("newcontent").
When you define a function using jQuery.myFunction = function() { }, the function will not receive any selected elements, so it is only useful if you pass it some parameters.

Object has no method 'apply'

I am creating a few DOM elements dynamically like,
var anchorElement = jQuery('<a />',{text:property.text});
var liElement = jQuery('<li />',{"class":"navlink_"+i,id:"navlink_"+i});
anchorElement.on('click',property.fnctn);
liElement.append(anchorElement);
parentID.append(liElement);
Where property is a JSON object.
property.text is the text that I want to put into anchor element. (Works fine)
I want to attach a click event handler to that anchor element.
The function that needs to be bound to that element is specified in JSON and we can access it like
property.fnctn
The following line should bind the event handler to the anchor element.
anchorElement.on('click',property.fnctn);
This was not working so I tried converting it into string like,
anchorElement.on('click',property.fnctn.toString());
No Success...
When I click on this link, the error is logged in the console
The object has no method 'apply'.
What is the reason...???
I am able to get it working with a slight work around like
anchorElement.attr('onclick',property.fnctn+"()");
Above statement works, but I want to know why .on() API is not working.
Thanks :)
AÐitya.
Update:
Youve said that property.actfn is a string, "paySomeoneClick". It's best not to use strings for event handlers, use functions instead. If you want the function paySomeoneClick, defined in the string, to be called, and if that function is global, you can do this:
anchorElement.on('click',function(event) {
return window[property.fnctn](event);
});
That works because global functions are properties of the global object, which is available via window on browsers, and because of the bracketed notation described below.
If the function is on an object you have a reference to, then:
anchorElement.on('click',function(event) {
return theObject[property.fnctn](event);
});
That works because in JavaScript, you can access properties of objects in two ways: Dotted notation with a literal property name (foo.bar accesses the bar propety on foo) and bracketed notation with a string property name (foo["bar"]). They're equivalent, except of course in the bracketed notation, the string can be the result of an expression, including coming from a property value like property.fnctn.
But I would recommend stepping back and refactoring a bit so you're not passing function names around in strings. Sometimes it's the right answer, but in my experience, not often. :-)
Original answer:
(This assumed that property.fnctn was a function, not a string. But may be of some use to someone...)
The code
anchorElement.on('click',property.fnctn);
will attach the function to the event, but during the call to the function, this will refer to the DOM element, not to your property object.
To get around that, use jQuery's $.proxy:
anchorElement.on('click',$.proxy(property.fnctn, property));
...or ES5's Function#bind:
anchorElement.on('click',property.fnctn.bind(property));
...or a closure:
anchorElement.on('click',function(event) {
return property.fnctn(event);
});
More reading (on my blog):
Mythical methods
You must remember this
Closures are not complicated

Operating on a string rather than a selector from a jQuery Plugin

I want to create a plugin that works like so:
var fmatted = $('someString').myFunction();
I've developed jQuery functions in the following manner:
$(someSelector).someFunction();
I know that the selector gets converted to a jQuery object and can be used via this in the plugin. However, if I want to use a string rather than a selector, I'm not sure how I can access that string within my plugin.
Basically, I want to be able to use a plugin to operate on something other than a selector, very much like jQuery's .trim() function, but I can't figure out how to access that within the plugin.
jQuery(selector)[docs] (or $(selector)) is used to create a jQuery object containing elements that match the selector. Although it is possible for you to create a method which ignores the elements and retrieve the original selector, this is not efficient and makes it more difficult to understand what your code is doing.
jQuery.trim()[docs] is not implemented like that. In fact, notice that jQuery.trim() isn't a method on a jQuery object at all! If it were, you'd invoke it like this:
jQuery(" foo ").trim();
Instead, you do this:
jQuery.trim(" fooo ");
.trim() is a method, but not a method of jQuery objects. It's a method of the jQuery constructor function itself (in some languages you would call this a "class method").
You're not creating an object and the argument is never treated as a selector. To add a function like this yourself, all you need to do is this:
jQuery.someFunction = function(message) { alert(message); };
More idiomatically, the default behaviour of the jQuery.extend[docs] will do this for you:
jQuery.extend({someFunction: function(s) { alert(s); } })
That's all you need!
use the selector property:
var jQueryObject = $('my string');
var originalString = jQueryObject.selector;// it'll give you 'my string'
Is this what you're after?
$.fn.makeLower = function() { return this.selector.toLowerCase(); }
$("FOO").makeLower(); // produces "foo"

Understanding javascript function calls in format of myFunc(arg).something()

I'm trying to understand the format of the Javascript functions that jQuery, among other people, use.
For instance jQuery(arg).hide() or $("#obj").hide
I'd like to write similar format functions but I don't understand how.
I know how to write
function myFunc(args) {
}
but I don't understand the second part ie the .hide()
is that a function within a function?
thanks for any help
It's called method chaining. The way to achieve this is for your first function to return an object, so the second function can be called as a method on that object.
The standard way to do this style of programming is to always return the same type of object, so for example, jQuery always returns a jQuery object representing a collection of HTML nodes. If one of the calls modifies the collection then the next call will be on that collection. That's how you can do something like $('#myid').parent().hide();. $('#myid') returns a jQuery object representing the #myid element and .parent() returns a jQuery object representing the parent element of #myid. .hide() returns the same object, so you could then call another method on the same object if you wanted.
This is called method chaining. I highly recommend picking up Crockford's "JavaScript: The Good Parts". This is a very quick read but wonderfully explains OOP in JavaScript and identifies good versus bad language features. Highly recommend it.
As Skilldrick pointed out, this is called method chaining.
The most straightforward example for this is an object that returns itself when you call any of its methods:
var world = {
'hello': function() {
alert('Hello');
return this;
},
'goodbye': function() {
alert('Goodbye');
return this;
}
};
world.hello().goodbye();
This is identical to world.hello(); world.goodbye();.
jQuery does a little more than that. Calling the jQuery or $ function on a valid selector string will return a jQuery object representing the matched elements (it's not actually an array, though you could think of it as one). Most of its methods will return the object itself after modifying the object (e.g. $("a").css({...}) will apply changes to the styling of the matched elements and then return the set of matched elements again).
But some jQuery methods allow modifying the set you're working with (e.g. $("a").parent() will return a jQuery object representing the parents of the matched elements). That is, they don't return the same object, but an object that behaves identically.
You have to be careful if you decide to use this style, though, as the flow will break if you need a method that has a return value of its own (e.g. if you want calculations or getter methods). This can be avoided by passing a callback function to the method, but the resulting coding style may be terribly convoluted.

jquery object inside an object literal

i am trying not to repeat the selector and get to its children via a the same objects parentElment declared variable.
I tried:
testimonialsBelt={
parentElment:$(".testimonialsCntnr ul"),
childrenElem:this.parentElment.children().length
}
I also tried:
testimonialsBelt={
parentElment:$(".testimonialsCntnr ul"),
childrenElem:$("testimonialsBelt.parentElment").children().length
}
but i keep on getting a undefined when calling alert(testimonialsBelt.childrenElem).
is there anyway to get the jquery object with object literals?
What is the rule? when can i use this and when must i have the full path? (in this case testimonialsBelt.parentElment).
i am trying to have all these variables in one object called testimonialsBelt. i know i can do this with loose javaScript.
Thanks
In object literals, you can only use this to refer to the object that you're declaring inside of a function. Try the following:
var testimonialsBelt = {
parentElment: $(".testimonialsCntnr ul"),
childrenElem: function() {
return this.parentElment.children().length;
}
};
The difference in calling childrenElem is that instead of using alert(testimonialsBelt.childrenElem), you would instead have alert(testimonialsBelt.childrenElem()).
Otherwise, this refers to the current scope that you are in (typically window if you are declaring the object literal as a global).
Addressing your edit: I'm not sure what you mean by "loose javascript," but I assume you mean as simple as possible. In which case, you can try the following, although I'm not a big fan of the method. It's more verbose, but is easy to understand.
var testimonialsBelt = {
parentElment: $(".testimonialsCntnr ul")
};
testimonialsBelt.childrenElem = parentElment.children().length;
This gives you an object where childrenElem is static (it doesn't change) and avoids calling $(".testimonialsCntnr ul") twice. However, if you expect $(".testimonialsCntnr ul").children() to change, then you will need to use my first example.
In JavaScript (not ECMAScript) you can use this:
testimonialsBelt={
parentElment:#1=$(".testimonialsCntnr ul"),
childrenElem:#1#.children().length
}

Categories

Resources