문제

I may just be searching Google using the wrong keywords but I am having very little luck finding information on creating expandable form fields. I have an input form where a user can list all of the inventory assigned to a server node, but would like for them to be able to add additional items if needed. Example being the form shows an option for (1) Disk to be added but they can click a + symbol and add more.

I already created 8 MYSQL rows for each type such as disk1, disk2, etc. to allow for a considerable amount to be stored. However, my concern is that this works out to be a LOT of options.

1) How can I use Javascript to create expandable forms? I only found one code example that didn't work. 2) Should I hard-code all of the options? Such as, right now my code has a Select box named "ram", "motherboard", etc. Could I generate these or should I go ahead and write it out for each field such as "ram1", "ram2", etc?

enter image description here

도움이 되었습니까?

해결책

Cloning the field in JavaScript is easy. Say you have:

<select name="hdd"><!-- ...options here...--></select>

then once you get a reference to that existing element in the DOM (see below), you can do this:

var newSelect = existingSelect.cloneNode(true);
newSelect.selectedIndex = -1; // To clear any existing selection
existingSelect.parentNode.insertBefore(newSelect, existingSelect.nextSibling);

Getting the reference to the existing select can be done on any modern browser using a CSS selector and document.querySelector (to get the first match) or document.querySelectorAll (to get a list of all matches), for instance:

var list = document.querySelectorAll('select[name="hdd"]');
var existingSelect = list[list.length - 1]; // Get the last one

...which will give you the last one. Or more likely, you have a row of some kind (a tr, or a div) containing that which you want to copy. Not a problem, give that row a class (say, "hdd"), and clone the entire thing (here I'm cloning the last row and adding it to the end):

var list = document.querySelectorAll('.hdd');
var existingRow = list[list.length - 1];  // Get the last one
var newRow = existingRow.cloneNode(true); // Clone it
newRow.querySelector('select[name="hdd"]').selectedIndex = -1; // Clear selected value
existingRow.parentNode.insertBefore(newRow, existingRow.nextSibling);

On the MySQL side of things, it's best not to have columns like hdd1, hdd2, etc., because it makes queries on those fields complicated and does, of course, limit the maximum number you can have (granted you'll probably want to limit that anyway). (Having those columns in one row is called "denormalizing" the DB.)

The usual way to do that in DB design is to have a second table, listing HDDs, where a key in that second table (a "foreign key") links back to your main table. (See "database normalization" for more information.)

So your main table might have a record id, say SystemID. Your HDDs table would then have a SystemID column and an HDD column, where it could have many rows for the same SystemID.

Here's a complete example of the form bit: Live Copy | Live Source

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Add Form Field Example</title>
</head>
<body>
  <div class="hdd">
    <label>HDD: <select name="hdd">
      <option>--choose--</option>
      <option>80GB</option>
      <option>500GB</option>
      <option>1TB</option>
      <option>2TB</option>
      </select></label></div>
  <input type="button" id="theButton" value="Add Row">
  <script>
    (function() {
      document.getElementById("theButton").addEventListener("click", addRow, false);

      function addRow() {
        var list = document.querySelectorAll('.hdd');
        var existingRow = list[list.length - 1];  // Get the last one
        var newRow = existingRow.cloneNode(true); // Clone it
        newRow.querySelector('select[name="hdd"]').selectedIndex = -1; // Clear selected value
        existingRow.parentNode.insertBefore(newRow, existingRow.nextSibling);
      }
    })();
  </script>
</body>
</html>

Some useful references:

다른 팁

Try creating a generic DEVICE_DETAIL table, with columns for TYPE and DETAILS. Then you can hold an arbitrary number & add new types in the future.

create table DEVICE (
    ID integer not null,
    ..
    primary key (ID)
);
create table DEVICE_DETAIL (
    ID integer not null,
    FK_DEVICE integer not null,
    "TYPE" varchar(24),                  -- type code; defined internally.
    CONFIG varchar(200),
    NOTES clob,                          -- if necessary?
    .. more columns if useful
    primary key (ID)
);

The benefit of this, is that you don't need separate tables for HDD, IP addresses, RAM, or a wide range of future possibilities. You just need a couple of columns which can hold the details -- and for most things, one line will suffice.

Add & show new fields in the UI, as the user fills out the previous ones.

The simplest way to do this is to register an "Add Field" click handler, and use that to create a new field in Javascript. I've put together a quick example to show you how to do this with input fields.

Here's the HTML:

<form id='form'>
  <div>
    <label for='input0'>Field 0</label>
    <input name='input0' type='text'></input>
  </div>
</form>

<a id='moreLink' href='#'>Add Field</a>

Here's the Javascript:

var inputIndex = 0;

document.getElementById('moreLink').addEventListener('click', function() {
  var form = document.getElementById('form'),
    newLabel = document.createElement('label'),
    newInput = document.createElement('input'),
    newDiv = document.createElement('div'),
    inputId
  ;

  inputIndex++;
  inputId = 'input' + inputIndex;

  newLabel.htmlFor = inputId;
  newLabel.innerHTML = 'Field ' + inputIndex;
  newInput.name = inputId;
  newInput.type = 'text';

  newDiv.appendChild(newLabel);
  newDiv.appendChild(newInput);

  form.appendChild(newDiv);
});

And here's a link to a JSFiddle so you can see it in action: http://jsfiddle.net/tpmet/

This is a pretty naive solution, but it'll perform fine and will work in any browser you throw at it, at least as far back as IE6.

If your markup gets more complicated, you should consider creating a template once at startup and cloning that template in the click handler. And if you plan to add entire forms or other large amounts of DOM, I'd recommend reading up on Document Fragments, which are more complicated but would perform better at that level of scale.

Hope this was helpful, please comment if my answer is unclear.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top