Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I'd like some comments, and any suggestions for where to go next with this that you have.

I've been working on developing a javascript library that allows for dynamic forms by simply adding some extra html tags and attributes to your form. It's brand new, so it doesn't have a lot of features, but it's based on the idea that you shouldn't need to write a bunch of javascript and have to deal with bugs and stuff just to get your form to have multiple pages or to add new fields when you click a button... stuff like that.

All you have to do to make it work is include jquery and this javascript in the page after all the form html.

...
<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js'></script>
<script type='text/javascript' src='edomform.js'></script>
</body>

I've got the current javascript in a fiddle with some example html and css, and some basic documentation/guide material in a google doc that you can comment on if you like. Any comments and suggestions are welcome.

You're also welcome to use this for whatever you want as-is or with any modifications you or anyone comes up with.

http://jsfiddle.net/Wp2Ue/1/
https://docs.google.com/document/d/1T08AJr4OGR2ohXLeSK3WjKn8zG-sSLi3Vz1Ya5tLkQY/edit?usp=sharing

Edit I'll also include the javascript here, just for ease of access I suppose.

    //Configuration variables
var config = jQuery("edfconfig");

function getConfigBoolean(attr) {
    if (config != null)
    return jQuery(config).attr(attr) != undefined;
}
function getConfigValue(attr) {
    if (config != null)
    return jQuery(config).attr(attr);
}

var noasterisks         = getConfigBoolean("noasterisks");
var addafter            = getConfigBoolean("addafter");
var doactions           = getConfigBoolean("doactions");
var noappend            = getConfigBoolean("noappend");
var requiredmessage     = getConfigValue("requiredmessage");
var requiredmessageid   = getConfigValue("requiredmessageid");


//eDomForm variables
var attrs = jQuery("edfvars")[0];
var variables = {};
if (attrs != null)
for (i=0;i<attrs.attributes.length;i++) {
    variables[attrs.attributes[i].nodeName] = attrs.attributes[i].nodeValue;
}

//Function because jQuery doesn't have a selector for the name attribute
function getByName(n) {
    return document.getElementsByName(n);
}

//required fields have the class required_field
var required = jQuery(".required_field");
//message div to display global form messages
var message = jQuery("#message");
//reference to the entire form itself
var form = jQuery("#form");

//form data
jQuery(form).data("required_empty",required.length);

//Add next and back buttons
jQuery(".form_page").each(function(i){
    jQuery(this).prepend('<button type="button" class="back">Back</button> <button type="button" class="next">Next</button>');
});

//Next and Back buttons
var pages = jQuery(".form_page");
var backButtons = jQuery(".back");
var nextButtons = jQuery(".next");
for (i=0;i<pages.length;i++) {
    if (i != pages.length-1) {
        nextButtons[i].onclick = function() {
            jQuery(this).closest("div").fadeOut();
            jQuery(this).closest("div").nextAll(":not(.disabled):first").fadeIn();
        };
    } else {
        jQuery(nextButtons[i]).remove();
    }
    if (i != 0) {
        backButtons[i].onclick = function(i) {
            jQuery(this).closest("div").fadeOut();
            jQuery(this).closest("div").prevAll(":not(.disabled):first").fadeIn();
        };
    } else {
        jQuery(backButtons[i]).remove();
    }
}

//Aliases
function getByAlias(a) {
    return jQuery("[alias="+a+"]");
}
function hasClass(element, cls) {
    return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
}

var aliases = jQuery(".alias");

for (i=0;i<aliases.length;i++) {
    var alias = jQuery(aliases[i]).attr("alias");
    var original = jQuery("."+alias);
    for (j=0;j<original.length;j++) {
        if (hasClass(original[j],"required_field")) {
            jQuery(aliases[i]).addClass("required_field");
        }
        original[j].onchange = aliasChange.bind(null,original[j],aliases[i]);
        aliases[i].onchange = aliasChange.bind(null,aliases[i],original[j]);
    }
}
function aliasChange(o,a) {
    a.value = o.value;
    a.onblur();
}
var radioGroupCounter = 1;

jQuery(document).ready(function() {
    //Prevent form submission if required fields have not been filled in
    if (form[0] != null)
    form[0].onsubmit = function() {
        var required_fields = document.getElementsByClassName("required_field");
        for (i=0;i<required_fields.length;i++) {
            if (required_fields[i].value == "") {
                jQuery("#"+requiredmessageid).html(requiredmessage);
                return false;
            }
        }
        jQuery("#"+requiredmessageid).html("");
        return true;
    };

    //Hidden pages
    function handleHiddenPages() {
        jQuery(".revealer").each(function(i){
            var page = jQuery(this).attr("page");
            jQuery(this).click(function(){
                if (jQuery(this).is(":checked")) {
                    jQuery("."+page).removeClass("disabled");
                } else {
                    jQuery("."+page).addClass("disabled");
                }
            });
        });
    }
    handleHiddenPages();

    //Switchers
    function handleSwitchers() {
        jQuery(".switcher").each(function(x){
            var connections = jQuery(this).attr("connections");
            connections = jQuery.parseJSON(connections);
            var connectedSections = {};
            for (var key in connections) {
                //if something like a-b
                if (connections[key].indexOf("-") > -1) {
                    var nums = connections[key].split("-");
                    var resultNums = [];
                    for (i=0;i<nums.length;i++) {
                        nums[i] = parseInt(nums[i]);
                    }
                    for (i=nums[0];i<=nums[nums.length-1];i++) {
                        resultNums.push(i+"");
                        connectedSections[i] = key;
                    }
                } else {
                    if (connections.hasOwnProperty(key))
                    connectedSections[connections[key]] = key;
                }
            }
            jQuery(this).change(function(){
                for (var key in connectedSections) {
                    jQuery("."+connectedSections[key]).hide();
                }
                jQuery("."+connectedSections[jQuery(this).val()]).show();
            });
        });
    }
    handleSwitchers();

    //Displayers/Hiders
    function handleDisplayers() {
        jQuery(".displayer").each(function(x){
            var connected = jQuery(this).attr("display");
            var special = "";
            var connecteds = [];
            if (connected.indexOf(" ") > -1) {
                connecteds = connected.split(" ");
                var special = connecteds[0];
                connected = connecteds[1];
            }
            var name = jQuery(this).attr("name");
            var group = getByName(name);
            jQuery(group).each(function() {
                jQuery(this).on("click",function() {
                var button = this;
                    if (jQuery(this).attr("display") != null) {
                        if (special == "") {
                            jQuery("."+connected).each(function() {
                                jQuery(this).show();
                            });
                        }
                        else if (special == "next") {
                            jQuery("."+connected).each(function() {
                                if (button.compareDocumentPosition(this) == 4) {
                                    jQuery(this).show();
                                    return false;
                                }
                            });
                        }
                        else if (special == "prev") {
                            jQuery(jQuery("."+connected).get().reverse()).each(function(i) {
                            if (button.compareDocumentPosition(this) == 2) {
                                jQuery(this).show();
                                return false;
                            }
                        });
                        }
                    }else {
                        if (special == "") {
                            jQuery("."+connected).each(function() {
                                jQuery(this).hide();
                            });
                        }
                        else if (special == "next")
                        jQuery("."+connected).each(function() {
                            if (button.compareDocumentPosition(this) == 4) {
                                jQuery(this).hide();
                                return false;
                            }
                        });
                        else if (special == "prev")
                        jQuery(jQuery("."+connected).get().reverse()).each(function(i) {
                            if (button.compareDocumentPosition(this) == 2) {
                                jQuery(this).hide();
                                return false;
                            }
                        });
                    }
                });
            });
        });
    }
    handleDisplayers();

    //findNext function from stackoverflow
    /**
     * Find the next element matching a certain selector. Differs from next() in
     *  that it searches outside the current element's parent.
     *  
     * @param selector The selector to search for
     * @param steps (optional) The number of steps to search, the default is 1
     * @param scope (optional) The scope to search in, the default is document wide 
     */
    $.fn.findNext = function(selector, steps, scope)
    {
        // Steps given? Then parse to int 
        if (steps)
        {
            steps = Math.floor(steps);
        }
        else if (steps === 0)
        {
            // Stupid case :)
            return this;
        }
        else
        {
            // Else, try the easy way
            var next = this.next(selector);
            if (next.length)
                return next;
            // Easy way failed, try the hard way :)
            steps = 1;
        }

        // Set scope to document or user-defined
        scope = (scope) ? $(scope) : $(document);

        // Find kids that match selector: used as exclusion filter
        var kids = this.find(selector);

        // Find in parent(s)
        hay = $(this);
        while(hay[0] != scope[0])
        {
            // Move up one level
            hay = hay.parent();     
            // Select all kids of parent
            //  - excluding kids of current element (next != inside),
            //  - add current element (will be added in document order)
            var rs = hay.find(selector).not(kids).add($(this));
            // Move the desired number of steps
            var id = rs.index(this) + steps;
            // Result found? then return
            if (id > -1 && id < rs.length)
                return $(rs[id]);
        }
        // Return empty result
        return $([]);
    }

    //Adding New Sections
    function handleAdds() {
        jQuery(".add").each(function(x){
            var add = jQuery(this).attr("add");
            if (add.indexOf(" ") > -1) {
                add = add.split(" ");
            }
            var to = jQuery(this).attr("to");
            var radiogroup = jQuery(this).attr("radiogroup");
            if (radiogroup != null)
            radiogroup = radiogroup.split(" ");
            var cpy = jQuery("<div />").append(jQuery("."+add).clone()).html();
            if (to == null) {
                jQuery(this).click(function() {
                    var text = cpy;
                    var counter = radioGroupCounter++;
                    if (radiogroup != null)
                    for (i=0;i<radiogroup.length;i++) {
                        var re = new RegExp(radiogroup[i]+"\\[\\d\\]","g");
                        text = text.replace(re,radiogroup[i]+"["+(counter)+"]");
                    }
                    if (addafter)
                    jQuery(this).after(text);
                    else
                    jQuery(this).before(text);

                    handleHiddenPages();
                    handleDisplayers();
                    handleSwitchers();
                });
            } else {
                if (to.indexOf(" ") > -1) {
                    to = to.split(" ");
                }
                jQuery(this).click(function() {
                    var text = cpy;
                    var counter = radioGroupCounter++;
                    if (radiogroup != null)
                    for (i=0;i<radiogroup.length;i++) {
                        var re = new RegExp(radiogroup[i]+"\\[\\d\\]","g");
                        text = text.replace(re,radiogroup[i]+"["+(counter)+"]");
                        console.log(text);
                    }
                    jQuery("#"+to).append(text);

                    handleHiddenPages();
                    handleDisplayers();
                    handleSwitchers();
                });
            }
        });
    }
    handleAdds();

    //Action tags


    function handleAll() {
        handleHiddenPages();
        handleDisplayers();
        handleSwitchers();
        handleAdds();
    }
});

required = jQuery(".required_field");

//Loop through required fields, adding the onblur event
//so that whenever the user deselects a required field,
//if it is blank the asterisk will turn red.
for (i=0;i<required.length;i++) {
    jQuery(required[i]).after("<span>*</span>");
    jQuery(required[i]).data("empty",true);
    required[i].onblur = function() {
        if (this.value == "") {
            jQuery(this).next().css("color","#f00");
        } else {
            jQuery(this).next().css("color","#000");
        }
    };
}
share|improve this question
add comment

Know someone who can answer? Share a link to this question via email, Google+, Twitter, or Facebook.

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.