ID Parsing then using as Selector - javascript

So I have this funny little problem, where I want to parse the IDs of images. Nothing too complicated... but weirdly enough, my code doesn't seem to work properly. It's weirdddd. Could any care to explain this? I feel blind for not being able to see the error myself.
Here's a snippet of the relevant code that fails to work:
//Toggling images using img-index variable.
img-index = 0;
img-src[0] = $("#ppsfb").attr("id");
img-src[1] = $("#gty").attr("id");
$("#cycle").click(function(){
//Since img-index is just a counter.
if (img-index < 2){
img-index = img-index + 1;
} else {img-index = 0;}
$(img-src[img-index]).fadeIn(1000);
});

img-src is not a valid identifier in JavaScript. That's likely why this is failing.
Check out this fiddle and note the Unexpected token - error

img-index is not a valid variable name in JavaScript, you probably want to use img_index or imgIndex. Also, calling attr('id') on something that comes from an ID selector is pointless, $("#ppsfb").attr("id") is 'ppsfb' or nothing. You're probably better off storing whole jQuery objects in img_src too, your $(img-src[img-index]) wouldn't do what you wanted it to do even after fixing the naming problem. Furthermore, you probably want to hide or fadeout the current image before showing the new one.
img_index = 0;
img_src[0] = $('#ppsfb');
img_src[1] = $('#gty');
$("#cycle").click(function(){
img_src[img_index].hide() // Or .fadeOut or ...
if(img_index < 2)
img_index = img_index + 1;
else
img_index = 0;
img_src[img_index].fadeIn(1000);
});
Presumably you have the positioning, stacking, etc. already sorted out.

Related

Trying to make sense of "this" in my javascript code (one thing works, the other doesn't)

I've been trying to learn javascript by refactoring some Jquery examples in a book into javascript. In the following code I add a click listener to a tab and make it change to active when the user clicks on the tab.
var tabs = document.querySelectorAll(".tabs a span");
var content = document.querySelectorAll("main .content li");
for (var tabNumber = 0; tabNumber <= 2; tabNumber++) {
tabs[tabNumber].addEventListener("click", function (event) {
for (var i = 0; i < tabs.length; i++) {
tabs[i].classList.remove("active");
}
tabs[tabNumber].classList.add("active");
for (var i = 0; i < content.length; i++) {
content[i].innerHTML = "";
}
event.preventDefault();
});
}
This returns an undefined error when I run it. However, I tried replacing tabs[tabNumber].classList.add("active") with this.classList.add("active") and it worked.
Why doesn't the previous code work? As far as I can see they are referring to the same thing, and tabs[tabNumber] should work since at that point in the code it is tabs[0].
If use this, I think it's better and a more polished solution. If you still want to use tabNumber, it's probably evaluating to 3 in every click callback, because it's the number after the last iteration, and you don't have a tabs[3] position.
So, you just have to make a closure of the tabNumber variable.
I guess other answers told you why tabs[tabNumber] does not work (because it comes from the score of the for loop and so, is always equal to the greater value of tabNumber).
That's why I would recommend using a .forEach loop. Careful though because it doesn't work on arrays of DOM nodes produced by document.querySelectorAll(), but you can use:
// ES6
Array.from(document.querySelectorAll('...'))
// ES5
[].slice.call(document.querySelectorAll('...'))
Anyway, I made a simplified working demo of your code.
Note that I save the currently active tab in a variable, to prevent another for loop. You could also do:
document.querySelector('.active').classList.remove('active')
But I like to reduce the amount of DOM reading.
Good luck for your apprentissage, re-writing some jQuery code into Vanilla JS seems like a good method, and you might acquire a far better comprehension of JavaScript.

jQuery find - What order does it return elements in?

I have been using jQuery's find method and it's been very useful.
However, I came across an example where the find seemed to be duplicating things and not returning elements in the order they appeared in the document. (I'm not sure if find is supposed to do this - I doubt it).
However, it shouldn't have duplicates in the elements it finds and show the wrong order, surely?
Full example can be found here: jsFiddle - Notice how span[9] and span[10] are in the wrong order and duplicated.
Why is this the case?
Update
Updated so that output is written to document, please use new link above.
.find() returns elements in document order. More info here: http://docs.jquery.com/Release%3ajQuery_1.3.2
I think the anomaly has something to do with the wildcard selectors. Are those necessary? Removing them seems to resolve the issue.
you add unused * in your code, replace this find with your code:
$('#div1').find("*[class=w_line_" + i + "]").each(function () {
and have this, have good time;
I can´t find anything strange with the order.
$(document).ready(function() {
for (var i = 1; i <= 10; i++) {
console.log(i);
$('#div1').find("*[class*=w_line_" + i + "]").each(function() {
console.log(i, $(this));
});
}
});
This selector seems to return the elements in the same order as yours and I can´t see any duplicates.
$('#div1 *[class*=w_line_' + i + ']')

IE Issue with Javascript Regex replacement

r = r.replace(/<TR><TD><\/TD><\/TR>/gi, rider_html);
...does not work in IE but works in all other browsers.
Any ideas or alternatives?
I've come to the conclusion that the variable r must not have the value in it you expect because the regex replacement should work fine if there is actually a match. You can see in this jsFiddle that the replace works fine if "r" actually has a match in it.
This is the code from fiddle and it shows the proper replacement in IE.
var r = "aa<TR><TD></TD></TR>bb";
var rider_html = " foo ";
r = r.replace(/<TR><TD><\/TD><\/TR>/gi, rider_html);
alert(r);
So, we can't really go further to diagnose without knowing what the value of "r" is and where it came from or knowing something more specific about the version of IE that you're running in (in which case you can just try the fiddle in that version yourself).
If r came from the HTML of the document, then string matching on it is a bad thing because IE does not keep the original HTML around. Instead it reconstitutes it when needed from the parsed page and it puts some things in different order (like attributes), different or no quotes around attributes, different capitalization, different spacing, etc...
You could do something like this:
var rows = document.getElementsByTagName('tr');
for (var i = 0; i < rows.length; i++) {
var children = rows[i].children;
if (children.length === 1 && children[0].nodeName.toLowerCase() === 'td') {
children[0].innerHTML = someHTMLdata
}
}
Note that this sets the value of the table cell, rather than replacing the whole row. If you want to do something other than this, you'll have to use DOM methods rather than innerHTML and specify exactly what you actually want.

Javascript/jQuery function yields undefined in <IE8

A short while back I asked a question here about how I could calculate when a heading was longer than one line within a given container, and subsequently wrap each of these lines in a <span>:
Use Javascript/jQuery to determine where a heading breaks to the next line?
I chose an answer which worked great for me, at least until I checked in IE7 and IE6, in which all the headings handled by this script rendered as
"undefinedundefinedundefinedundefinedundefinedundefined[...]"
on the page. As I'm not really a JavaScript person (that's why I asked such a question in the first place), it's really tough for me to figure out where the problem is. I assumed an undefined variable or something, but I just can't seem to grasp it.
Can anyone help?
I'll repeat the code here, but please refer to the link above for context:
$(function(){
$h = $('.fixed').find('h3');
$h.each(function(i,e){
var txt = $(e).text();
$th = $('<h3 />').prependTo($(e).parent());
var lh = $(e).text('X').height();
$(e).text('');
while (txt.length > 0) {
$th.text($th.text() + txt[0]);
txt = txt.slice(1);
if (($th.height() > lh) || (txt.length <= 0)) {
var shc = $th.text().split(' ');
var ph = shc.slice(0,-1).join(' ')+' ';
if (txt.length <= 0) { ph += shc.pop(); }
$('<span />').text(ph).appendTo($(e));
$th.text(shc.pop());
}
}
$th.remove();
})
});
You need to change
$th.text($th.text() + txt[0]);
to be
$th.text($th.text() + txt.charAt(0));
IE<8 doesn't accept string positions through array indexes ;)
The styling doesn't work, but that'll be a CSS issue which I couldn't fix before leaving. But everything is wrapped in spans :)
Nothing jumps out at me. But, since you mentioned in your comment to your question that you see "undefined" in Firebug, I would start there. Even though those browsers are failing gracefully, the fact that you see undefined there is your first hint to finding the problem for the harder-to-diagnose IE6/7. I would use Firebug and either breakpoint in the function, or use some console.log() calls to document what the values that you are working with are each step of the way. Once you start seeing undefined... you have likely found your problem.

Removing list elements with Greasemonkey

A blog I read has some annoying commenters. I thought I would try my hand at Greasemonkey to turn them off.
The basic structure of the HTML is simple - a comment looks something like this:
<li>
<cite>user name ...</cite>
comment text
</li>
So with that in mind, I bashed my head against the keyboard for a while until this dropped out:
var killlist = /user1|user2/;
var comments = document.getElementsByTagName('li');
if (comments.length) {
for ( var i = 0; i < comments.length; i ++ ) {
var comment = comments[i];
var cites = comment.getElementsByTagName('cite');
if (cites.length) {
var cite = cites[0];
var title = cite.textContent;
if (killlist.test(title)) {
comment.parentNode.removeChild(comment);
}
}
}
}
window.alert('Done!')
(the window.alert is just so I know if the script runs to completion)
This mostly works. e.g. on one test page, it removed 13 of 16 posts by one of the users. I tried replacing the removeChild line with this:
comment.style.visibility = 'hidden';
That appears to get everything, but at the expense of leaving great empty spaces where the comments would have been.
I'm a complete javascript newbie, so can anyone see anything obvious I'm doing wrong?
The behavior you're seeing is due to comments being a live NodeList. As you remove elements referenced by comments from the DOM, comments is mutated (and its length updated) and your loop goes out the window.
You can loop in reverse order as #Pat suggested, or "unhook" the NodeList from the DOM with a copy operation first:
var comments = Array.slice(document.getElementsByTagName('li'));
Then proceed as before.
You should be able to fix it by reversing the order of your for loop and deleting elements from the end of the comments array first:
for ( var i = comments.length - 1; i >= 0; i-- )

Categories

Resources