[thelist] Dynamic Form Javascript Coding + Tips(2)

.jeff jeff at members.evolt.org
Wed Jul 25 11:22:47 CDT 2001


dante,

:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: From: dante
:
: As I mentioned in previous posts, I've been
: working on a form that dynamically changes
: depending on values entered.
:
: http://www.vianet.net.au/~dante/xml/input_form.html
:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

what level of browser are you looking to support?  are you considering
offering alternative, server-side form creation for those users that aren't
up to that level of support or don't have js at all?

:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: When a value (between 1 & 12) is entered into
: the author text input & the change form button
: is pressed - the code should be written into
: a div.
:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

if the user really is limited to a finite range of elements, then i'd give
them a dropdown menu.  that way you don't have to validate that they've
entered numbers and that the number they entered is within a certain range.
use the onchange event handler to rebuild the requisite number of form
elements.

:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: 1) I need the wholeName div to be erased each
:    time before it gets rewritten - right now
:    it's appending the new content instead of
:    replacing it.
:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

simple, clear the value of the "nameData" variable each time the Repeater()
function is called.  otherwise your writeNames() function is simply
appending to that variable and will continue to do so, creating as many
author form elements as you ask it to (and then some).  however, as you'll
soon see, you don't need the wipeData or nameData variables at all.

:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: 2) I need the same data to be written to a second
:    div (wholeNameTwo), but I would prefer not to
:    use redundant code.
:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

you'll need to further generalize your writeNames() function.  i'd also
recommend renaming the divs you're writing to.  i'd make them authorWrapper
and illustratorWrapper.  this is necessary for the generalization process.

then, i'd pass an object reference of the object the user is interacting
with to the Repeater() function.  this object can be used to get both the
name of the object which will be used to determine what kind of elements
you're building as well as the value of the object so you know how many
blocks to build.  make sure to pass the name of the object to the
writeNames() function so it knows which elements to build as well.

additionally, instead of having the writeNames() function actually write to
the layer, i'm setting it up to simply return a string value which can be
used to insert into the layer.  the reason for this is that the writeNames
function is called over and over again resulting in writing to the layer
many times when you really only need to be writing to the layer once.  so,
your Repeater() function will do the calling of the writeNames() function
and will also do the layer writing.

since we'll be using methods not supported by some browsers
(getElementById()), we'll check for their support prior to using them so as
to prevent errors from occurring.  if they don't support these methods then
we'll simply submit the form where the server-side processing can take over,
validate the data and send an updated form back to the user.

you'll also notice that i'm giving the user the chance to back out of their
choice which would result in losing any author data they've already entered.
you could probably come up with a better approach that wouldn't have that
limitation, but it would involve many, many more lines of code.

(as an aside, i think i've come up with a very simply way of preserving the
user's information simply by querying its existence when building the copy
of the elements that will eventually replace it and if it exists using the
existing elements values as the values for the new copies.  that means that
the only data that would be lost is the data that was in elements beyond the
new count, in the instance where they first had 4 elements, entered data,
then decided to change it to 2 elements.  i'd include that bit in this
reply, but i'm too lazy to go back and rewrite portions of my explanation
and the associated code which is all from my head anyway [read: untested])

your dropdown menu:

<select name="author" onChange="Repeater(this)">
  <option value="1" selected>1</option>
  <option value="2">2</option>
  <option value="3">3</option>
  <option value="4">4</option>
  <option value="5">5</option>
  <option value="6">6</option>
  <option value="7">7</option>
  <option value="8">8</option>
  <option value="9">9</option>
  <option value="10">10</option>
  <option value="11">11</option>
  <option value="12">12</option>
</select>

your script:

var repeaterWarning = 'You will have to re-enter any '
                    + 'author information you\'ve '
                    + 'already entered.  Do you wish '
                    + 'to continue?';

function Repeater(obj)
{
  if(document.getElementById)
  {
    if(confirm(repeaterWarning))
    {
      var writeStr = '';
      for(var i = 0; i < obj[obj.selectedIndex].value; i++)
      {
        writeStr += writeNames(obj.name, i + 1);
      }
      writeObj = document.getElementById(obj.name + 'Wrapper');
      writeObj.innerHTML = writeStr;
    }
  }
  else
  {
    document.upLoadLibrary.submit();
  }
}

now, your writeNames() function will need to be adjusted slightly to make it
more generalized.  it should still have two arguments being passed to it --
object name, and block number.  since your name blocks all contain
approximately the same HTML, i've created an array, which i loop over to
create those elements.  we're no longer passing the

additionally, i've changed the way the elements are named so they're more
easily connected with the type of information they're containing -- author
or illustrator.

and finally, i've changed the way you're quoting your attributes and
wrapping your strings in javascript.  if you're going to be trying to
validate to xhtml (as evidenced by the trailing slash on your <input> tags),
then you'd better wrap your attribute values in double-quotes.  that means
that single-quotes are the best choice for wrapping your strings in
javascript.

function writeNames(objName, objNumber)
{
  var nameParts = new Array('First', 'Middle', 'Last');
  var objLabel = objName.charAt(0).toUpperCase() + objName.substring(1);
  var returnVal = '<table border="0" align="center" width="340">'
                + '<input type="hidden" name="' + objName
                + '_order_number_' + objNumber + '" value="'
                + objNumber + '" /><tr><td colspan="2"><b>'
                + objLabel + ' ' + objNumber + ':</b></td></tr>';
  for(var i = 0; i < nameParts.length; i++)
  {
    returnVal =+ '<tr>'
               + '<td width="100">' + nameParts[i] + ' Name:</td>'
               + '<td><input type="text" name="'
               + objName + '_' + nameParts[i].toLowerCase() + '_name_' +
objNumber
               + '" size="30" maxlength="80" value="" /></td>'
               + '</tr>'
  }
  returnVal =+ '<tr><td colspan="2"></td></tr></table>';
  return returnVal;
}

the advantage of the method above is you could add as many repeatable
elements to the form as you wanted and all you'd have to do to add them is
add an appropriately named div (object name plus "Wrapper") and a dropdown
menu for the new element and you're in the money so long as each new element
has the same approximate structure.  you'd also need to adjust your
server-side code to compensate, but at least your efforts on the client-side
are highly minimized.

:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: p.s: I've been told that this form has caused
: problems with Netscape - something that hasn't
: happened for me during testing(?), so beware :)
:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

yeah, it doesn't work at all in nn4.  i'd remove the bit of code to support
nn4 -- you'll not get it to work anyway as form elements within positioned
elements are part of another document object and therefore not part of the
form they're contained in within the top level document object.
additionally, you'll have to wrap the elements you're creating in that layer
with <form></form> tags so the newly built elements will even render -- not
to mention all the styling issues you're going to run into within that new
layer.  once you do have the display right, you'll have to come up with a
mechanism for transferring the data from the forms within the layer to the
form in the main document for submission.  yuck -- don't even bother.

if i were you i'd come up with some server-side processing to address that.
the server-side script could detect whether or not the additional author and
illustrator form elements are present and if not, give the form back to the
user, but with the right number of elements created on the fly -- all while
retaining any form element values already entered by the user.

done right (as i've tried to illustrate above), this form could work for
damn near everyone.

maybe i'll get around to putting up an example of this complete with
server-side code so it supports everyone.

good luck,

.jeff

http://evolt.org/
jeff at members.evolt.org
http://members.evolt.org/jeff/






More information about the thelist mailing list