Why doesn't IE7 think these two strings are equal? - javascript

I have an event handler that will remove an element from a list of the corresponding checkbox is unchecked. In the handler for the click event for the checkbox, first I copy the value of the label for that checkbox:
var label = $(this).next().html();
Then, I iterate over the list items and compare each of them to that label:
$("#sortable li").each(function() {
if ($(this).html() === label) {
$(this).remove();
}
});
In Internet Explorer 8 and in Firefox, this works exactly as I'd expect. In Internet Explorer 7, it does not. The condition in the "if" statement is never true. What am I missing here?
By request, the strings being compared are, "Charge" and "Charge" in one case.

Try alert(label) and alert($(this).html()) to see exactly what's being compared.
I'm not seeing any reason to use strict comparison (===), and you could conceivably benefit from using ordinary comparison (==).
As a method of doing what you're saying you want to do, this all seems pretty crazy. I'd always recommend identifying corresponding DOM elements by something more designed-for-the-purpose than their HTML contents, such as an ID.

Why don't you use the Script Debugger and see exactly why that comparison is false? Just set a breakpoint in the if and watch the variables.
The IE8 internal script debugger will help you, just switch to compatibility mode to run the script in the IE7 javascript runtime

Have you tried debugging it? Use alert to see what the two values hold, check that the function is actually called in IE7 and check that they have the same type.

Not an answer to your direct question, but here's another method that uses jQuery's data method to set and read a flag directly on the element:
$(this).next().data("toRemove", true);
//...
$("#sortable li").each(function() {
if ($(this).data("toRemove")) {
$(this).remove();
}
});
Of course, if you were manipulating label at any point then this wouldn't be what you want. I just mention this because .data() is a very useful jQuery feature that I haven't heard much about. I didn't even know about it until a week ago.

Related

jquery selectors with option (select) throwing error

I noticed this after a user reported the behavior since it was working fine on Chrome, Firefox and IE8+. However in IE7 the following selectors:
$('#parentjobs option')
$('#parentjobs option:not(:contains("new"))')
throw this error:
Error: Unable to get value of the property '0': object is null or undefined
Which points to line 5126 on jquery-1.8.3:
context = Expr.find["ID"]( token.matches[0].replace( rbackslash, "" ), context, xml )[0];
I don't have IE7 installed but I can reproduce the error when I switch the document mode and browser mode to IE7 on the IE debug page (F12)
Any ideas what might be going wrong?
I'm not sure what the problem is, but something that might make it work cross-browser, in a different way, is to use filter:
$("#parentjobs").find("option").filter(function () {
return $(this).text().indexOf("new") === -1;
});
Which says "only include the <option> elements that don't contain the text 'new'"...and should do the same as your original selector.
filter includes/excludes elements based on the result of the return. If true is returned, the element is left in the list. If false is returned, the element is removed from the list.
Using .text() is the same as what :contains() looks at, and === -1 means the text isn't found.
It might just be me, but I like to be more explicit with selecting elements, staying away from long selectors (especially pseudo selectors) and using jQuery methods instead. Although this might make your selections a little slower (not allowing jQuery to optimize native browser methods), it's easier to debug and looks cleaner to me than a big string (and hopefully works for you in all browsers).
Reference:
http://api.jquery.com/filter/
Found out that in IE7 and below getElementById is not case-sensitive which was the cause of my problem.
http://msdn.microsoft.com/en-us/library/ie/ms536437(v=vs.85).aspx
In IE8 Standards mode, getElementById performs a case-sensitive match on theID attribute only.
In IE7 Standards mode and previous modes, this method performs a case-insensitive match on both the ID and NAME attributes, which might produce unexpected results.

What does the jQuery function $('#myelement').is('*') do?

What does the following code do:
$('#myelement').is('*')
What does the asterisk signify? Since there is only one element, #myelement, I can't understand the point of using is(), which checks if an element matches a set of elements?
This is some seriously existential JavaScript.
$('#myelement').is('*')
It will fail whenever #myelement doesn't exist, and return true otherwise.
Basically check to see if an element exists or not. Not the best method...
is checks the element fits the criteria. In this case, "*" means all elements.
So, it simply returns true if the previous selector returns anything.
Take a look here for an example: http://jsfiddle.net/b7DwB/
http://api.jquery.com/is/
Pretty much what it does well from my understanding of it at least, and how I tend to use it. Is return true or false on whatever its called on.
Example I have a checkbox that I want to make sure is checked before I submit my form via AJAX I would do something like
if( $('input#tosCheck').is(':checked') ){
/*its checked submit form*/
}else{
alert('Error');
}
All in all the link to the API from jQuery better describes it then I ever could, but I wanted to at least share an example of use to help you gauge some idea.
Can't say I've ever seen that jQuery code used before, but it seems to be a poor way of checking for the existence of an element. Since * is the universal selector, the expression in question will always return true if #myelement exists, otherwise it will return false.
I say this is a "poor" way of checking the existence of an element because you can simply check the length of the jQuery object instead:
$('#myelement').length > 0
I haven't done any testing, but I assume the above is faster since it doesn't have the overhead of the is() function call.

What happens if a JavaScript event-listener is called and target element is missing?

For the moment, we're loading site-wide event-listeners from a single common.js file for a Rails project. We're aware of (most of) the trade-offs involved there, and are just trying to mitigate them. Once our basic architecture takes hold, we may move them off to separate files by controller or by view.
For the moment, the quick question is how we can activate them only when necessary, which begs the mangled, pseudo-zen question:
if an event-listener is declared in a forest when nobody is around to hear it, does it still make a sound?
In other words, if one declares a basic listener (i.e., nothing persistent like .live() or .delegate()) in the JavaScript for a given page, and the target element is not actually present on that given page, does anything really happen, other than the few cycles devoted to evaluating it and checking the DOM for the element? Is it active in memory, looking for that element? Something else? It never seems to throw an error, which is interesting, given that in other contexts a call like that would generate a null/nil/invalid type of error.
For instance:
$(document).ready(function () {
$('#element').bind('blur keyup', function);
}
Assume that #element isn't present. Does anything really happen? Moreover is it any better to wrap it in a pre-filter like:
$(document).ready(function () {
if ($('#element')) {
$('#element').bind('blur keyup', function);
}
Or, are the .js interpreters in the browsers smart enough to simply ignore a basic listener declared on an element that's not present at $(document).ready? Should we just declare the initial, simple form above, and leave it at that, or will checking for the element first somehow save us a few precious resources and/or avoid some hidden errors we're not seeing? Or is there another angle I'm missing?
JQuery was designed to work with 0+ selected elements.
If no elements were selected, nothing will happen.
Note that you will never get null when using jQuery selector. For example:
$('#IDontExist') // != null
$('#IDontExist').length === 0 // true (it's ajQuery object with
// zero selected elements).
The docs says:
If no elements match the provided selector, the new jQuery object is "empty"; that is, it contains no elements and has .length property of 0.
$('#element') if results into empty set then jQuery will not do anything.
Since jQuery always returns an object we can can call the methods on an empty set also but internally it will do the checking before applying it's logic.
Even if you want to check if the element exists before attaching the event handler you can use length property of jQuery object.
if ($('#element').length > 0) {
$('#element').bind('blur keyup', function);
}

Setting a property via property or setAttribute

Is one of these more preferable than the other? Why? How about performance--if these are being called thousands of times?
A) element.setAttribute("disabled", true);
B) element.disabled = true;
They both seem to disable an input[text] element in FF 4.
In general…
Use properties. For a long time (until version 7 or 8 IIRC) Internet Explorer had a seriously broken implementation of setAttribute that would set the property not the attribute (the classic point of failure was class since there is no class property (it is className).
In this case in particular… element.setAttribute("disabled", true); is wrong. It should be element.setAttribute("disabled", "disabled");
element.setAttribute("disabled", some_bool) doesn't work like you'd think it will. In particular, standardswise, disabled is what's known as a boolean attribute; its very presence, regardless of its value, makes it true. disabled="", disabled="disabled", disabled="true" and even disabled="false"(!!!) all mean the same thing in most browsers. (Although the last two are actually invalid HTML, most browsers will consider them equivalent to disabled="disabled" for truth purposes. Including every one of the Big Four.) You set a boolean attribute to true by setting a value -- any value, even if it's falsy -- and you set it to false by removing the attribute entirely.
If you care about the actual string value of the attribute (which in this case you shouldn't), and particularly if the attribute isn't already exposed via the DOM (that is, it doesn't have a corresponding property), then use (get/set)Attribute. In most cases (particularly if you care about how it affects the element, like in this case where you're trying to disable an element), use the DOM property.
IE needs some attributes to be set with setAttribute, but not all. I don't have a list though, you just have to check if it works or not. Also, using setAttribute will put the attribute in the DOM, so it can be shown when doing view source.
Only one tip: element.setAttribute('class',xxx) doesnt works in some versions of IE.
Prefer element.className = xxx instead

jQuery: is element.click(func) or element.attr('onclick','func()') more efficient?

I'm populating a list by cloning elements into it. Then I change attrs to make each item unique. They need to call a function on click, so I'm wondering if it's more efficient to use new_element.click(func); or new_element.attr('onlick','func();');
new_element.attr('onclick','func();');
Is:
inefficient (needlessly creating a new inline function from a string, that does nothing except call func and lose the this reference);
aggravating to put any complex code in, since it all has to be JS string escaped;
broken in IE, due to bugs in setAttribute.
Avoid. click()/bind('click') is there for a reason.
onclick has a number of limitations, including cluttering the DOM and only allowing one function at a time. So you should use click. See Quirks Mode for more information.
Directly referencing the function will be more efficient than having to interpret a string.
The lowest touch way of doing this, however, is this way:
$(links_selector).live('click', func);
links_selector will presumably be something like ul.listClass a.actionClass. This will not require anything to be done when new list elements get added.
Since you are using jQuery then make it this way
new_element.click(function(){
// your code
});
or you can bind the click event handler like
new_element.bind("click", function(){
// your code
});
Any difference in performance between the two is most likely going to be negligible. You should use the one that reads better, and that's element.click. (Plus, onclick has many disadvantages, as #Matthew Flaschen mentioned.)

Categories

Resources