jQuery selector debugger - javascript

I recently started to work on existing project. The previous developer had a lot of javascript and html template files. Over time, he removed pieces of code from this files leaving parts without any reference (see the examples).
For example
(a) a button without a click event
(b) a jquery selector without a DOM element inside the HTML: $('#someSelector') but <someElement id="someSelector"></someElement> doesn't exists.
The case (a) is quite simple to solve, because I just see the unused element and I delete it from the appropriate file.
The second part is a little bit more difficult, because the browser console is not firing an error when jQuery does not find a selector.
I can test selectors using something like this:
if($('theSelector').length ){
//alert or console, the selector matches some element.
}
This technique is very expensive in time, because I need to test one by one every selector.
Is there a tool for automate this task? I tried FireQuery (a firefox plugin) but it is not giving me good results.
P.S:
The project is not using a javascript framework nor system template. (really bad!)

you can kick the tires for a bit after modifying $ to log it's calls.
load the following script
var $$=$, log=[];
$=function(s){
log.push(s);
return $$.apply(this, arguments);
};
$$.extend($,$$);
now click around and do "everything" jQuery does on the site, then run:
console.log(log.filter(function(s){
return jQuery(s).length===0;
}));
to dump a list of un-realized selectors to the console. of course, fix the problems and remove this code because it slows jQuery down a lot, and it might not be 100% compatible with all plugins, but it works on the quick tests i did here on stack via the console. you might also consider shadowing "jQuery" in addition to "$" to capture noconflict usages.

Related

jQuery and selectors: how can I make sure that there really is the element I'm looking for?

I'm no experienced JavaScript developer (I know quite a lot about Ruby, though), and so far, when I had to implement some lines of JS, it seemed enough to use jQuery and hack together something.
As far as I understand jQuery, it doesn't assume HTML elements to really be there, but it simply executes a query, and if there is a matching element (or many), some stuff is done with it. This works well for generic code which may want to apply some action to some elements on a page (which may be there or not), but when it comes to specific logic, it's a problem.
What do I mean with this? Let me give an example.
Let's suppose I have one single page with one single HTML element (with the ID '#my_element'). For exactly this page I have to run some JS code, and I have to be sure that it finds this element and does the things to it that I want.
Doing this with jQuery, I simply do something like $('#my_element').addTooltip(), which seems fine first: when I hover over the element, a tooltip is displayed.
Let's assume that some months later I already have completely forgotten about this JS script, and I change the ID of the element to something else. What happens? Nothing. I won't notice the problem with the missing tooltip until I stumble over it by accident.
So I wonder how I can make sure that my JS is really applied, which means: the required elements are found, the stuff is done to them, etc.
Is jQuery's philosophy the "wrong" tool for this? Do I need another framework? Maybe something more sophisticated pattern, e.g. something like MVC? I played with KnockoutJS before, and it seems that this may be better for this, as it's bound directly to elements using data-bind attributes, so it fits tighter on the code than jQuery does.
The comments mentioned always checking the .length property before performing actions on returned results (which is probably the best answer,) but in the case of an actual syntax error your statement that "nothing happens" isn't always true.
If you're using Chrome developer tools or a similar tool in another browser (firebug, etc.) you should see the error in the "Console"
You can also turn on javascript debugging for more information. When you call the "addTooltip()" on something which is null (the jQuery collection) you'll see an error pop up in the Console and may get an exception in the debugger.
This is one of the easiest ways to find errors in your client-side javascript.
You could add a specific plugin to verify the existence of a non-zero- length collection, and use that in the chain:
(function ($) {
$.fn.verify = function() {
if (this.length) {
return this;
}
else {
console.log("No elements found with supplied selector.")
}
}
})(jQuery);
$("#myElement").verify().addTooltip();
This does, of course, rely on the verify() plugin being manually applied, there is – to the best of my knowledge – no error-reporting built in to jQuery to automatically enable logging of invalid selectors, or reporting of selectors returning zero elements.

Script on parent site not working on child site: $.Deferred is not a function

I have a website that is built off a parent site, and needs to be as identical as possible. My clients have a process through which they grab all the scripts and css files of the parent site and use them to create the child. For one of these websites though, I am getting an error in the main javascript file that is not happening on the parent site.
Here are the two websites:
parent site
child site
The main issue is that the carousel at the top of the page (I believe it's using slickslider) is not getting initialized on the child site. I am not sure if this is because of the Javascript errors, and if you can figure out the reason why it's not working I will be super grateful as that is the main issue at hand. That said, I'm assuming right now that my problem is the javascript error in main.js:
Uncaught TypeError: l.Deferred is not a function
Again, there are no errors on the parent site, but l.Deferred breaks on the child site. Why isn't it working?
I tried wrapping l in jQuery -- $(l).Deferred -- but when I did this it seemed to cause a loop, where the page would spend several minutes trying to load before timing out and crashing.
If you can tell me why the slider on my child site isn't working, or at the very least why l.Deferred is breaking, that would be a huge help.
EDIT: Update to use the correct version of jquery:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>jq11 = jQuery.noConflict(true);</script>
<script src="/sites/all/themes/wma2/js/main.js"></script>
(function($){
window.matchMedia || (window.matchMedia = function(){....
})(jq11);
UPDATE: I checked the console and $.fn.jQuery is using the jquery 1.11.2 at the point when it says l.Deferred is not a function
I also tried wrapping l in the correct jquery:
jq11(l).Deferred
but when I do that the page gets stuck in a loop and crashes after trying to load for several minutes.
I'm not 100% sure what "process through which they grab all the scripts and css files of the parent site and use them to create the child" means, but the client page is at least at some point loading jQuery 1.4.4 (check the first of the last 3 included scripts in the head).
$.Deferred wasn't introduced until jQuery 1.5, https://api.jquery.com/jquery.deferred/ so trying to run anything using 1.4.4 will throw an error because that function, indeed, doesn't exist there.
One of the last scripts on the page loads another entire copy of jQuery, and THAT one, 1.11, does support Deferreds. But it's almost the last thing to run on the page, so almost no code uses it. So you have an old jQuery, then code that tries to use a method in a newer jQuery, and then finally a newer jQuery. That's why jQuery and $ aren't even assigned to the same thing, as you can confirm in the console:
jQuery.fn.jquery: "1.4.4"
$.fn.jquery: "1.11.2"
It's possible that you have code that uses old 1.4.4 syntax, so you may not be able to replace it, but it's probably best, if you do need both versions, to wrap all your code explicitly in an IIFE
(function($){
/* code using $, which maps to whatever is specified at the end*/
})(jQuery);
that specifies which of the two you mean to use.

Keep the javascript fully separated from markup on primefaces

I'm working on a web interface with the help of primefaces framework.
In that interface, one of the objectives is to have the code divided in javascript functions that do not share information between each other and they don't allow being invoked by other parts (that eases testing and reduces the number and complexity of possible use-cases).
All "parts" are encapsulated using:
(function (window, document, undefined){
var $ = window.jQuery;
// main content here
})(window,document);
The communication required between each part is minimal and the required one is made using DOM events where an object is passed between each other. (if the event is not caught, it's just a functionality that didn't act. If it caused something to break, the js does not stop working, among other reasons).
This has been working for quite a while with minimal bugs found until I had to work with jsf+primefaces.
By reading the documentation, primefaces has many XML tags that do not map to HTML tags. One of the main ones I have to work with is <p:ajax>.
This tag was many on*-like attributes whose concept works much like the HTML3's ideology of writing javascript in HTML's "on*" attributes. Still, those <p:ajax> are always attached to specific XML elements like <h:inputText> or <p:commandButton> and that's where I started looking at.
In primefaces documentation, there's information about the inline on* attributes but I was fully unable to find information about jsf or primefaces' personalized DOM events.
How it appears with primefaces, I'm forced to change the javascript code so that functions/methods can be called inline in the HTML. That would require a lot of work also because, depending on the situation, the js code might even not be there (because the feature it enables is not required for that page).
How do I make the system on primefaces such that I have my javascript fully detached from the jsf/primefaces XML (and the whole HTML output I can manage).
EDIT:
I ran out of ideas on where to look at, I'll work on looking at primefaces source code now. I may get better luck there.
EDIT:
Meanwhile I got some ideas for searching using different keywords and I found this(see: "Client Side API"):
http://courses.coreservlets.com/Course-Materials/pdf/jsf/primefaces/users-guide/p-ajaxStatus.pdf
This is near what I wanted but it seems like it does not exist for the elements I mentioned above. I'll work on continuing searching for more.
After some testing, investigation, etc... I was finally able to understand the whole story of what was happening.
Primefaces was doing everything right after all! The <p:ajax> has the correct code to send all the events it should! The problem lies in jQuery itself.
jQuery's trigger() method (and it's shortcuts) works in such way that it handles all events directly inside jQuery bubbling and calling the callbacks registered using on() (or any of the shorthands).
The main issue in jQuery is that it only resend the "click" event to the DOM because it tries to use a method in the DOM element with the same name as the event. In the DOM, (at the moment) the only situation when that happens is the "click" event. That's why I was getting the click event and not the rest of the events.
With that, the mistery and confusion was, finally, solved. uff!

How to get jQuery code completion to work in Sublime Text 2?

I am doing some light jQuery based Javascript programming with Sublime Text 2. Is there such a thing as code completion for jQuery? I've installed SublimeCodeIntel, but getting nothing.
For instance, consider the following:
<div id="container">hello</div>
<script type="text/javascript">
function doStuff() {
$('#container').html('change it');
}
</script>
When I type $('#container'). I would expect a popup with things like html, val, etc... to popup. Has anyone gotten jQuery intellisense to work at all?
P.S. To be sure, I am not trying to get snippets working, but rather code completion.
Try package installer in sublime
search for jquery and install.
SublimeCodeIntel should work just fine with jQuery, you just need to tell it where to find it. Check out the docs on configuring search paths - basically, you create a ~/.codeintel/config file, and put something like
{
"JavaScript": {
"javascriptExtraPaths": ["/path/to/jquery.not-minified.js"]
}
}
in it. Remember to not use the minified version of jQuery, as some of the variable names can be changed (I think, don't hold me to it for v2). You also don't have the inline documentation. This file can also be created as /path/to/project_root/.codeintel/config if you're using different versions, different plugins, etc. Remember that SublimeCodeIntel can take a little while to index everything, so be patient the first time it runs. I've found it helpful to restart Sublime after indexing is done, just so everything is freshly loaded.
This jQuery package for Sublime text might help
https://github.com/mrmartineau/Jquery
If you have installed a jQuery syntax-file (there is one available from the link provided by Srikanth AD) then my AndyJS2 add-in is available via PackageControl.
AndyJS2 provides completions for both JavaScript and jQuery - use the syntax options by clicking the bottom-right of the ST window to switch between JavaScript and jQuery.
I doubt that it would work well, though, in parallel with SublimeCodeIntel. You can disable this Package, without having to uninstall it, from the Preferences menu, Package Control

How to use page-mod to modify element loaded by JavaScript

I'm creating firefox addon to add onclick event to the specific button. ("input" element)
The button is placed in http://example.com/welcome#_pg=compose
but when I open the page, following error occures:
TypeError: document.querySelector("#send_top") is null
#send_top is id of the button which I want to modify. So, the button is not found.
This error occurs because http://example.com/welcome and http://example.com/welcome#_pg=compose is completely different pages.
In this case, the addon seems loading http://example.com/welcome but there is no button whose '#send_top' ID.
When #_pg=compose anchor is added, the button is loaded by JavaScript.
How can I load http://example.com/welcome#_pg=compose to modify the button?
Three thoughts to help you debug this:
to correctly match the url you should consider using a regular expression instead of the page-match syntax - this might allow you to react to the anchors in a more predictable way
I've found that when using content scripts with pages that are heavily modified by JS, you can run into timing issues. A hacky workaround might be to look for the element you want and, if it isn' there, do a setTimeout for a 100 milliseconds or so and then re-check. Ugly, yes, but it worked for some example code I used with the new twitter UI, for example.
You can use the unsafeWindow variable in your content script to directly access the page's window object - this object will contain any changes JS has made to the page and is not proxied. You should use unsafeWindow with great caution however as its use represent a possible security problem. In particular, you should never trust any data coming from unsafeWindow, ever.

Categories

Resources