PDA

View Full Version : Looping Sequential function in javascript?



Falkon303
02-22-2009, 08:45 AM
Ok,

So I have 3 elements...

with the ids = "c1","c2", and "c3".


What I am trying to do, is create a javascript function that loops through each element sequentially.

I don't mean a "for i", type loop, but I mean if I click a button, I get an alert that says "c1 = first element", but if I click that same button 15 minutes later, it says "c2 - second element", but after "c3" is alerted, it loops back to "c1".

Similar to a carousel slideshow that loops.......

http://sorgalla.com/projects/jcarousel/examples/special_circular.html

but with elements...

hmm...

I'll try some more and see if I can get this.



<script>
function getcrawling()
{
// Begin crawling element
divcrawl = document.getElementById('cont');
acrawl = divcrawl.getElementsByTagName("a");
var a_array = new Array();
for (j=0;j<acrawl.length;j++)
{
a_array[j] = acrawl[j].id;
splitstring = document.getElementById(acrawl[j].id).id.split("-");
if (splitstring[1] == 'one'){document.getElementById(acrawl[j].id).id = splitstring[0] + '-two';}
else if (splitstring[1] == 'two'){document.getElementById(acrawl[j].id).id = splitstring[0] + '-three';}
else if (splitstring[1] == 'three'){document.getElementById(acrawl[j].id).id = splitstring[0] + '-four';}
else if (splitstring[1] == 'four'){document.getElementById(acrawl[j].id).id = splitstring[0] + '-one';}
else {document.getElementById(acrawl[j].id).id = splitstring[0] + '-two';}
}
alert(a_array);
}
</script>

<div id="cont" name="cont">
<a id="345" >test</a><br />
<a id="335" >test</a><br />
<a id="342" >test</a><br />
<a id="335" >test</a><br />
<a id="325" >test</a><br />
<a id="322" >test</a><br />
<a id="315" >test</a><br />
<a id="385" >test</a><br />
<a id="382" >test</a><br />
</div>
<br><br>
<a onclick="getcrawling();">test crawl</a>


Ok, So I got it working using a loop based crawler. This is ugly, but I am still getting used to decoding the moderators heiroglyphs.

Twey
02-22-2009, 12:38 PM
<script type="text/javascript">
var nextEl = (function(n) {
var ordinals = {
'1' : 'first',
'2' : 'second',
'3' : 'third'
};

var i = 1;

function nextEl() {
alert("c" + i + " - " + ordinals[i] + " element");
i = ((i + 1) % n) + 1;
}

return nextEl;
})(3);
</script>

<input type="button" onclick="nextEl();">What you've got is not a 'crawler' of any kind — that is a misnomer. Additionally, why are all your variables global? Not to mention that your HTML is entirely invalid.

Falkon303
02-22-2009, 04:42 PM
I would like to know why global variables are bad.

I appreciate the notification that my html is invalid, but when I stated already that is was (I said "This is ugly."), that doesn't make much sense to restate the obvious.

Twey
02-22-2009, 06:41 PM
I appreciate the notification that my html is invalid, but when I stated already that is was (I said "This is ugly."), that doesn't make much sense to restate the obvious.There's a difference between 'ugly' (works, but in a nasty way — e.g. using a whole bunch of global variables) and 'broken' (isn't even real HTML). :)

Rather than write a whole essay on global variables and why they're bad, I'll point you to this one: http://c2.com/cgi/wiki?GlobalVariablesAreBad

Alternatives in JS include using closures (as above) or sticking them in namespacing objects (or a combination of both).

There are some more examples of efficient management of scope in in JS in this thread (http://dynamicdrive.com/forums/showthread.php?t=41961). My last post in that thread deals specifically with the issues of globals, too.

Falkon303
02-23-2009, 03:10 AM
I appreciate your response. If you could let me know what exactly is broken in my html in particular, it would help me to better understand. I realize I didn't include my dtd, head tags, etc....


What are Local and Global variables?
When a function is defined certain variables used for storing values are incorporated inside the function. These variables are found and used only inside these functions. Since functions are separate from the main code, it's advisable to use variables that are initialized only when a function is called and die when the execution comes out of the function. Variables that exist only inside a function are called Local variables. They have no presence outside the function.


So, if I use "function(value);" rather than attaching a function handler onto the element itself, that is an example of using globals vs locals?

Twey
02-23-2009, 04:53 PM
I realize I didn't include my dtd, head tags, etc....Well, that certainly does make it rather broken, but I did assume it to be a code fragment :)

<script> requires an attribute type="text/javascript"; <br /> has dodgy pseudo-XHTML syntax, which isn't used on your later <br>s, and your use of <br>s here is presentational rather than semantic, so it shouldn't really happen. Try wrapping your links in some other element. An <ul> would seem to suit this situation.

If you have any doubts about your HTML in future, the validator (http://validator.w3.org/) can usually sort them out (but it will miss some things; it can't tell the difference between semantic and presentational use of an element, for example). It can even handle code snippets. You should be aiming at HTML 4.01 Strict.

Falkon303
02-23-2009, 07:07 PM
hahahah! You know it's funny. Every time I code I attach the type="text/javascript", but this was after 1 day w/no sleep (too much coffee) and I was exhausted.

as for the <br /> dreamweaver generated those entirely on her own. My only excuse there is being too lazy to battle a program. Thanx for the tips though.

Twey
02-23-2009, 07:59 PM
Oh, I missed responding to this:


So, if I use "function(value);" rather than attaching a function handler onto the element itself, that is an example of using globals vs locals?No. You're not creating any variable there at all.


as for the <br /> dreamweaver generated those entirely on her own. My only excuse there is being too lazy to battle a program.Maybe it's time you got an editor that you don't have to fight in order to get what you want, then. :)

Falkon303
02-24-2009, 08:16 PM
<script type="text/javascript">
var nextEl = (function(n) {
var ordinals = {
'1' : 'first',
'2' : 'second',
'3' : 'third'
};

var i = 1;

function nextEl() {
alert("c" + i + " - " + ordinals[i] + " element");
i = ((i + 1) % n) + 1;
}

return nextEl;
})(3);
</script>

<input type="button" onclick="nextEl();">What you've got is not a 'crawler' of any kind — that is a misnomer. Additionally, why are all your variables global? Not to mention that your HTML is entirely invalid.

Your script subtracts instead of increments, but that's ok. Same loop really. Thanx Twey, I'll study this. How would I make this go to 5 or 6?

Update:

I made some modifications to your script to set a limit number using an if statement, this increments instead of decrements(?).


<script type="text/javascript">
var nextEl = (function(n) {
var ordinals = {
'1' : 'first',
'2' : 'second',
'3' : 'third',
'4' : 'fourth'
};
var i = 1;
function nextEl() {
alert("c" + i + " - " + ordinals[i] + " element");
if (i == '4')
{i = 1;} else {i = (i + 1);}
}
return nextEl;
})(3);
</script>
<input type="button" onClick="nextEl();">

I think it would also be cool to be able to set the limit to the length of an element in a page. For example if there are 54 "a" elements, this function could go through each one by one, and start at the beginning when it reached the end. Thanx much for help on this Twey.

is there anyway to use (if ordinals[i] == undefined), to represent the end of the list. This would be perfect for having an unlimited amount of items in the array, but the script itself would know the end.
*grovels at your mod feet*

Twey
02-24-2009, 09:30 PM
Ah, yes, adding 1 to it throws it right off, since it ends up on 3 which should never happen. That'll teach me to show off by breaking KISS :)
<script type="text/javascript">
var nextEl = (function(n) {
var ordinals = {
'1' : 'first',
'2' : 'second',
'3' : 'third'
};

var i = 1;

function nextEl() {
alert("c" + i + " - " + ordinals[i] + " element");
i = i > n ? 1 : i + 1;
}

return nextEl;
})(3);
</script>You can make it do more by increasing the 3 at the bottom.

Anyway, yes, the maths I used to try to get it to cycle isn't really important (maths has never been my strong point :p) and you can do it with an if as you attempted (the above being a condensed, less redundant version of such):


function nextEl() {
alert("c" + i + " - " + ordinals[i] + " element");

if (i > n)
i = 1
else
++i;
}

The strange behaviour you encountered was because you wrapped your numbers in quotation marks, making them into strings. 1 + 1 === 2, but '1' + '1' === '11'.

Falkon303
02-24-2009, 10:00 PM
Ah, yes, adding 1 to it throws it right off, since it ends up on 3 which should never happen. That'll teach me to show off by breaking KISS :)
<script type="text/javascript">
var nextEl = (function(n) {
var ordinals = {
'1' : 'first',
'2' : 'second',
'3' : 'third'
};

var i = 1;

function nextEl() {
alert("c" + i + " - " + ordinals[i] + " element");
i = i > n ? 1 : i + 1;
}

return nextEl;
})(3);
</script>You can make it do more by increasing the 3 at the bottom.

Anyway, yes, the maths I used to try to get it to cycle isn't really important (maths has never been my strong point :p) and you can do it with an if as you attempted (the above being a condensed, less redundant version of such):


function nextEl() {
alert("c" + i + " - " + ordinals[i] + " element");

if (i > n)
i = 1
else
++i;
}

The strange behaviour you encountered was because you wrapped your numbers in quotation marks, making them into strings. 1 + 1 === 2, but '1' + '1' === '11'.


Thanx Twey, you are absolutely correct. The script is fixed now, I found the same thing, wrapping the '1', it just kept saying 'item 111111', and I about laughed when I figured out why. The version with the if statement works well enough, but I was curious if you could recall the method of finding if an element exists or not....

I was thinking something along the lines of


if (ordinal[i] == undefined) (i = 1;} else {i = (i+1);}

yet this didn't seem to work..... any thoughts/ideas?

Update - This works perfect!! I can add as many ordinals as I like! :) Thanx much for the insight on this Twey!



<script type="text/javascript">
var nextEl = (function(n) {
var ordinals = {
'1' : 'first',
'2' : 'second',
'3' : 'third',
'4' : 'fourth',
'5' : 'fifth',
'6' : 'sixth',
'7' : 'seventh',
'8' : 'eighth'
};
var i = 0;
function nextEl() {
if (ordinals[i + 1] != null)
{i = (i + 1)} else {i=1;};
alert("c" + i + " - " + ordinals[i] + " element");
}
return nextEl;
})(3);
</script>

<input type="button" onClick="nextEl();">


So I gather this is the same thing?



function nextEl() {
alert("c" + i + " - " + ordinals[i] + " element");

if (i > n)
i = 1
else
++i;
}

Twey
02-24-2009, 11:15 PM
Your indentation is kind of wacky. I suggest not using tabs — they are rarely rendered the same way across different systems, and can completely mess up readability. Blocks should be separated from the surrounding code by at least one blank line.

Yes, you can generalise it to as many ordinals as you like simply by checking that they're all there:
<script type="text/javascript">
var nextEl = (function() {
var ordinals = ['zeroth',
'first',
'second',
'third',
'fourth',
'fifth'];

var i = 1;

function nextEl() {
alert("c" + i + " - " + ordinals[i] + " element");
i = ordinals[i + 1] ? i + 1 : 1;
}

return nextEl;
})();
</script>

Falkon303
02-25-2009, 01:08 AM
Your indentation is kind of wacky. I suggest not using tabs — they are rarely rendered the same way across different systems, and can completely mess up readability. Blocks should be separated from the surrounding code by at least one blank line.

Yes, you can generalise it to as many ordinals as you like simply by checking that they're all there:
<script type="text/javascript">
var nextEl = (function() {
var ordinals = ['zeroth',
'first',
'second',
'third',
'fourth',
'fifth'];
};

var i = 1;

function nextEl() {
alert("c" + i + " - " + ordinals[i] + " element");
i = ordinals[i + 1] ? i + 1 : 1;
}

return nextEl;
})();
</script>

That code isn't working for me... I believe the ")" after setting the ordinals (after the "}") is absent.

After setting the ")", when I try it with the button calling nextEl(), I recieve an object expected error. I am anxious to try this though.

Also: I'd love to write these variables to the inside of an element (without using innerhtml!), any assistance with this is appreciated.

I am not looking to create new elements, but rather write to a <span> element with the id&name of "mojo".

- Ben

Twey
02-25-2009, 01:30 AM
No, it actually shouldn't be there at all, sorry. I switched to an array since this was all looking very numerical. :)
Also: I'd love to write these variables to the inside of an element (without using innerhtml!), any assistance with this is appreciated.

I am not looking to create new elements, but rather write to a <span> element with the id&name of "mojo".If it's just text, and the 'mojo' element already has a text node inside it, you can just do document.getElementById("mojo").firstChild.nodeValue = "new value";; otherwise, you'll need to create the structure appropriately. The code for this can get ugly fast, so it's usually wise to abstract it out a little; http://dynamicdrive.com/forums/showpost.php?p=183756 demonstrates one way of doing so.

Falkon303
02-25-2009, 02:45 AM
No, it actually shouldn't be there at all, sorry. I switched to an array since this was all looking very numerical. :)If it's just text, and the 'mojo' element already has a text node inside it, you can just do document.getElementById("mojo").firstChild.nodeValue = "new value";; otherwise, you'll need to create the structure appropriately. The code for this can get ugly fast, so it's usually wise to abstract it out a little; http://dynamicdrive.com/forums/showpost.php?p=183756 demonstrates one way of doing so.

Am I to understand that if I wish to create, say an img, I need to use the document.createElement('img') method?

As far as I can tell, this is the way DOM works. There doesn't seem to be an equivalent to "innerHTML", which brings up an interesting point.

Perhaps a function that creates a subnode with html could be created to replace the use of innerhtml, with the usage of - "sethtml(elmntid, updatevalue)".

I haven't figured out how to create nodes and such, but I am well on my way!

My first task will be to create a function library that can replace things such as innerhtml..... I know there are a few, but their usage is odd sometimes. Also, I am not even sure of things like "document.getElementById('franky').style.display = 'none';" I wish there was a list of all the horribly invalid non-DOM aspects of Jezebelian javascript.

I made a slideshow script out of it for fun.

http://www.megafileupload.com/en/file/85547/slideshow-zip.html

Feel free to check it out. I'd love to know how I did on it

here's the script (which I edited to make the array look better than the zip I uploaded.....)-


<script type="text/javascript">
imagedir = 'images/';
var nextEl = (function(n) {
var ordinals = {
'1' : 'fr3r342r43.jpg',
'2' : 'it9409rew4e.jpg',
'3' : 'r4i90r43r34.jpg',
'4' : 'r43u298ew.jpg',
'5' : 'r432r234r.jpg',
'6' : 'r432r432r4.jpg',
'7' : 'r432r432r342.jpg',
'8' : 'ru342898re2.jpg'
};
var i = 0;
function nextEl(value) {
if (value == "forward")
{if (ordinals[i + 1] != null) {i = (i + 1)} else {i=1;};}
else
{if (ordinals[i - 1] != null) {i = (i - 1)} else {i=8;};}
document.getElementById("mojo").firstChild.src = imagedir + ordinals[i];}
return nextEl;
})();
</script>
<input type="button" onClick="nextEl('back');" value="prev">
<input type="button" onClick="nextEl('forward');" value="next">
<br />
<span id="mojo" name="mojo"><img src="images/fr3r342r43.jpg" /></span>


Now what I should have done for the "{if (ordinals[i - 1] != null) {i = (i - 1)} else {i=8;};}" area, was used ordinals.length instead of "8" (correct?).

Packaged with php, this could be a nice slideshow script. You'd just need to use the "get all images from dir" of php.

Twey
02-25-2009, 12:30 PM
You could be more flexible by allowing a custom step:
<script type="text/javascript">
var nextEl = (function(imgdir) {
var i = 0,
ordinals = ['fr3r342r43.jpg',
'it9409rew4e.jpg',
'r4i90r43r34.jpg',
'r43u298ew.jpg',
'r432r234r.jpg',
'r432r432r4.jpg',
'r432r432r342.jpg',
'ru342898re2.jpg'];

function nextEl(step) {
step = step || 1;

i = ordinals[i + step] ? i + step : 0;

document.getElementById("mojo").firstChild.src = imagedir + "/" + ordinals[i];
}

return nextEl;
})('images');
</script>

<input type="button" onclick="nextEl(-1);" value="prev">
<input type="button" onclick="nextEl();" value="next">

<span id="mojo">
<img src="images/fr3r342r43.jpg" alt="Gallery Image">
</span>Note that: since we're using purely numerical values now, we're using an array (and have reverted to the more natural zero-index); we're passing imgdir in as a parameter, rather than just chucking it in the global namespace; we've removed that presentational <br>, and the weird pseudo-XHTML tag endings (read Beware of XHTML (http://www.webdevout.net/articles/beware-of-xhtml)); and we've removed the name attribute from the <span>, where it's no longer valid (and anyway quite useless).

Falkon303
02-25-2009, 05:48 PM
You could be more flexible by allowing a custom step:
<script type="text/javascript">
var nextEl = (function(imgdir) {
var i = 0,
ordinals = ['fr3r342r43.jpg',
'it9409rew4e.jpg',
'r4i90r43r34.jpg',
'r43u298ew.jpg',
'r432r234r.jpg',
'r432r432r4.jpg',
'r432r432r342.jpg',
'ru342898re2.jpg'];

function nextEl(step) {
step = step || 1;

i = ordinals[i + step] ? i + step : 0;

document.getElementById("mojo").firstChild.src = imagedir + "/" + ordinals[i];
}

return nextEl;
})('images');
</script>

<input type="button" onclick="nextEl(-1);" value="prev">
<input type="button" onclick="nextEl();" value="next">

<span id="mojo">
<img src="images/fr3r342r43.jpg" alt="Gallery Image">
</span>Note that: since we're using purely numerical values now, we're using an array (and have reverted to the more natural zero-index); we're passing imgdir in as a parameter, rather than just chucking it in the global namespace; we've removed that presentational <br>, and the weird pseudo-XHTML tag endings (read Beware of XHTML (http://www.webdevout.net/articles/beware-of-xhtml)); and we've removed the name attribute from the <span>, where it's no longer valid (and anyway quite useless).

Wow. That has to be one of the shortest slideshow scripts I have ever seen.

I was trying to use "document.getElementById('image').style.left", and slowly push the image to the left/right per picture (ie: a carousel slideshow).

I believe the correct usage is "offsetLeft', but I am not familiar with moving elements yet. Especially slowly so the user can see it (ie: var speed = 1-10).

That will probably be my next post.

Thanx much.