Forum Moderators: open
I only know enough about JavaScript to be dangerous, so I'd appreciate a little help.
I set up an html form page with multiple parts entry divs occupying the same area. I want to be able to sequentually show one parts div at a time while keeping the others hidden by clicking on just two buttons, "Previous Part" and "Next Part".
I created (more like hacked from existing) two javascripts. One to handle the initial page load and one to handle the prev/next part buttons.
The "hideallexcept" function works great for initial page load. The problem is that the "shownextdiv" function index variable is not being increased/decreased most likely because i have the syntax wrong when executing the "shownextdiv" function WITH i++ OR i-- in the onclick= of the button div or i have it all wrong.
The form basically looks like the following...
<! hideallexcept handles initial page load of parts divs.
function hideallexcept(id) {
for (var i = 0; i < div.length; i++) {
var layer = document.getElementById(div[i]);
if (id != div[i]) {
layer.style.display = "none";
}else{
layer.style.display = "block";
}
}
}
<! the following array and variable works with the shownextdiv function.
div = new Array()
div[0] = "partdiv1"
div[1] = "partdiv2"
.
.
.
div[9] = "partdiv10"
var i = 0
<! hide previous and/or next div, show current div.
function shownextdiv(idx) {
if ( idx > 0 and idx < 9 ) {
document.getElementById(div[idx--]).style.display = "none";
document.getElementById(div[idx]).style.display = "block";
document.getElementById(div[idx++]).style.display = "none";
}
if ( idx = 0 ) {
document.getElementById(div[idx]).style.display = "block";
document.getElementById(div[idx++]).style.display = "none";
}
if ( idx = 9 ) {
document.getElementById(div[idx--]).style.display = "none";
document.getElementById(div[idx]).style.display = "block";
}
}
<body onload="hideallexcept('partdiv1');">
<div> <input type="button" name="prevpart" id="prevpart" value="prevpart" onclick="shownextdiv(i--);"/></div>
<div> <input type="button" name="nextpart" id="nextpart" value="nextpart" onclick="shownextdiv(i++);"/></div>
<div class="form-rfq" id="partdiv1">****</div>
<div class="form-rfq" id="partdiv2">****</div>
.
.
.
<div class="form-rfq" id="partdiv10">****</div>
</body>
Any help would be appreciated.
Your attempt would have worked, but the 'i++' and 'i--' in the function calls was stopping it. 'i' was not defined within the context of that script (in that case the context is with the onclick statement).
Here's what I'd do:
First the HTML:
<head>
<style> #parts INPUT { display: none; } </style>
<noscript><style> #parts INPUT { display: block; } </style></noscript>
</head><body><div>
<input type="button" name="prevpart" id="prevpart" value="prevpart" onclick="shownext();"/>
<input type="button" name="nextpart" id="nextpart" value="nextpart" onclick="showprev();"/>
</div><div class="form-rfq" id="parts">
<input style='display: block' ...>
<input ...></div>
</div></body>
We won't need an onload so that's gone from the <body>. Also I've put the 2 buttons in 1 div, remember divs are used mainly for page sections, so no need to enclose them individually.
All the parts input boxes are now inside the 1 div, that saves having preset id's and fixed code. The code we'll write will work with whatever is there, however many boxes there are.
There's also a little CSS in there, first we set all input boxes in the parts div to hidden, the first one will be shown as it's set specifically. Next there's a noscript tag, so if the user doesn't have javascript all boxes will be visible. We've also put the buttons in a noscript tag to complete the compatibility.
So now we just need our 2 functions, prev and next:
// Define 'i' here so it becomes a global variable
var i = 0;// We'll need to keep using these so only look up once
var inputs = document.getElementById( "parts").getElementsByTagName( "INPUT");function showprev() {
// Do nothing if 'i' is not in valid range
return if( !i);
i--;
// Rest of the code is common, so moved to a single function
updateparts();
}function shownext() {
// Same as prev function, but i++ instead
return if( i == inputs.length -1);
i++;
updateparts();
}function updateparts() {
// ok, we'll cycle through the input boxes now
// the ( j == i? "block": "none") part is a short way of doing if this else that
for( j = 0; j < inputs.length; j++)
inputs[j].style.display = ( j == i? "block": "none");
}
I haven't tested so it might not work quite right but give it a try and let me know how you get on.
I appreciate your input but if I understand your html code, I think there is a little mix up in understanding what is to be shown/hidden.
originally, the form allowed you to submit data for just one part. I want the form to allow the user to enter data for up to 10 parts before submitting the form to the php mail form script. Each part has many input fields.
That why I duplicated the part div 10 times and modified each part div's input field ids so they where unique for each part.
So i'm looking to show only one of the 10 part divs with all its input fields at a time. So if a user wants to enter - say - 3 parts before submitting, they would simply enter all the data for part1 (which is visible by default while all other part divs are hidden). Then they would click of the "next part" button. That would cause part1's div to be hidden and the next part div - part2 - to be visible for data entry and so on.
I probably should of laided out the part div examples like...
<div class="form-rfq" id="part1">
input id="part_number1"...
.
.
.
input ...
</div>
.
.
.
<div class="form-rfq" id="part10">
input id="part_number10"...
.
.
.
input ...
</div>
that should change the coding some - I think. I'll try to figure out what should change while I wait for your response.
Is the var i you defined global to just the script area its defined in or the whole html file?
<script type="text/javascript">
var i = 0;
<\script>
BTW... how did you put your code in the nice box?
// define the part div id array and change the document.getElementById below to document.getElementById(div[j]) unless the getElementById is able to parse all divs id's starting with "part".
div = new Array();
div[0] = "part1";
div[1] = "part2";
div[2] = "part3";
div[3] = "part4";
div[4] = "part5";
div[5] = "part6";
div[6] = "part7";
div[7] = "part8";
div[8] = "part9";
div[9] = "part10";
// Define 'i' here so it becomes a global variable
var i = 0;
// We'll need to keep using these so only look up once
var part = document.getElementById( "part");
function showprev() {
// Do nothing if 'i' is not in valid range
return if( !i);
i--;
// Rest of the code is common, so moved to a single function
updateparts();
}
function shownext() {
// Same as prev function, but i++ instead
return if( i == inputs.length -1);
i++;
updateparts();
}
function updateparts() {
// ok, we'll cycle through the part divs now
// the ( j == i? "block": "none") part is a short way of doing if this else that
for( j = 0; j < part.length; j++)
part[j].style.display = ( j == i? "block": "none");
}
I did misunderstand your input boxes yes, my mistake I should have asked. No problem, we'll tweak it slightly but no major issues.
ok, we really want to get away from this:
div = new Array();
div[0] = "part1";
div[1] = "part2";
div[2] = "part3";
div[3] = "part4";
div[4] = "part5";
div[5] = "part6";
div[6] = "part7";
div[7] = "part8";
div[8] = "part9";
div[9] = "part10";
The reason being, this is called 'hard coding'. Meaning the code is fixed, can only handle exactly 10 sections, so if you change your page you have to change the script as well. What if you want to extend to 15, or shrink to 5 parts?
Lets change the HTML so it's what you need it to be:
<div class="form-rfq" id="parts">
. <div>
. . <input ...>
.
.
. . <input ...>
. </div>
. <div>
. . <input ...>
.
.
. . <input ...>
. </div>
. <div>
. . <input ...>
.
.
. . <input ...>
. </div>
</div>
I think that's about what you have?
Now, we have only DIVs inside your div id='parts', so the Javascript will just need a little tweak as follows:
// We'll need to keep using these so only look up once
var inputs = document.getElementById( "parts").getElementsByTagName( "DIV");
By looking the elements up on the page, the Javascript will automatically use whatever is on the page, no need to 'hard code' names of divs, or numbers of divs.
In the next and update functions, we're working on the length of the 'inputs' array, so again no need to hard code anything.
One thing I should have noted though, as we're not using an onload, you'll have to put the script after the parts div, or when it tries to look up the elements they won't exist yet.
However, i'm still using the onload (for the moment) to set the visibility of the part divs because i didn't understand the solution you posted:
<head>
<style> #parts INPUT { display: none; } </style>
<noscript><style> #parts INPUT { display: block; } </style></noscript>
</head>
I think its called an inline style as opposed to putting it in a css style sheet file?
If i read it correctly, you have two styles attached to the "parts" div. One sets visibility off and the other on?
On the bright side, i took your shownext/showprev/updateparts javascript code - corrected the syntax (because they didn't work) and modified them a little.
div = new Array();
div[0] = "part01";
div= "part02";
div[2] = "part03";
div[3] = "part04";
div[4] = "part05";
div[5] = "part06";
div[6] = "part07";
div[7] = "part08";
div[8] = "part09";
div[9] = "part10";var i = 0;
function showprev() {
if (i > 0) {
hideallexcept(i--);
}
}function shownext() {
if (i < div.length) {
hideallexcept(i++);
}
}function hideallexcept(j) {
for (var n = 0; n < div.length; n++) {
document.getElementById(div[n]).style.display = ( j == n ) ? "block" : "none";
}
}
The above code works and i was able to modify your "updateparts" - now "hideallexcept" - to work for both setting the correct part div visibility during body onload and onclick for shownext/showprev.
I'd like to move more towards your methodology... meaning:
1. removing the div array hard codingdiv = new Array();
div[0] = "part1";
div[1] = "part2";
div[2] = "part3";
div[3] = "part4";
div[4] = "part5";
div[5] = "part6";
div[6] = "part7";
div[7] = "part8";
div[8] = "part9";
div[9] = "part10";2. One time elements lookup
var inputs = document.getElementById("parts").getElementsByTagName("DIV");
once i get what i have working properly.
The only problem is when i change onclick shownext/showprev direction. for some reason it does the following:
initial page load shows part01
shownext shows part01
shownext shows part02
shownext shows part03
shownext shows part04
showprev shows part05 <---
showprev shows part04
showprev shows part03
showprev shows part02
shownext shows part01 <---
shownext shows part02
shownext shows part03
I can't see why its doing that.
The test site rfq page is:
< url removed >
the parts entry areas are the; "Part[x] Information", "Tube Mill" and "Tube Fabrication" boxes. While clicking on the next/prev part buttons, watch the title "Part[x] Information" in the "Part[x] Information" box.
[1][edited by: Fotiman at 6:41 pm (utc) on Aug. 14, 2008]
[edit reason] No personal URLs please. See the TOS. [/edit]
corrected the syntax (because they didn't work)
D'oh! Nevermind, I did say it was untested, glad you managed to correct me!
I figured out the increment/decrement problem
Well done, this is called a pre-increment, rather than a post-increment.
Please let me know how you get on with making the code adaptable. FYI, you can add the extra external DIV, and it will still work even if you leave all the original DIVs with their IDs on.
The first line hides all divs. The first is set explicitly on the element, thus overriding this, so you start with them all hidden except the first.
The second inline style does indeed show all divs. As it appears after the first it overrides, thus all divs are shown. But as it's enclosed in a
<noscript>tag this will only take effect if they have Javascript disabled.
Think, if a person has JS disabled, how do they enter multiple parts? This way works for both and is very easy to implement.