SCRIPTING:

Nikki Nova
JAVASCRIPT CLASS FOR SQL AND MYSQL PHP FORM SUBMISSION DYNAMIC INTERFACES WITH DYNAMIC ADDITIONS AND REMOVALS OF FORM FIELDS VIA DOM AND DHTML: THE FORM ADDER
Client side scripting, like via Javascript or ECMAScript, can provide a meaningful support to server side scripting (like by PHP) which is not perfunctory or tampering, but that can be genuinely useful, and not achievable in any other way.

HTML form fields meant to host SQL database drawn values, may need such a HTML interface where the user can be prompted on whether to add to or remove from the HTML form one or more form elements so to dispatch to the server side script and thence to the database more fields all pertaining to the same SQL group: typical example a comment field prompting whether you want to add one more comment - which would require one more field.
Populate your form on demand with dynamically added fields or remove selected ones among the produced fields.
The submission won't be altered and all the newly added or removed fields would be dispatched to the server side interpreter.
November 2004
{ @ }
The model above is Nikki Nova
LOADS OF NIKKI NOVA ON THE NET


PURPOSE OF THE SCRIPT
What is the problem that this script solves

Client side scripting is perceived by a few like an approach that illegitimately tampers with a world that should have been all style sheets (css) layout driven, with server side scripting allowed by necessity.
Not that the latter is better tolerated than client side scripting is by those who believe in a css approach as the big resolver (we carry our bias and illusions truly everywhere, even on browsers): only, they just can't do anything about it because when we are on the server side a dedicated language tailored for the specific platform of the server Operative System is a requirement that cannot be eluded no matter how despised it would be because belonging to the same scripting paradigm.

Yet, it is barely comprehensible this apparently widespread distrust of the client side: all web logs show that 97% of the visits have javascript enabled (and that 3% is likely mostly composed by search engines visiting bots), important enterprises like Hotmail rely on it too and prosper, and I can't see why we should portray neglecting client side as an improvement rather than as an impoverishment: all the power that client side scripting undoubtedly provides is a fact, and the pretence we would have been gaining something with the stance just adds conceit to a wrong thesis: we are losing something, and not gaining, when we give up something.

I agree 100% that a server side engine should never, absolutely never, rely or trust on the client side not even for mere incoming data validation.

A Marc Chagall painting
A Marc Chagall painting
Yet, what I am here about to propose to your attention is a javascript class that does something on the client side that not only can prove its patent utility for the server side end, but that could not be achieved in any other fashion - unless resubmitting to the server side over and over again just to produce html changes on the client side page that are not mission critical but which none the less still are interesting additional features and that can be attained staying on the client we already are on.
So that when in order to do this we predicate the solution would have consisted in repeatedly requesting again from the server side non mission critical and yet interesting features, what we predicate is a plain misconception, which a few even argue would tantamount to "spreading" good programming practice and performance enhancement!

Moreover, this javascript class adds a significant value to a page and not a perfunctory one (this is not scripting frippery for decorative purposes and frills), while at the same time providing a sheer enrichment in the layout and, last but not least, while also allowing for a default setting which won't send things awry if the client side is not supported (notorious javascript disabled, a phoenix we all hear about but we never actually meet): in fact, if javascript would not be enabled, as long as your form holds a default set of form fields, this (alleged and anyway remotely) possible inability to add more fields (this is what this class does) to a form on the fly via javascript, would not compromise one thing on the server side, whereas if javascript is enabled (as it is 97% of the times) the gain is remarkable: more fields to be processed on the server side in case the client surfing the page requires them - and don't you wish to provide your end users with more functionalities rather than less, if this addition does not compromise a basic default setting.
And so, being things like this, no one can disprove any longer the utility of this javascript approach to support server side scripting too. This is a fact.

I have developed this class working on the field, I mean dealing with an actual server side database interface that had to print a set of html form fields, populated with data taken from the database, whereas the need to add fields via client side script arose as an inherently interesting option.
This was basically to serve a many to one SQL table which could allow, for one type of element, a manifold set of possible answers - from 1 till x.
Thus what was needed was just one default html form field and the possibility to add more on demand in case the surfer wished so.

Moreover, this javascript can produce not only form fields, or remove them on demand, but also all the wrapping html you may want for each of them, in case these form fields are conceived as more complex html units and therefore should also have around them a set of commands or of other form elements or of Css statements that provide them all with one same feeling.

Not only, but this class proved its utility also for those cases of SQL fields that would allow only for a limited amount of chars (say, typically, the 255 varchar mySQL data type limit) in order to avoid filling a SQL table with blob data type, and that yet were also fit, in some cases, to extend their functionality to twice or thrice that amount: in this case, multiple additional form fields with a limit of 255 chars could be produced on demand via client side scripting and this only if and when needed by the client.
The thus produced fields could then either be recombined (once elaborated onto a server side interpreter) or assigned to multiple SQL table fields in a many to one relation so to build texts (aren't we in the hypertext era?) that are well above the 255 chars limit and yet without forcing the SQL tables to host too obtrusive data types (like the blob data type).

This is client side truly helping the server side, while compromising nothing.


THE CODE
The copy and paste code of the class

The name of this class is:
formAdder
and first of all I provide you with its code.

A Henri Matisse painting
A Henri Matisse painting

lines (with comments and blank lines):
A Joan Miro painting
A Joan Miro painting


INITIALIZATION OF THE CLASS
The first steps

Since this class works with forms, the first thing you need is a form in your page.

Then you need a layer with an id, for each group of additional form elements you may want to build. You'll arguably need only one of such layers, to which you will append as many additional form fields as you may want to produce. But of course if there is more than one page location where you want to append fields, then you need more of such layers (but with different ids!) in such locations.
This layer can have its own css style declaration, it is up to you if you want to decorate it via css or not. What it needs as mandatory as far as this script is concerned is only an id, for which we'll use in our example a placeholder value: foo.
So, say:

<div id="foo"></div>

You put it in the page exactly in the location where you want your possible html forms being added or removed.
I would like to strongly suggest to you to give to it a width via css, or layers included there could overstretch the page: instance:
<div id="foo" style="width: 200;"></div>

Once you have this, the initialization of the class, with a placeholder variable named still foo (to simplify things we assign the same name to both for now - this is legitimate for the one foo belongs, so to say, to the DOM hierarchy, the other to the scripting hierarchy, likewise you can have a John living in UK and another one living in Canada) is:

var foo=new formAdder(layerId);

The only argument passed to the constructor is the id of the layer as a String, so for instance:

var foo=new formAdder("foo");

The only thing that I really want you to keep in mind now is that you should never initialize this class instance before you have loaded in the browser the full opening and closing tag set of your involved layer mentioned just before. So that script statement can be put only after the layer tag set.

In the example such layer is a <DIV> tag but of course it could be whatever else, and you can assign to it as many Style Sheet properties as you prefer, though basically that layer is just a proxy meant to reside stealthy in the page so to afford a backbone onto which you can append your generated new form fields in the exact location where such layer is appears. So it should probably be empty and with no css decorations.
The only thing you can not do with such layer(s) is to assign to it style sheet properties such as an invisible visibility or display "none" css values, for this would prevent also the form fields added to it from showing up.


AVAILABLE CLASS METHODS
Description of the methods and usage of the class

  • set:
    foo.set(String);

    I am now going to explain to you the most apparently difficult thing. After this, it's all downhill.

    There is in this class a default behaviour: the class produces textarea tags.
    If you want to override this, you call in set() before adding layers to the class (you will see soon as you add the layers). You pass to this method one argument, which is the name of the tag you want to produce: instance:
    foo.set("select");
    Such a statement would override the default textarea tag and would rather produce a select drop down menu.
    So to produce a mere text form tag:
    foo.set("text");
    For a checkbox:
    foo.set("checkbox");
    For a radio button:
    foo.set("radio");
    For a button (though I deem this unlikely):
    foo.set("button");
    Or, even for a hidden form input tag (which maybe makes no sense, yet the class is complete and can do this too):
    foo.set("hidden");

    If from now on you call the next documented method addLayers, each call to it would produce a tag of the given set type, unless you call in again set() with a different argument.

    Apparently, so far so good: you can add form tags which is what you wanted.

    Yet there can be a different case, namely when you want to add not only a form tag because just the form tag would not suffice, but you want to add it plus a set of other wrapping html elements that should go with each of these added form tags, arguably to keep consistency not only with the overall feel of the page (which could be compromised if you'd add just bare form tags, maybe) but also to add for instance labels or anchors.

    A typical case indeed if the above, would be a "remove this field" link, and an "add another field" link, that should go with each newly produced form tag as its faithful servants, and that should carry javascript commands in their event handlers, each related to its own just newly produced form tag, I guess (or anyway that was what I had to do on the server side that spurred me to produce this class to address that problem).

    But since I don't know what you may want, I could not set any plausible default for these potentially "millionfold" cases, namely of sets of form tags that must also be accompanied by a set of ulterior mating tags and formattings.

    This case posed a conundrum. Which I solved this way.
    Let's analyze it together, so you'll see what's the rationale behind it.

    These elements that should go with the form tag to add, most times cannot be passed to the class just as they are as a String and once for all: in fact, though all similar, these added tags are plural: tags, not tag- so it is well possible that though basically identical, yet a few elements in them should differ at least for a few details - typical case the possibly needed id attributes values, which have to be unique.
    Therefore this immediately entails that one template can no longer account for them all.
    So, the question arises: how can you instruct the class that the string representing the html nucleus template you want to add has to account for these customizations of each instance too, at each newly produced and inserted (added) instance?

    This means that this template can host "sensitive" places, so to call them funny, where replacements must occur.
    You also may need to discriminate among more different types of replacements in more locations.

    This means you need to put in this template string some identifiers that flag where these replacements must occur.

    This also means you need to define the replacers.

    This problem is solved in this class in the following manner.
    Whereas you need in the string to include these tailored details, you place a symbol crafted as follows:
    @# plus a number, say:
    @#1

    A trivial example could now be:
    'A Label <br><textarea name="@#1" id="@#2"></textarea>'
    Do not forget to sorround the @# signs with quotes "" if the tag would require them.

    Pass such string to the method named set:

    foo.set('A Label <br><textarea name="@#1" id="@#2"></textarea>');

    A John Everett Millais
    A John Everett Millais painting

    Once placed and passed these placeholders to the method set(), the method will understand it is not an argument passed to it like the previously documented ones, and the class will replace in it the placeholders accordingly to the following guidelines:
    • each @#1 is replaced with:
      the id of the backbone layer in our example:
      <div id="foo"></div>
      namely will be replaced with the String:
      foo[]
      namely with the id plus a set of square brackets, as a String: this is what most server side languages like PHP would expect when parsing submitted fields meant to be grouped like arrays on the server.
    • each @#2 is replaced with:
      the id of the layer as above plus a number signifying the amount of layers currently produced: this is very likely to be the perfect candidate for yielding a full formatted and ready unique id.
      Numbers start with zero included.

      In order to make sure this class always works in the expected way, I strongly urge you to assign always (always) an id to the main form field you're adding, and to assing to its value in between quotes precisely (exactly) this @#2 placeholder:

      <input id="@#2" etc etc...>

      Below you can read why (click).
    • each @#3 is replaced with:
      just the layer id String ('foo').
    • each @#4 is replaced with:
      just the amount (a Number, of course) of currently produced layers. This number starts from zero included.
      If added tags are removed, the situation will be correctly reported (and no conflict may arise with previously assigned number, for a removed tag is erased as far as everything of it was concerned).
    The reason you cannot assign real values but only placeholders (that apparently strange @# symbol) should be obvious to your eyes: since you are likely to be going to use that statement over and over again to create multiple instances of the form tags with their surrounding mating html elements that go with it, these instances cannot be tags having all the same values and identifiers, or names: but such identifiers must be drawn dynamically from the class, because each time a new form element is produced, there must be something in the class that provides us with data to read the updated situation. You do not want to end up assigning twice the same id continuously to every newly produced tag names to see later all your further scripts jeopardized by this mistake, correct?
    But if you don't want that, it means you want to rely on the class to tell you what the most adequate values for the most recent situation are!
    Thus you put placeholders.
    [A note for experienced scripters who none the less could be wondering: remember this, that the reason you have to swap these placeholders at runtime is that javascript does not implement pointers for primitive data types, so I could not afford as a solution string concatenation and I could not store this data in any definitive memory slot extraneous to the scope of the class].

    The reason @# is used as a prefix is, if you think of it, very far from being fantastically arbitrary: in fact, such apparently nonsensical a string has been chosen because it should not be likely at all to recur anywhere else in your passed string as an accident rather than as a deliberately inserted swapper, because there exists no email address whose server portion starts with a # sign!
    So it was not arbitrarily chosen at all!
    Therefore it is nearly impossible that anything else which is not a placeholder intentionally inserted in your string to be replaced, gets mistaken for being such: chances that in your string there is such a syntax unless you deliberately insert it for this purpose are nearly zero (anyway you can change this if you check the code for the class variable named replacer: it holds this two chars '@#', though the class method named replace then checks for them plus a number) unless you are writing a pop-art like expression of bewilderment or insult like those we see in comics: @#!*%! - but also then the presence of numbers in such expressions is unlikely, for they want to convey rage, not mathematical logic.
    Don't forget to add a trailing number to the @# prefix when you use it as a placeholder swapper.
    Moreover, it conveniently reads: "at number": "@#"

    Please note that when including such complex nodes, the class itself will wrap them even more: once. In fact it will wrap them with a <SPAN> tag (or at least that's the default wrapper tag: you could change that locating the class variable named this.wrapperTag) whose id will be in the shape:
    _wrapper_ plus backbone div id in our case foo plus a progressive number. Instance:
    _wrapper_foo7

    If you don't like this prefix, namely "_wrapper_" you can change it locating the class variable named wrapperId in the code. But if you do, you must be sure you do put another prefix, and that the combination described above would not be likely to yield the identifier of any other already existing layer in your document.
  • A Peter Paul Rubens painting
    A Peter Paul Rubens painting
  • addLayers, addLayer:
    foo.addLayers(); or foo.addLayer();

    This creates an element after the type of parameters passed to set() or just uses the default values if set was never called in. The element is appended.

    If you want to specify further attributes for the new added tag, you have to issue the statements yourself in the way seen below, for certainly I could not predict, for instance, that your textareas must have, for instance, 12 rows.
    You achieve that after having produced your tag by using the class property named last. See below how, it should be rather intuitive:

    Of course, you can also issue commands like x.addLayer() from within an event handler such as onClick, or you could include the statements within functions of your own fantasy and conception and invoke these latter from event handlers of your liking.
  • removeLayers, removeLayer:
    foo.removeLayers(); or foo.removeLayer();

    This removes a layer previously added. It by default removes the last added one upward the ladder.
    It can accept two optional arguments:
    • which: a layer Id, which will be removed.
      Such layer id should include the _wrapper_ prefix if the added form element to be removed was created via a call to the set class method that did not include as its argument a mere form field tag name (textarea, text, select, etc...) but a whole string with the replacers in it ( "_wrapper_@#2" ).
      With no arguments passed at all, removes the last added ones.
    • remains: a second optional argument; by default the class removes, for its assigned lot of battlefield, all the layers except the last one that happens to be left after, say, a massive removal: that is, all layers can be removed, but one has to stay. This so to avoid depriving the database, upon submission of the form, of an arguably indispensable Post value.

      If you want to allow the deletion even of the only remaining tag, pass this second argument as 1.
      This is particularly needed in case you have a form tag already present and you want this to be considered as the un-deletable one: since that was already present and not produced by formAdder, that cannot be removed by formAdder too; therefore you may want to remove all those produced by formAdder. To do this, call removeLayers bypassing the which argument by an empty string, and the second argument as 1:
      foo.removeLayers("", 1);
  • To all the newly added layers, the outermost container will be assigned a css class name that defaults to:
    yourClass
    Such name is stored into the class variable named: this.className
    You can thus create a Css definition with that name to change its aspect, or add even selectors of Css definitions where for instance tags within that class are affected, say like:
    span.yourClass

    The current document uses these Css definitions for the tags added via this script :


    Netscape 6 could still make a mess with Css - with good peace of those who say this is not true, and who evidently never faced a more complex problem than making a website of 3 pages that imitate postcards.


THE TEST FORM
See it in action and enjoy

Working Example formAdder Set Up Guidelines Summary:

  1. var x=new formAdder('foo');
  2. Optional step: change class properties?
    x.wrapperTag="DIV";
  3. x.set('');

    Use this in the TEST:
    x.set(' ');

    Use this in the TEST:
  4. x.addLayer();
  5. You could now modify the properties of the newly added layer on the fly if you want, for the class only assigns to it an id, a name, and a class name.
    To change the properties, use the class variable named last; instance:
    x.last.style.color='#ff0000';
    x.last.value='I am layer n.' + x.amount;


    WARNING: for this feature to work (namely for calling in the class property named "last" and affecting through it the designed form tag), if you pass replacements in the shape @#Number, it is imperative that inside your main FORM FIELD nested within the bigger definition you assign this very same line:
    id="@#2"
    Anyway, the class property named "last" will refer to an object with an id corresponding to the replacement for @#2, so if you use such property make sure such an id (the replacement for @#2) exists in some element at least. The class is designed to avoid errors if you don't comply with this requirement; but yet, then, if this compliance lacks and none the less you also use last do not wonder why you see affected another layer: the _wrapper_.

    Example of usage of the class variable named last: what is in this textarea will be executed by the script on the run, so be careful if you decide to edit it.

  6. x.removeLayer( , remains? );

TEST IT (click the buttons after the image)
A John Sargent Singer painting
A beautiful John Sargent Singer painting

         

This would be the stealth foo layer used to append, here shown just for clarity



Of course, it is possible that you are now wondering whether this class which works so good with form fields, could be used to add and remove other type of tags too than just form fields, or anyway set of tags that do not involve form fields somewhere.
The answer is: definitely yes, it can. Just run it in the @# definitions fashion, defining there what these html units must be.

This is how flexible these scripts can be, though I have no personal illusion or any peculiar narcissism that would have barred me from knowing what I know all to well, namely that you can also find questionable solutions on this website, now and then, or that a misconception is possible; and yet it is still true that Unitedscripters is a place where you can also find truly interesting things at times - which nothing prevents you from making better, possibly dropping an acknowledgement as I myself various times do here when I used a tidbit of another programmer - pardon: scripter.
One day I'll tell ya what's the difference. But that day is not today.