views:

58

answers:

2

I've seen a lot of help for dynamically adding rows or fields, but I'm interested in controlling fields that are dependent on one another.

For example, I have a form with 3 user inputs:

<select id="foo">
  <option value="0">No</option>
  <option value="1">Yes</option>
</select>

When #foo's value is set to 1, I'd like to enable #bar.

<!-- by default, bar should be disabled -->
<select id="bar">
  <option value="something_1">Something 1</option>
  <option value="something_2">Something 2</option>
  <option value="other">Other...</option>
</select>

When #bar's value is set to other, I'd like to enable #baz.

<!-- by default, baz should be disabled -->
<textarea id="baz"></textarea>

My Goal

I'd like to some guidance on writing a small plugin that allows easy creation of form inputs with dependencies.

I'd like short, concise syntax. Is there a way I could add html attribute helpers to aid the jQuery plugin in "automating" things?

Foreseeable Issues

  1. If #foo is set to "Yes", then #bar is set to "other", then #foo is set to "No", I will want #bar's dependencies deactivated/hidden as well.
  2. Inputs are enabled/disabled and/or visible/hidden; Having the ability to define custom behaviors for elements would be nice.

Reinventing the Wheel

If there's a plugin out there that does this kind of thing, let me know! I couldn't seem to find one...

+1  A: 

You'll want to focus on event handling on the .change() event as your entry point. The handler can look up the form element id and value in a JSON structure to decide what, if any, actions need to happen. The javascript might look like this:

form = {"input1" : 
    {"value1": {
        /*action list */
        [{"hide": ["input2", "input3"], "show": ["input4"], "set": {"input5": "True", "input6": "False"}]
    },
    "value2": {[/* another set of actions */]}
}


function onchange(e) {
    id = $(this).attr("id");
    value = $(this).val();
    if (id in form) {
        if (value in form[id]) {
            $.each(form[id][value], function(i, action) {
                if ("hide" in action) { $(action).hide(); }
                /* etc for other actions */
            });
        }
    }
}

$(document).ready(function() {$("input").change(onchange);}
Ian Wetherbee
Ian, this is a fair start but the `form` variable gets really messy as soon as you start including a lot of options... I took this and worked with it and came up with something pretty elegant. I'll be posting it soon.
macek
A: 

A quick plugin

(function($){

  $.fn.inputDependsOn = function(id, values, options){

    var self = this;

    // methods
    this.disable = function(e){
      return e.addClass(options.cssClass).attr({disabled: true}).trigger("disable");
    };

    this.enable = function(e){
      return e.removeClass(options.cssClass).attr({disabled: null}).trigger("enable");
    };

    // options
    options = $.extend({}, $.fn.dependsOn.defaults, options || {});

    var parent = $(id);

    this.each(function(){
      var child = $(this);

      // parent binds
      parent
        .bind("change", function(){
          var v = parent.val();
          if(parent.is(":not(:disabled)") && v in values){
            self[values[v]](child);
          }
          else {
            self[options.init](child);
          }
          child.change();
        })
        .bind("disable", function(){
          self.disable(child);
        })
      ;
    });

    // init
    parent.change();
    return this;
  };

  $.fn.dependsOn.defaults = {
    init: "disable",
    cssClass: "disabled"
  };

})(jQuery);

Using the HTML in the original question, goal can be accomplished with:

$("#bar").inputDependsOn("#foo", {"1": "enabled"});
$("#baz").inputDependsOn("#bar", {"other": "enable"});

This plugin will be maintained and update here:

github.com/macek/jquery-input-depends-on

macek