2

I'm currently creating a site with a fair number of forms that vary in the types of fields included and I was wondering what other people do to keep the amount of form "constructor" code to a minimum and reusable.

Here's an example of some of my current code:

function editForm () {

  function saveButton () {
    return $('<tr/>')
      .append(
        $('<th/>')
      )
      .append(
        $('<td/>')
          .append(
            $('<input/>')
              .addClass("new-button")
              .addClass("submit-button")
              .attr("type", "button")
              .attr("value", "Save")
          )
          .append(" or ")
          .append(
            $('<a/>')
              .attr("href", "#")
              .text("Cancel")
          )
      );
  };

  this.section = function () {
    return $('<form/>')
      .attr("action", "#")
      .attr("method", "GET") 
      .append(
        $('<table/>')
          .append(
            $('<tbody/>')
              .append(
                $('<tr/>')
                  .append(
                    $('<th/>')
                      .append(
                        $('<label/>')
                          .attr("for", "title")
                          .text("Title")
                      )
                  )
                  .append(
                    $('<td/>')
                      .append(
                        $('<input/>')
                          .addClass("title")
                          .addClass("text")
                          .attr("name", "title")
                          .attr("value", title)
                          .attr("type", "text")
                          .attr("required", "true")
                      )
                  )
              )
              .append(
                saveButton()
              )
          )
      );
  };

  this.menuItem = function () {
    return $('<form/>')
      .attr("action", "#")
      .attr("method", "GET")
      .append(
        $('<table/>')
          .append(
            $('<tbody/>')
              .append(
                $('<tr/>')
                  .append(
                    $('<th/>')
                      .append(
                        $('<label/>')
                          .attr("for", "name")
                          .text("Item Name")
                      )
                  )
                  .append(
                    $('<td/>')
                      .append(
                        $('<input/>')
                          .addClass("name")
                          .addClass("text")
                          .attr("name", "name")
                          .attr("value", menu_item.name)
                          .attr("type", "text")
                          .attr("required", "true")
                      )
                  )
              )
              .append(
                $('<tr/>')
                  .append(
                    $('<th/>')
                      .append(
                        $('<label/>')
                          .attr("for", "price")
                          .text("Price")
                      )
                  )
                  .append(
                    $('<td/>')
                      .append(
                        $('<input/>')
                          .addClass("price")
                          .addClass("text")
                          .attr("name", "price")
                          .attr("value", menu_item.price)
                          .attr("type", "text")
                          .attr("required", "true")
                      )
                  )
              )
              .append(
                $('<tr/>')
                  .append(
                    $('<th/>')
                      .append(
                        $('<label/>')
                          .attr("for", "description")
                          .text("Description")
                      )
                  )
                  .append(
                    $('<td/>')
                      .append(
                        $('<textarea/>')
                          .addClass("description")
                          .addClass("text")
                          .attr("name", "description")
                          .attr("required", "false")
                          .attr("rows", "2")
                          .attr("cols", "50")
                          .text(menu_item.description)
                      )
                  )
              )
              .append(
                saveButton()
              )
          )
      );
  };
  return this;
};

Here's some more info on what I'm currently doing and what I'm trying to achieve:

The forms on my site are the only objects that I've laid out using a table layout so I can have form labels right aligned to the input field. From my understanding this gutter between labels and fields is the best way to make the forms easier for users to grok. I'm open to suggestions on how to achieve this same effect in other ways, especially without using tables if possible.

My javascript currently builds these forms element by element using the JQuery selecter to create an element $("<element/>") and then using javascript functions like .append() to chain them all together.

Because I'm building the forms with a table layout, it means that there is a lot of repeated code in create the basic row structure:

<tr>
  <th>
    <label for="fieldname">Field</label>
  </th>
  <td>
    <input name="fieldname" type="text">
  </td>
</tr>

Because of this approach you can see a lot of repetition in my code above that intuitively I think I should be able to eliminate and possibly make a form-builder that I can use site-wide.

In my code above I am repeating many elements like , , , , , etc.

What I'd like to be able to do is create forms in a much more succinct format like so:

menu_item = {
  name:         "",
  price:        "",
  description:  ""
}

createForm()
  .addField(menu_item.name, "Nome", "text-input", required)
  .addField(menu_item.price, "Preço", "text-input", required)
  .addField(menu_item.description, "Descrição", "textarea")
  .addField("Salvar item", "submit-button");

or better yet, like so:

createForm()
  .addField({
    value:       menu_item.name,
    label_text:  "Nome",
    input_type:  "text-input", 
    required:    true })
  .addField({
    value:       menu_item.price,
    label_text:  "Preço",
    input_type:  "text-input", 
    required:    true })
  .addField({
    value:       menu_item.description,
    label_text:  "Descrição", 
    input_type:  "textarea" })
  .addField({
    value:       "Salvar item", 
    input_type:  "submit-button" });

where the addField function has a format where you can name the field, define the label shown to the user (which initially will be Portuguese, but we would like to be multilingual in the future) and the type of input element and options for that input element such as required="true" or placeholder="i.e. Cereal, Waffles, Toast, etc."

Anyone have any suggestions on how they resolve this issue or any production-ready JQuery plugins (i.e. plugins that are currently maintained and not simply experiments or abandonware) I should look into for helping me with this kind of thing?

Andrew De Andrade
  • 3,606
  • 5
  • 32
  • 37

1 Answers1

0

I have successfully worked with trimpath[1], a javascript templating engine. Should get you there.

[1] http://code.google.com/p/trimpath/wiki/JavaScriptTemplates

Edit: Some additional information: It's maintained, very fast and defines the bare minimum, you can wrap your glue around it.

Another Edit: for more javascript template libraries, look here:

HTML Templates in Javascript? Without coding in the page?

Community
  • 1
  • 1
neurolabs
  • 542
  • 3
  • 8
  • good stuff. my only concern is that trimpath appears to use a template defined in your HTML code per the example they gave. In my case the forms (i.e. templates) do not exist on the page until the javascript writes them to the page. I need to dig in a bit more and see if I can save the entire template as a string in the javascript. This way it writes the complete template string to the page with ${placeholder} fields and then trimpath populates those fields in the subsequent lines of javascript. – Andrew De Andrade Nov 25 '10 at 18:49
  • You can use a javascript string with trimpath, see the link i provided and search for "myStr" – neurolabs Nov 25 '10 at 19:11