Form data compilation for display
Type A Type B

var frm = new form();

           frm.addFieldset('general', 'General');
           textfield = new text();
           textfield.set_name('title');
           textfield.set_id('mod_lesson_title_' + pageid);
           textfield.set_label('Page Title');
           textfield.set_required();
           textfield.set_text(lesson.pages[pageid].title);
           frm.addElement(textfield);
           selectfield = new selectElement();
           selectfield.set_name('Jump_1');
           selectfield.set_label('Jumps');
           selectfield.set_id("mod_lesson_jump_1_" + pageid);
           selectfield.set_options(joptions);
           frm.addElement(selectfield);
           $.when(frm.printForm()).then(function(tempformstuff) {
               $('.mod_lesson_pages').append(tempformstuff); 
               $('#mod_lesson_editor_save_btn').click(function() {
                   // Could do client side validation here.
                   if ($("#mod_lesson_title_" + pageid).val() == "") {
                       var textelement = $("#fitem_mod_lesson_title_" + pageid);
                       frm.handleError('title', textelement, 'text', 'Title should not be empty');
                   } else {
                       lesson.pages[pageid].save_edit_form(frm);
                   }
               });
               $('#mod_lesson_editor_cancel_btn').click(function() {
                   $('.mod_lesson_page_editor').remove();
               });
           });

var formdata = {

               lessonpagetype: lesson.pages[pageid].qtypestring,
               pageid: pageid,
               title: {
                   id: "mod_lesson_title_" + pageid,
                   label: "Page Title",
                   name: "title",
                   text: lesson.pages[pageid].title,
                   required: 1
               },
               contents: lesson.pages[pageid].contents,
               select: {
                   id: pageid,
                   label: "Jumps",
                   name: "Jump_1",
                   options: formfactory.formatOptions(joptions),
                   helpButton: "<button type=\"button\">Help is here</button>"
               }
           };
           $.when(templates.render('mod_lesson/page_editor', formdata)).done(function(pageeditor) {
               $('.mod_lesson_pages').append(pageeditor); 
               $('#mod_lesson_editor_save_btn').click(function() {
                   // Do client side validation.
                   var titleelement = $("#mod_lesson_title_" + pageid);
                   if (titleelement.val() == "") {
                       var errors = {
                           errors: {
                               name: "title",
                               message: "The lesson page title should not be empty"
                           }
                       };
                       formfactory.handleErrors(errors, formdata);
                   } else {
                       lesson.pages[pageid].save_edit_form(formdata);
                   }
               });
               $('#mod_lesson_editor_cancel_btn').click(function() {
                   $('.mod_lesson_page_editor').remove();
               });
           });

Template for a select element

Same for both.

       <label {{#hiddenLabel}}class="accesshide"Adrian Greeve/form comparison/hiddenLabel for="Template:id">
           Template:label
           {{#required}}{{>core/form-required}}Adrian Greeve/form comparison/required
           {{#advanced}}{{>core/form-advanced}}Adrian Greeve/form comparison/advanced
       </label>
       {{{helpButton}}}

Form template
Type A Type B

{{!

   @template mod_lesson/page_editor

}}

<form action="">

Edit this Template:lessonpagetype

   {{#title}}
       {{>core/form-element-text}}
   Adrian Greeve/form comparison/title
Page Content
   {{#select}}    
       {{>core/form-element-select}}
   Adrian Greeve/form comparison/select    
       <button type="button" id="mod_lesson_editor_save_btn">Save</button>
       <button type="button" id="mod_lesson_editor_cancel_btn">Cancel</button>

</form>

Library
Type A Type B

define(['jquery', 'core/templates'], function($, templates) {

   var Form = function() {
       this._fieldsets = {};
       this.elements = {};
       this.formPage = ;
   };
   // These two methods would actually be using classes for the form.
   Form.prototype.add_top = function() {
this.formPage += '
<form action="">';
   };
   Form.prototype.add_bottom = function() {
this.formPage += '
<button type="button" id="mod_lesson_editor_save_btn">Save</button>'; this.formPage += '<button type="button" id="mod_lesson_editor_cancel_btn">Cancel</button>
</form>
';
   };


   Form.prototype.addFieldset = function(key, title) {
       this._fieldsets[key] = title;
   };
   Form.prototype.handleError = function(errorname, errorelement, elementtype, errormessage) {
       var index = elementtype + "-" + errorname;
       this.elements[index].set_error(errormessage);
       var htmlpromise = templates.render(this.elements[index].template, this.elements[index]);
       $.when(htmlpromise).then(function(newhtml) {
           templates.replaceNode(errorelement, newhtml);
       });
   }
   Form.prototype.handleErrors = function(errors) {
       // Need to loop through all potential errors.
       var errorname = errors.errors.name;
       var errorelementid = $(":input[name=" + errorname + "]").attr("id");
       // console.log(errorelementid);
       var errorelement = $("#fitem_" + errorelementid);
       // console.log(errorelement);
       // Get the form element type.
       var elementtype = errorelement.attr("data-field-type");
       Form.prototype.handleError.call(this, errorname, errorelement, elementtype, errors.errors.message);
   }


   Form.prototype.addElement = function(element) {
       var index = element.type + "-" + element.name;
       this.elements[index] = element;
   };
   Form.prototype.showElements = function() {
       console.log(this.elements);
   };
   Form.prototype.printForm = function() {
       var allpromises = [];
       for (index in this.elements) {
           allpromises.push(this.elements[index].show());
       }
       return $.when.apply($.when, allpromises).then(function() {
           Form.prototype.add_top.call(this);
           var schema = arguments;
           for (index in schema) {
               this.formPage += schema[index][0];
           }
           Form.prototype.add_bottom.call(this);
           return this.formPage;
       }, function() {
          return 'default html'; 
       });
   }
   return Form;

});

define(['jquery', 'core/templates'], function($, templates) {

   var formData;
   return {
       handleErrors: function(errors, formdata) {
           // name attribute of the error.
           var errorname = errors.errors.name;
           var templatedata;
           for (index in formdata) {
               if (typeof formdata[index] == "object") {
                   if (formdata[index].name == errorname) {
                       formdata[index].error = errors.errors.message;
                       templatedata = formdata[index];
                   }
               }
           }
           // for (index in errors.errors) {
           //     console.log(errors.errors["name"]);
           // }
           // Need to loop through all potential errors.
           var errorelementid = $(":input[name=" + errorname + "]").attr("id");
           // console.log(errorelementid);
           var errorelement = $("#fitem_" + errorelementid);
           // console.log(errorelement);
           // Get the form element type.
           var elementtype = errorelement.attr("data-field-type");
           // console.log(elementtype);
           var template = 'core/form-element-' + elementtype;
           var templatepromise = templates.render(template, templatedata);
           $.when(templatepromise).then(function(newhtml) {
               templates.replaceNode(errorelement, newhtml);
           });
       },
       getFormData: function() {
           formData = $('form').serializeArray();
           var tempstorage = {};
           for (index in formData) {
               var name = formData[index].name;
               if (name !== 'query') {
                   tempstorage[name] = formData[index].value;
               }
           }
           return tempstorage;
       },
       /**
        * Format a normal array into an object for a select form element.
        *
        * @param {array} options An array of options.
        * @param {string} selected The selected option. Needs to match the array index.
        * @return {object} An options object that can be used with a select form element.
        */
       formatOptions: function(options, selected) {
           var returnoptions = [];
           var select = 0;
           if (selected !== 'undefined') {
               select = selected
           }
           for (index in options) {
               if (index == selected) {
                   returnoptions.push({
                       value: index,
                       text: options[index],
                       selected: select
                   });
               } else {
                   returnoptions.push({
                       value: index,
                       text: options[index],
                   });
               }
           }
           return returnoptions;
       }
   };

});