simple jquery widget - javascript

jQuery.widget("ui.test", {
_init: function(){
alert(this.element.innerHTML);
}
});
How do I make it so when I am attaching this to a HTML element
It will alert the innerHTML (I know it does nothing, it is just to understand the basics).
<div id="baba">ja jaj</div>
<script>
$('#baba').test();//will alert "ja jaj"
</script>
What am I missing here?
What I missed:
My code was actually perfectly fine, EXCEPT, I assumed that this.element is an HTML element, while in reality it is a jQuery object. Hence innerHTML did nothing while html(), in the answer below, worked.

You're missing the jQuery UI library. Simply attach it and yu're good to go - http://jsfiddle.net/jUm5H/
(function($) {
$.widget("ui.test", {
_init: function() {
alert( this.element.html() );
}
});
}(jQuery));
$('#baba').test();
UPDATE
"To make sure that your plugin doesn't collide with other libraries that might use the dollar sign, it's a best practice to pass jQuery to an IIFE (Immediately Invoked Function Expression) that maps it to the dollar sign so it can't be overwritten by another library in the scope of its execution." - source
So it's basically just a good practice. You can ignore it and it will work - http://jsfiddle.net/jUm5H/1/ But it's better to do it in a correct way from the beginning. It might save a lot of debugging time and frustration in the future projects :)

Related

Why use jQuery plugins over javascript functions?

Why would you use a jQuery plugin over a traditional javascript function? The only difference I see is you need to pass in a jQuery object into the js function... other that that, I don't see a huge difference, as it seems both can accomplish the same thing in similar steps:
$(document).ready(function () {
$('p').jQuery_greenify();
greenify($('p'));
});
$.fn.jQuery_greenify = function () {
this.css("color", "green");
};
function greenify (el) {
el.css("color", "green");
}
I also find namespacing to be easier with javascript functions:
var mynamespace = {
greenify : function (el) {
el.css("color", "green");
}
}
mynamespace.greenify($('p'));
Usually, usefulness of JQuery functions is in chaining them. Just like you want to call:
string.substring(2, 5).startsWith("lol")
instead of
Util.StartsWith(Util.substring(string, 2, 5), "lol")
It's easier to read that way. In fact, I think that second function might still need a "return this" to be useful?
It may depend on the context - some operations are very much tied to an element or set of elements, while others just make more sense standing on their own - thus, your approach of namespacing would be just fine. It's partially coding style.
A disclaimer - I'm not as experienced with writing JQuery plugins, this is just my general observations based on JS language design.
Always a jQuery object
When using a plugin as you said (it is really an object prototype) You are sure that this will be a jQuery object since you cannot call it without a jQuery object except if you make your way around with .call, .apply, .bind and etc.
Meanwhile, you can pass anything to a function, so the argument may not be a jQuery object and will throw an error.
Readability when chaining
You can chain function with both method, but let be honest, with a jQuery prototype, it is prettier :
$.fn.jQuery_greenify = function () {
return this.css("color", "green");
};
$('div').jQuery_greenify().append(...);
//VS
function greenify (el) {
return el.css("color", "green");
}
greenify($('div')).append(...);
Scope
When adding a function to the prototype, no matter which scope you are, it will be accessible everywhere. That allow you the create a certain closure :
(function(){
$.fn.jQuery_greenify = function () {
return this.css("color", "green");
};
})();
$('div').jQuery_greenify(); //Work
//VS
(function(){
function greenify (el) {
return el.css("color", "green");
}
})();
greenify($('div')); //Undefined is not a function error
The original usefulness of jQuery was to provide a consistent API to things such as DOM manipulation and AJAX - things which [older] browsers implemented very differently. It would take 20+ lines of code to do what can be done with 1 - 2 lines with jQuery. It abstracted away all of the inconsistencies so you could just focus on coding.
Then, John Resig's worst nightmare happened and people now think jQuery is a language, almost separate and independent from Javascript. </rant>
Today, most browsers have adopted standards and you don't have to worry so much about inconsistencies unless you are trying to support < IE9. You can use something like underscore to help take advantage of newer javascript features (with backwards compatability for things which are still inconsistently implemented even in today's browsers).
Regarding plugins, the advantage is having a consistent way to implement reusable code. For example, I kind of disagree with how you created a namespace (not really, but I would have done it differently).
Point is, it's all javascript. Learn javascript. If it's easier and quicker to do it without using a library, by all means do it! Pay attention to the community and try and use techniques which have been adopted by others... even if it occasionally means using a library.
NOTE: If someone puts jQuery under the "languages" section on their resume, throw it in the trash.

Why "$().ready(handler)" is not recommended?

From the jQuery API docs site for ready
All three of the following syntaxes are equivalent:
$(document).ready(handler)
$().ready(handler) (this is not recommended)
$(handler)
After doing homework - reading and playing with the source code, I have no idea why
$().ready(handler)
is not recommended. The first and third ways, are exactly the same, the third option calls the ready function on a cached jQuery object with document:
rootjQuery = jQuery(document);
...
...
// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
But the ready function has no interaction with the selector of the selected node elements, The ready source code:
ready: function( fn ) {
// Attach the listeners
jQuery.bindReady();
// Add the callback
readyList.add( fn );
return this;
},
As you can see, it justs add the callback to an internal queue( readyList) and doesn't change or use the elements in the set. This lets you call the ready function on every jQuery object.
Like:
regular selector: $('a').ready(handler) DEMO
Nonsense selector: $('fdhjhjkdafdsjkjriohfjdnfj').ready(handler) DEMO
Undefined selector:$().ready(handler) DEMO
Finally... to my question: Why $().ready(handler) is not recommended?
I got an official answer from one of the jQuery developers:
$().ready(fn) only works because $() used to be a shortcut to $(document) (jQuery <1.4)
So $().ready(fn) was a readable code.
But people used to do things like $().mouseover() and all sorts of other madness.
and people had to do $([]) to get an empty jQuery object
So in 1.4 we changed it so $() gives an empty jQuery and we just made $().ready(fn) work so as not to break a lot of code
$().ready(fn) is literally now just patched in core to make it work properly for the legacy case.
The best place for the ready function is $.ready(fn), but it's a really old design decision and that is what we have now.
I asked him:
Do you think that $(fn) is more readable than $().ready(fn) ?!
His answer was:
I always do $(document).ready(fn) in actual apps and typically there's only one doc ready block in the app it's not exactly like a maintenance thing.
I think $(fn) is pretty unreadable too, it's just A Thing That You Have To Know Works™...
Since the different options do pretty much the same thing as you point out, it's time to put on the library writer hat and make some guesses.
Perhaps the jQuery people would like to have $() available for future use (doubtful since $().ready is documented to work, even if not recommended; it would also pollute the semantics of $ if special-cased).
A much more practical reason: the second version is the only one that does not end up wrapping document, so it's easier to break when maintaining the code. Example:
// BEFORE
$(document).ready(foo);
// AFTER: works
$(document).ready(foo).on("click", "a", function() {});
Contrast this with
// BEFORE
$().ready(foo);
// AFTER: breaks
$().ready(foo).on("click", "a", function() {});
Related to the above: ready is a freak in the sense that it's (the only?) method that will work the same no matter what the jQuery object wraps (even if it does not wrap anything as is the case here). This is a major difference from the semantics of other jQuery methods, so specifically relying on this is rightly discouraged.
Update: As Esailija's comment points out, from an engineering perspective ready should really be a static method exactly because it works like this.
Update #2: Digging at the source, it seems that at some point in the 1.4 branch $() was changed to match $([]), while in 1.3 it behaved like $(document). This change would reinforce the above justifications.
I would say its simply the fact that $() returns an empty object whereas $(document) does not so your applying ready() to different things; it still works, but I would say its not intuitive.
$(document).ready(function(){}).prop("title") // the title
$().ready(function(){}).prop("title") //null - no backing document
More than likely this is just a documentation bug and should be fixed, the only downside to using $().ready(handler) is it's readability. Sure, argue that $(handler) is just as unreadable. I agree, that's why I don't use it.
You can also argue that one method is faster than another. However, how often do you call this method enough times in a row on a single page to notice a difference?
Ultimately it comes down to personal preference. There is no downside to using $().ready(handler) other than the readability argument. I think the documentation is miss-leading in this case.
Just to make it patently obvious that there is some inconsistency in the three, plus I added the fourth often used form: (function($) {}(jQuery));
With this markup:
<div >one</div>
<div>two</div>
<div id='t'/>
and this code:
var howmanyEmpty = $().ready().find('*').length;
var howmanyHandler = $(function() {}).find('*').length;
var howmanyDoc = $(document).ready().find('*').length;
var howmanyPassed = (function($) { return $('*').length; }(jQuery));
var howmanyYuck = (function($) {}(jQuery));
var howmanyYuckType = (typeof howmanyYuck);
$(document).ready(function() {
$('#t').text(howmanyEmpty + ":" + howmanyHandler + ":"
+ howmanyDoc + ":" + howmanyPassed + ":" + howmanyYuckType);
});
The displayed results of the div from the last statement are: 0:9:9:9:undefined
SO, only the Handler and Doc versions are consistent with the jQuery convention of returning something of use as they get the document selector and with the Passed form you must return something (I wouldn't do this I would think, but put it in just to show "inside" it has something).
Here is a fiddle version of this for the curious: http://jsfiddle.net/az85G/
I think this is really more for readability than anything else.
This one isn't as expressive
$().ready(handler);
as
$(document).ready(handler)
Perhaps they are trying to promote some form of idiomatic jQuery.

Overwrite jQuery to execute code after element has become visible - how to?

I am developing a small javascript framework for internal use in our company. In some cases our framework is overwriting basic jQuery functionality in order to handle internal logic or fix browser bugs etc. I want these cases to be completely transparent for our developers so they can just keep using jQuery the way they are used to.
I have come across a problem that I can’t seem to get my head around to do in a nice transparent way – at least I can’t come up with a good way to do it - so I turn to you :).
What I want to do is overwrite jQuery in a way so I can execute a certain piece of code each time something “becomes visible”. For instance if a developer runs the show() method, I want to execute my code after the element has become visible. In fact no matter how the developer “makes an element visible” (e.g. show(), css(), animate() etc.) I want my code to run
I know that show() for instance has a “callback” parameter that can be used for just that. But the point is; this should be totally transparent for the developer. He does not need to know that this code is “run underneath”.
All my overwrites is done using closures, so I can save a reference to the original method, do my thing and execute the original. Here is an example of how I am doing this with the show method:
(function ($) {
var originalShowMethod = jQuery.fn.show;
jQuery.fn.show = function (speed, easing, callback) {
// Do stuff before
var theReturn = jQuery(originalShowMethod.call(this, speed, easing, callback));
// Do stuff after
return theReturn;
};
})(jQuery);
My initial approach was to just simply do it this way (running my code at “// Do stuff after”). That also works great except when you are passing a speed parameter (because then it's using something like setTimeout or setInterval internally), or using one of the other “show an element” methods.
Is there some master “show an element” method in jQuery that I can overwrite so all methods that has something to do with “showing elements” will be affected by my piece of code? Or do I have to overwrite all "showing methods"? Can anyone give an example of how I can accomplice this task? and what i need to overwrite if that's the way to do it.
Thanks in advance.
I think you want something like the .is() and the :visible selector, it sounds like you might want to run a function like this using setInterval
function checkElementVis(){
if($(".element").is(":visible")){
alert("is visible");
} else {
alert("not visible");
}
}

How can dynmically change a line of a JavaScript function?

Suppose I had the following function:
function alertMesg()
{
alert("This ok function alerts message!");
}
Now at run time I would like to change the alertMesg function to do something else. My thought was to do somehting like this.
var temp = window.alertMesg.toString.replace("ok","great")
temp = temp.replace('function alertMesg()',"");
window.alertMesg = new Function(temp);
Basically, the problem is I have no control over the source in the alertMesg function. I would like to change the function, but I can't actually change the source of it because it is produced server side. That being said, I need it to act differently.
PS: I forgot to mention an important part: I have to keep most of the function. I can't just replace the function out right. I have to keep 95% of the function the way it is, and change the other five percent.
#Barlow Tucker, quixoto, pekka
Thanks, for the interest.
Basically, I don't think the proxy idea will work because I am not just adding functionality, I am changing the functionality of the code. I want for example, the third line of the function to be different. In my real life example I have to add a line right in the middle of a function.
If you must replace the content of a function, it is possible:
function alertMesg()
{
alert ("This ok function alerts my message!");
}
alertMesg(); // alerts "This ok function alerts my message!"
// do whatever you want to the function here
var temp = alertMesg.toString();
temp = temp.replace('my', 'your');
// now replace the original function
alertMesg=new Function(temp.substring(temp.indexOf('{')+1,temp.lastIndexOf('}')));
alertMesg(); // alerts "This ok function alerts your message!"
This probably isn't the best way to do what you're trying to achieve, but I can't really suggest anything else unless you provide more details.
Dynamic code replacement like you're suggesting might work in some cases, but it's a scary road to go down-- fragile, one wrong step and you're busted, and it quickly becomes a maintenance nightmare.
As a commenter said, your cleaner bet is to just wrap the native window.alert and then do the right thing when the string you care about comes through, per the answer here:
JavaScript: Overriding alert()
(Insert standard comment here about how you should get your server side people on the same page/team as you on this so you don't need to hack around your own page.)
UPDATE: You're not asking about alert, you're asking about this problem generally. Yes, you could what others are suggesting. But if you have the original code for the function, why not just replace it entirely? If the function you want is a global function called foo(), you can run JS that does:
window.foo = function() {
// The stuff I know is there (A)
...
// Some new stuff I want to change (B)
...
// More stuff I know is there (C)
}
Which will throw away the original and replace it with your version. This would work reasonably well, although "monkey patching" the stuff in the page definitely comes with some maintenance headaches.
I will definitely note here that if you can't do this for some reason and thus insist on doing textual code replacement in the middle of existing functions, you're abusing the language/environment for the purposes of maintainable anything, and you are truly screwed in multiple ways.

How to change onClick handler dynamically?

I'm sure there are a million posts about this out there, but surprisingly I'm having trouble finding something.
I have a simple script where I want to set the onClick handler for an <A> link on initialization of the page.
When I run this I immediately get a 'foo' alert box where I expected to only get an alert when I click on the link.
What stupid thing am I doing wrong? (I've tried click= and onClick=)...
<script language="javascript">
function init(){
document.getElementById("foo").click = new function() { alert('foo'); };
}
</script>
<body onload="init()">
<a id="foo" href=#>Click to run foo</a>
</body>
Edit: I changed my accepted answer to a jQuery answer. The answer by 'Már Örlygsson' is technically the correct answer to my original question (click should be onclick and new should be removed) but I strongly discourage anyone from using 'document.getElementById(...) directly in their code - and to use jQuery instead.
Try:
document.getElementById("foo").onclick = function (){alert('foo');};
Use .onclick (all lowercase). Like so:
document.getElementById("foo").onclick = function () {
alert('foo'); // do your stuff
return false; // <-- to suppress the default link behaviour
};
Actually, you'll probably find yourself way better off using some good library (I recommend jQuery for several reasons) to get you up and running, and writing clean javascript.
Cross-browser (in)compatibilities are a right hell to deal with for anyone - let alone someone who's just starting.
jQuery:
$('#foo').click(function() { alert('foo'); });
Or if you don't want it to follow the link href:
$('#foo').click(function() { alert('foo'); return false; });
I tried more or less all of the other solutions the other day, but none of them worked for me until I tried this one:
var submitButton = document.getElementById('submitButton');
submitButton.setAttribute('onclick', 'alert("hello");');
As far as I can tell, it works perfectly.
If you want to pass variables from the current function, another way to do this is, for example:
document.getElementById("space1").onclick = new Function("lrgWithInfo('"+myVar+"')");
If you don't need to pass information from this function, it's just:
document.getElementById("space1").onclick = new Function("lrgWithInfo('13')");
OMG... It's not only a problem of "jQuery Library" and "getElementById".
Sure, jQuery helps us to put cross-browser problems aside, but using the traditional way without libraries can still work well, if you really understand JavaScript ENOUGH!!!
Both #Már Örlygsson and #Darryl Hein gave you good ALTARNATIVES(I'd say, they're just altarnatives, not anwsers), where the former used the traditional way, and the latter jQuery way. But do you really know the answer to your problem? What is wrong with your code?
First, .click is a jQuery way. If you want to use traditional way, use .onclick instead. Or I recommend you concentrating on learning to use jQuery only, in case of confusing. jQuery is a good tool to use without knowing DOM enough.
The second problem, also the critical one, new function(){} is a very bad syntax, or say it is a wrong syntax.
No matter whether you want to go with jQuery or without it, you need to clarify it.
There are 3 basic ways declaring function:
function name () {code}
... = function() {code} // known as anonymous function or function literal
... = new Function("code") // Function Object
Note that javascript is case-sensitive, so new function() is not a standard syntax of javascript. Browsers may misunderstand the meaning.
Thus your code can be modified using the second way as
= function(){alert();}
Or using the third way as
= new Function("alert();");
Elaborating on it, the second way works almost the same as the third way, and the second way is very common, while the third is rare. Both of your best answers use the second way.
However, the third way can do something that the second can't do, because of "runtime" and "compile time". I just hope you know new Function() can be useful sometimes. One day you meet problems using function(){}, don't forget new Function().
To understand more, you are recommended read << JavaScript: The Definitive Guide, 6th Edition >>, O'Reilly.
I agree that using jQuery is the best option. You should also avoid using body's onload function and use jQuery's ready function instead. As for the event listeners, they should be functions that take one argument:
document.getElementById("foo").onclick = function (event){alert('foo');};
or in jQuery:
$('#foo').click(function(event) { alert('foo'); }
Here is the YUI counterpart to the jQuery posts above.
<script>
YAHOO.util.Event.onDOMReady(function() {
document.getElementById("foo").onclick = function (){alert('foo');};
});
</script>
I think you want to use jQuery's .bind and .unBind methods. In my testing, changing the click event using .click and .onclick actually called the newly assigned event, resulting in a never-ending loop.
For example, if the events you are toggling between are hide() and unHide(), and clicking one switches the click event to the other, you would end up in a continuous loop. A better way would be to do this:
$(element).unbind().bind( 'click' , function(){ alert('!') } );
Nobody addressed the actual problem which was happening, to explain why the alert was issued.
This code: document.getElementById("foo").click = new function() { alert('foo'); }; assigns the click property of the #foo element to an empty object. The anonymous function in here is meant to initialize the object. I like to think of this type of function as a constructor. You put the alert in there, so it gets called because the function gets called immediately.
See this question.
The YUI example above should really be:
<script>
YAHOO.util.Event.onDOMReady(function() {
Dom.get("foo").onclick = function (){alert('foo');};
});
</script>

Categories