Skip to main content
deleted 8 characters in body; edited tags
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

Would this be useful to you? What other functionality should I include? Any refactoring or structure changes that I should make?

New - I am worried about exposing 4 different functions. Is this too many?

  1. Would this be useful to you?
  2. What other functionality should I include?
  3. Any refactoring or structure changes that I should make?
  4. I am worried about exposing 4 different functions. Is this too many?
  • useUse as jQuery plugin
  • easyEasy to chain rules together
  • understandableUnderstandable by reading a line of code
  • canCan build/add custom conditions

Would this be useful to you? What other functionality should I include? Any refactoring or structure changes that I should make?

New - I am worried about exposing 4 different functions. Is this too many?

  • use as jQuery plugin
  • easy to chain rules together
  • understandable by reading a line of code
  • can build/add custom conditions
  1. Would this be useful to you?
  2. What other functionality should I include?
  3. Any refactoring or structure changes that I should make?
  4. I am worried about exposing 4 different functions. Is this too many?
  • Use as jQuery plugin
  • Easy to chain rules together
  • Understandable by reading a line of code
  • Can build/add custom conditions
Rolled back edit that invalidated answers
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

Need a review of a jQuery plugin Plugin that conditionally displays elements based on form values [UPDATE]

ADDED CODE UPDATES

  • You can use two syntaxes with reactIf() (Hat tip: RoToRa)

    1. supply a function or helper, as original, or

    2. reference a helper with a string followed by arguments

      $('.cities')
      .reactIf($('#zip'), IS.NotBlank) .reactIf('#zip', 'Between', 19100, 19400);

  • helpers use this instead of $(this) (Hat tip: RoToRa)

  • checks for a data reference instead of class to find if initialized (still adds class) (Hat tip: RoToRa)

  • short-circuiting the $.each() loop (Hat tip: RoToRa)

  • verified using jquery objects as well as selector strings to find the element to watch (Hat tip: meo)

Links

Git Hub: https://github.com/natedavisolds/react.js

Here's the demo page: http://natedavisolds.com/workshop/react.js/demo/react.htmlHere's the demo page

  • use as jQuery pluinplugin
  • easy to chain rules together
  • understandable by reading a line of code
  • can build/add custom conditions
$('.elements_to_display')
   .reactIf( '#some_form_element', SatisfiesFirstCondition)
   .reactIf( '#some_other_form_element', 'SatisfiesAnotherCondition'SatisfiesAnotherCondition)
   .reactIf( '#some_other_form_element', 'SatisfiesAnotherCondition', argsSatisfiesAnotherCondition);

The Code

Page JS [UPDATED]

var IS = $.extend({}, $.fn.reactor.helpers);
  
$('.cities')    
    .reactIf('#zip', 'Between', IS.Between(19100, 19400))
    .reactIf($('#zip'), IS.NotBlank);
        
$('.philly_middle_to_low_income')
    .reactIf('#income_2011', 'LessThan', IS.LessThan(40000))
    .reactIf($('#cities_select'), IS.EqualTo('philadelphia'));
        
$('.low_income_select_zips')
    .reactIf('#income_2011', IS.LessThan(15000))
    .reactIf('#zip', 'Between', IS.BetweenSameLength(19000, 20000))
    .reactIf($('#zip'), IS.NotBlank);
        
$('.reactor').trigger('change.reactor');

Plugin react.js [UPDATED]

 (function($){
    
    $.fn.reactTo = function(selector) {
        var $elements = $(selector),
            $reactor_element = $(this),
            _proxy_event = function() {
                $reactor_element.trigger('change.reactor');
            };

        $elements.filter('select').bind('change.reactor', _proxy_event);
        $elements.filter('input').bind('keyup.reactor', _proxy_event);  
            
        return this;
    };

    $.fn.reactIf = function(sel, exp_func) {
    
        var $sel = $(sel);   
        var args = Array.prototype.slice.call( arguments, 2 );
        
        var _func = function() {
            if ($.isFunction(exp_func)) {
               return exp_func.apply($sel);                               
            } else {
               var _returned = $.fn.reactor.helpers[exp_func].apply($sel, args);
               
               if ($.isFunction(_returned)) {
                  return _returned.apply($sel)
               } else {
                  return _returned;
               }
               
            }
        };
        
        this.each(function() {
            if (!$(this).hasClass('reactor')) { $(this).reactor(); }
            
            var conditions_arry = $(this).data('conditions.reactor');
            if (!$.isArray(conditions_arry)) { conditions_arry = []};
           
            conditions_arry.push(_func);

            $(this).data('conditions.reactor', conditions_arry);
        }); 

        $(this).reactTo(sel);
        
        return this;
    };
    
    $.fn.react = function() {
        
        this.each(function() {
           $(this).trigger('change.reactor')
        }); 

        return this;
    };
    
    $.fn.reactor = function(options) {
        var settings = $.extend({}, $.fn.reactor.defaults, options);
        
        this.each(function() {
            // var opts = $.meta ? $.extend({}, settings, $this.data()) : settings;
            
            var $element = $(this);
            
            if (!$.isArray($element.datahasClass('conditions.reactor')'reactor')) { $element.data('conditions.reactor', []).addClass('reactor'); }
                        
            var isReactionaryis_reactionary = function() {  
                var conditionalArray = $(this).data('conditions.reactor'); 
                var r = true;
                                
                $.each(conditionalArray, function() {
                    r = (r && this.call());
                    return r; // short circuits the loop when any value is false
                });
                
                
                
                return r;                                
            }
            
            var reaction = function(evt) {
                evt.stopPropagation();
                if (isReactionaryis_reactionary.apply(this)) {
                   settings.compliant.apply($element);
                } else {
                   settings.uncompliant.apply($element);
                }
            }
        
            $element.bind('change.reactor', reaction);
        });
                    
        return this;  
    };

    $.fn.reactor.defaults = {
        compliant: function() {
            $(this).show();
        },
        uncompliant: function() {
            $(this).hide();    
        }        
    };
    
    $.fn.reactor.helpers = {
    
        NotBlank: function() {
            return( $(this).val().toString() != "" )
        },
        
        Blank: function() {
            return( $(this).val().toString() == "" )
        },
        
        Disabled: function() {
            return( this.filter(':disable').length > 0 );
        },
        
        Enabled: function() {
            return( this.filter(':enabled').length > 0 );
        },
        
        EqualTo: function(matchStr) {
            var _func = function() { 
                var v = $(this).val();
                if (v) { return( v.toString() == matchStr ); } 
                else { return false; }
            } 
            return _func;
        },
                    
        LessThan: function(number) {
            var _func = function() {
                var v = $(this).val();
                return(!(v && parseInt(v) > number));
            }
            return _func;   
        },
            
        MoreThan: function(number) {
            var _func = function() {
                var v = $(this).val();
                return(!(v && parseInt(v) < number));
            }
            return _func;  
        },
                
        Between: function(min, max) {
            var _func = function() {
                var v = $(this).val();
                return(!(v && (parseInt(v) > max || parseInt(v) < min)));
            }
            return _func;
        },
            
        BetweenSameLength: function(min, max) {
            var len = min.toString().length;
            var _func = function() {
                var v = $(this).val();
                return(!(v && v.length == len && (parseInt(v) > max || parseInt(v) < min)));
            }
            return _func;
        }
    };

})(jQuery);
<form id="portfolio_form">
    <fieldset>
        
        <label>Zip</label>
        <input id="zip" type="text" value="" /><br />
        
        <label>2011 Income</label>
        <input id="income_2011" name="income[2011]" />
       
    </fieldset>  
    
    <p>Display cities only when zip is between 19100 and 19400</p>
   
    <fieldset class="cities">
        <label>Cities</label>
        <select id="cities_select">
            <option value=""></option>
            <option value="philadelphia">Philadelphia</option>
            <option value="media">Media</option>
            <option value="doylestown">Doylestown</option>
        </select>    
    </fieldset>
    
    <p>Display checkboxes only for Philadelphia and income less than 40000</p>
    <fieldset class="philly_middle_to_low_income">
        <input type="checkbox" /> Check One<br />
        <input type="checkbox" /> Check Two<br />
        <input type="checkbox" /> Check Three<br />
        <input type="checkbox" /> Check Four<br />
    </fieldset>   
   
   <p>Display checkboxes when zip is between 19000 and 20000 and income is lower than 15000<25000</p>
   <fieldset class="low_income_select_zips">
        <input type="checkbox" /> Check One<br />
        <input type="checkbox" /> Check Two<br />
        <input type="checkbox" /> Check Three<br />
        <input type="checkbox" /> Check Four<br />
    </fieldset>    
    
</form>

Need a review of a jQuery plugin that conditionally displays elements based on form values [UPDATE]

ADDED CODE UPDATES

  • You can use two syntaxes with reactIf() (Hat tip: RoToRa)

    1. supply a function or helper, as original, or

    2. reference a helper with a string followed by arguments

      $('.cities')
      .reactIf($('#zip'), IS.NotBlank) .reactIf('#zip', 'Between', 19100, 19400);

  • helpers use this instead of $(this) (Hat tip: RoToRa)

  • checks for a data reference instead of class to find if initialized (still adds class) (Hat tip: RoToRa)

  • short-circuiting the $.each() loop (Hat tip: RoToRa)

  • verified using jquery objects as well as selector strings to find the element to watch (Hat tip: meo)

Links

Git Hub: https://github.com/natedavisolds/react.js

Here's the demo page: http://natedavisolds.com/workshop/react.js/demo/react.html

  • use as jQuery pluin
  • easy to chain rules together
  • understandable by reading a line of code
  • can build/add custom conditions
$('.elements_to_display')
   .reactIf( '#some_form_element', SatisfiesFirstCondition)
   .reactIf( '#some_other_form_element', 'SatisfiesAnotherCondition')
   .reactIf( '#some_other_form_element', 'SatisfiesAnotherCondition', args);

The Code

Page JS [UPDATED]

var IS = $.extend({}, $.fn.reactor.helpers);
  
$('.cities')    
   .reactIf('#zip', 'Between', 19100, 19400)
   .reactIf($('#zip'), IS.NotBlank);
        
$('.philly_middle_to_low_income')
    .reactIf('#income_2011', 'LessThan', 40000)
    .reactIf($('#cities_select'), IS.EqualTo('philadelphia'));
        
$('.low_income_select_zips')
    .reactIf('#income_2011', IS.LessThan(15000))
    .reactIf('#zip', 'Between', 19000, 20000)
    .reactIf($('#zip'), IS.NotBlank);
        
$('.reactor').trigger('change.reactor');

Plugin react.js [UPDATED]

 (function($){
    
    $.fn.reactTo = function(selector) {
        var $elements = $(selector),
            $reactor_element = $(this),
            _proxy_event = function() {
                $reactor_element.trigger('change.reactor');
            };

        $elements.filter('select').bind('change.reactor', _proxy_event);
        $elements.filter('input').bind('keyup.reactor', _proxy_event);  
            
        return this;
    };

    $.fn.reactIf = function(sel, exp_func) {
    
        var $sel = $(sel);   
        var args = Array.prototype.slice.call( arguments, 2 );
        
        var _func = function() {
            if ($.isFunction(exp_func)) {
               return exp_func.apply($sel);                               
            } else {
               var _returned = $.fn.reactor.helpers[exp_func].apply($sel, args);
               
               if ($.isFunction(_returned)) {
                  return _returned.apply($sel)
               } else {
                  return _returned;
               }
               
            }
        };
        
        this.each(function() {
            if (!$(this).hasClass('reactor')) { $(this).reactor(); }
            
            var conditions_arry = $(this).data('conditions.reactor');
            if (!$.isArray(conditions_arry)) { conditions_arry = []};
           
            conditions_arry.push(_func);

            $(this).data('conditions.reactor', conditions_arry);
        }); 

        $(this).reactTo(sel);
        
        return this;
    };
    
    $.fn.react = function() {
        
        this.each(function() {
           $(this).trigger('change.reactor')
        }); 

        return this;
    };
    
    $.fn.reactor = function(options) {
        var settings = $.extend({}, $.fn.reactor.defaults, options);
        
        this.each(function() {
            // var opts = $.meta ? $.extend({}, settings, $this.data()) : settings;
            
            var $element = $(this);
            
            if (!$.isArray($element.data('conditions.reactor'))) { $element.data('conditions.reactor', []).addClass('reactor'); }
                        
            var isReactionary = function() {  
                var conditionalArray = $(this).data('conditions.reactor'); 
                var r = true;
                                
                $.each(conditionalArray, function() {
                    r = this.call();
                    return r; // short circuits the loop when any value is false
                });
                
                return r;                                
            }
            
            var reaction = function(evt) {
                evt.stopPropagation();
                if (isReactionary.apply(this)) {
                   settings.compliant.apply($element);
                } else {
                   settings.uncompliant.apply($element);
                }
            }
        
            $element.bind('change.reactor', reaction);
        });
                    
        return this;  
    };

    $.fn.reactor.defaults = {
        compliant: function() {
            $(this).show();
        },
        uncompliant: function() {
            $(this).hide();    
        }        
    };
    
    $.fn.reactor.helpers = {
    
        NotBlank: function() {
            return( this.val().toString() != "" )
        },
        
        Blank: function() {
            return( this.val().toString() == "" )
        },
        
        Disabled: function() {
            return( this.filter(':disable').length > 0 );
        },
        
        Enabled: function() {
            return( this.filter(':enabled').length > 0 );
        },
        
        EqualTo: function(matchStr) {
            var _func = function() { 
                var v = this.val();
                if (v) { return( v.toString() == matchStr ); } 
                else { return false; }
            } 
            return _func;
        },
                    
        LessThan: function(number) {
            var _func = function() {
                var v = this.val();
                return(!(v && parseInt(v) > number));
            }
            return _func;   
        },
            
        MoreThan: function(number) {
            var _func = function() {
                var v = this.val();
                return(!(v && parseInt(v) < number));
            }
            return _func;  
        },
                
        Between: function(min, max) {
            var _func = function() {
                var v = this.val();
                return(!(v && (parseInt(v) > max || parseInt(v) < min)));
            }
            return _func;
        },
            
        BetweenSameLength: function(min, max) {
            var len = min.toString().length;
            var _func = function() {
                var v = this.val();
                return(!(v && v.length == len && (parseInt(v) > max || parseInt(v) < min)));
            }
            return _func;
        }
    };

})(jQuery);
<form id="portfolio_form">
    <fieldset>
        
        <label>Zip</label>
        <input id="zip" type="text" value="" /><br />
        
        <label>2011 Income</label>
        <input id="income_2011" name="income[2011]" />
       
    </fieldset>  
    
    <p>Display cities only when zip is between 19100 and 19400</p>
   
    <fieldset class="cities">
        <label>Cities</label>
        <select id="cities_select">
            <option value=""></option>
            <option value="philadelphia">Philadelphia</option>
            <option value="media">Media</option>
            <option value="doylestown">Doylestown</option>
        </select>    
    </fieldset>
    
    <p>Display checkboxes only for Philadelphia and income less than 40000</p>
    <fieldset class="philly_middle_to_low_income">
        <input type="checkbox" /> Check One<br />
        <input type="checkbox" /> Check Two<br />
        <input type="checkbox" /> Check Three<br />
        <input type="checkbox" /> Check Four<br />
    </fieldset>   
   
   <p>Display checkboxes when zip is between 19000 and 20000 and income is lower than 15000</p>
   <fieldset class="low_income_select_zips">
        <input type="checkbox" /> Check One<br />
        <input type="checkbox" /> Check Two<br />
        <input type="checkbox" /> Check Three<br />
        <input type="checkbox" /> Check Four<br />
    </fieldset>    
    
</form>

Plugin that conditionally displays elements based on form values

Here's the demo page

  • use as jQuery plugin
  • easy to chain rules together
  • understandable by reading a line of code
  • can build/add custom conditions
$('.elements_to_display')
   .reactIf( '#some_form_element', SatisfiesFirstCondition)
   .reactIf( '#some_other_form_element', SatisfiesAnotherCondition)
   .reactIf( '#some_other_form_element', SatisfiesAnotherCondition);

Page JS

var IS = $.extend({}, $.fn.reactor.helpers);
  
$('.cities')    
    .reactIf('#zip', IS.Between(19100, 19400))
    .reactIf('#zip', IS.NotBlank);
        
$('.philly_middle_to_low_income')
    .reactIf('#income_2011', IS.LessThan(40000))
    .reactIf('#cities_select', IS.EqualTo('philadelphia'));
        
$('.low_income_select_zips')
    .reactIf('#income_2011', IS.LessThan(15000))
    .reactIf('#zip', IS.BetweenSameLength(19000, 20000))
    .reactIf('#zip', IS.NotBlank);
        
$('.reactor').trigger('change.reactor');

Plugin react.js

(function($){
    
    $.fn.reactTo = function(selector) {
        var $elements = $(selector),
            $reactor_element = $(this),
            _proxy_event = function() {
                $reactor_element.trigger('change.reactor');
            };

        $elements.filter('select').bind('change.reactor', _proxy_event);
        $elements.filter('input').bind('keyup.reactor', _proxy_event);  
            
        return this;
    };

    $.fn.reactIf = function(sel, exp_func) {
    
        var $sel = $(sel);
        var _func = function() {
            return exp_func.apply($sel);                               
        };
        
        this.each(function() {
            if (!$(this).hasClass('reactor')) { $(this).reactor(); }
            
            var conditions_arry = $(this).data('conditions.reactor');
            if (!$.isArray(conditions_arry)) { conditions_arry = []};
           
            conditions_arry.push(_func);

            $(this).data('conditions.reactor', conditions_arry);
        }); 

        $(this).reactTo(sel);
        
        return this;
    };
    
    $.fn.react = function() {
        
        this.each(function() {
           $(this).trigger('change.reactor')
        }); 

        return this;
    };
    
    $.fn.reactor = function(options) {
        var settings = $.extend({}, $.fn.reactor.defaults, options);
        
        this.each(function() {
            // var opts = $.meta ? $.extend({}, settings, $this.data()) : settings;
            
            var $element = $(this);
            
            if (!$element.hasClass('reactor')) { $element.data('conditions.reactor', []).addClass('reactor'); }
                        
            var is_reactionary = function() {  
                var conditionalArray = $(this).data('conditions.reactor'); 
                var r = true;
                                
                $.each(conditionalArray, function() {
                    r = (r && this.call());
                });
                
                
                
                return r;                                
            }
            
            var reaction = function(evt) {
                evt.stopPropagation();
                if (is_reactionary.apply(this)) {
                   settings.compliant.apply($element);
                } else {
                   settings.uncompliant.apply($element);
                }
            }
        
            $element.bind('change.reactor', reaction);
        });
                    
        return this;  
    };

    $.fn.reactor.defaults = {
        compliant: function() {
            $(this).show();
        },
        uncompliant: function() {
            $(this).hide();    
        }        
    };
    
    $.fn.reactor.helpers = {
    
        NotBlank: function() {
            return( $(this).val().toString() != "" )
        },
        
        Blank: function() {
            return( $(this).val().toString() == "" )
        },
        
        EqualTo: function(matchStr) {
            var _func = function() { 
                var v = $(this).val();
                if (v) { return( v.toString() == matchStr ); } 
                else { return false; }
            } 
            return _func;
        },
            
        LessThan: function(number) {
            var _func = function() {
                var v = $(this).val();
                return(!(v && parseInt(v) > number));
            }
            return _func;   
        },
            
        MoreThan: function(number) {
            var _func = function() {
                var v = $(this).val();
                return(!(v && parseInt(v) < number));
            }
            return _func;  
        },
                
        Between: function(min, max) {
            var _func = function() {
                var v = $(this).val();
                return(!(v && (parseInt(v) > max || parseInt(v) < min)));
            }
            return _func;
        },
            
        BetweenSameLength: function(min, max) {
            var len = min.toString().length;
            var _func = function() {
                var v = $(this).val();
                return(!(v && v.length == len && (parseInt(v) > max || parseInt(v) < min)));
            }
            return _func;
        }
    };

})(jQuery);
<form id="portfolio_form">
    <fieldset>
        
        <label>Zip</label>
        <input id="zip" type="text" value="" /><br />
        
        <label>2011 Income</label>
        <input id="income_2011" name="income[2011]" />
       
    </fieldset>  
    
    <p>Display cities only when zip is between 19100 and 19400</p>
   
    <fieldset class="cities">
        <label>Cities</label>
        <select id="cities_select">
            <option value=""></option>
            <option value="philadelphia">Philadelphia</option>
            <option value="media">Media</option>
            <option value="doylestown">Doylestown</option>
        </select>    
    </fieldset>
    
    <p>Display checkboxes only for Philadelphia and income less than 40000</p>
    <fieldset class="philly_middle_to_low_income">
        <input type="checkbox" /> Check One<br />
        <input type="checkbox" /> Check Two<br />
        <input type="checkbox" /> Check Three<br />
        <input type="checkbox" /> Check Four<br />
    </fieldset>   
   
   <p>Display checkboxes when zip is between 19000 and 20000 and income is lower than 25000</p>
   <fieldset class="low_income_select_zips">
        <input type="checkbox" /> Check One<br />
        <input type="checkbox" /> Check Two<br />
        <input type="checkbox" /> Check Three<br />
        <input type="checkbox" /> Check Four<br />
    </fieldset>    
    
</form>
Tweeted twitter.com/#!/StackCodeReview/status/90216357014155265
added 985 characters in body; edited title
Source Link

Need a review of a jQuery plugin that conditionally displays elements based on form values [UPDATE]

ADDED CODE UPDATES

  • You can use two syntaxes with reactIf() (Hat tip: RoToRa)

    1. supply a function or helper, as original, or

    2. reference a helper with a string followed by arguments

      $('.cities')
      .reactIf($('#zip'), IS.NotBlank) .reactIf('#zip', 'Between', 19100, 19400);

  • helpers use this instead of $(this) (Hat tip: RoToRa)

  • checks for a data reference instead of class to find if initialized (still adds class) (Hat tip: RoToRa)

  • short-circuiting the $.each() loop (Hat tip: RoToRa)

  • verified using jquery objects as well as selector strings to find the element to watch (Hat tip: meo)

Links

Git Hub: https://github.com/natedavisolds/react.js

$('.elements_to_display')
   .reactIf( '#some_form_element', SatisfiesFirstCondition)
   .reactIf( '#some_other_form_element', SatisfiesAnotherCondition'SatisfiesAnotherCondition')
   .reactIf( '#some_other_form_element', SatisfiesAnotherCondition'SatisfiesAnotherCondition', args);

Page JS [UPDATED]

var IS = $.extend({}, $.fn.reactor.helpers);
  
$('.cities')    
    .reactIf('#zip', IS.Between('Between', 19100, 19400))
    .reactIf($('#zip'), IS.NotBlank);
        
$('.philly_middle_to_low_income')
    .reactIf('#income_2011', IS.LessThan('LessThan', 40000))
    .reactIf($('#cities_select'), IS.EqualTo('philadelphia'));
        
$('.low_income_select_zips')
    .reactIf('#income_2011', IS.LessThan(15000))
    .reactIf('#zip', IS.BetweenSameLength('Between', 19000, 20000))
    .reactIf($('#zip'), IS.NotBlank);
        
$('.reactor').trigger('change.reactor');

Plugin react.js [UPDATED]

 (function($){
    
    $.fn.reactTo = function(selector) {
        var $elements = $(selector),
            $reactor_element = $(this),
            _proxy_event = function() {
                $reactor_element.trigger('change.reactor');
            };

        $elements.filter('select').bind('change.reactor', _proxy_event);
        $elements.filter('input').bind('keyup.reactor', _proxy_event);  
            
        return this;
    };

    $.fn.reactIf = function(sel, exp_func) {
    
        var $sel = $(sel);   
        var args = Array.prototype.slice.call( arguments, 2 );
        
        var _func = function() {
            if ($.isFunction(exp_func)) {
               return exp_func.apply($sel);                               
            } else {
               var _returned = $.fn.reactor.helpers[exp_func].apply($sel, args);
               
               if ($.isFunction(_returned)) {
                  return _returned.apply($sel)
               } else {
                  return _returned;
               }
               
            }
        };
        
        this.each(function() {
            if (!$(this).hasClass('reactor')) { $(this).reactor(); }
            
            var conditions_arry = $(this).data('conditions.reactor');
            if (!$.isArray(conditions_arry)) { conditions_arry = []};
           
            conditions_arry.push(_func);

            $(this).data('conditions.reactor', conditions_arry);
        }); 

        $(this).reactTo(sel);
        
        return this;
    };
    
    $.fn.react = function() {
        
        this.each(function() {
           $(this).trigger('change.reactor')
        }); 

        return this;
    };
    
    $.fn.reactor = function(options) {
        var settings = $.extend({}, $.fn.reactor.defaults, options);
        
        this.each(function() {
            // var opts = $.meta ? $.extend({}, settings, $this.data()) : settings;
            
            var $element = $(this);
            
            if (!$.isArray($element.hasClassdata('reactor''conditions.reactor'))) { $element.data('conditions.reactor', []).addClass('reactor'); }
                        
            var is_reactionaryisReactionary = function() {  
                var conditionalArray = $(this).data('conditions.reactor'); 
                var r = true;
                                
                $.each(conditionalArray, function() {
                    r = (r && this.call());
                    return r; // short circuits the loop when any value is false
                });
                
                
                
                return r;                                
            }
            
            var reaction = function(evt) {
                evt.stopPropagation();
                if (is_reactionaryisReactionary.apply(this)) {
                   settings.compliant.apply($element);
                } else {
                   settings.uncompliant.apply($element);
                }
            }
        
            $element.bind('change.reactor', reaction);
        });
                    
        return this;  
    };

    $.fn.reactor.defaults = {
        compliant: function() {
            $(this).show();
        },
        uncompliant: function() {
            $(this).hide();    
        }        
    };
    
    $.fn.reactor.helpers = {
    
        NotBlank: function() {
            return( $(this).val().toString() != "" )
        },
        
        Blank: function() {
            return( $(this).val().toString() == "" )
        },
        
        Disabled: function() {
            return( this.filter(':disable').length > 0 );
        },
        
        Enabled: function() {
            return( this.filter(':enabled').length > 0 );
        },
        
        EqualTo: function(matchStr) {
            var _func = function() { 
                var v = $(this).val();
                if (v) { return( v.toString() == matchStr ); } 
                else { return false; }
            } 
            return _func;
        },
                    
        LessThan: function(number) {
            var _func = function() {
                var v = $(this).val();
                return(!(v && parseInt(v) > number));
            }
            return _func;   
        },
            
        MoreThan: function(number) {
            var _func = function() {
                var v = $(this).val();
                return(!(v && parseInt(v) < number));
            }
            return _func;  
        },
                
        Between: function(min, max) {
            var _func = function() {
                var v = $(this).val();
                return(!(v && (parseInt(v) > max || parseInt(v) < min)));
            }
            return _func;
        },
            
        BetweenSameLength: function(min, max) {
            var len = min.toString().length;
            var _func = function() {
                var v = $(this).val();
                return(!(v && v.length == len && (parseInt(v) > max || parseInt(v) < min)));
            }
            return _func;
        }
    };

})(jQuery);
<form id="portfolio_form">
    <fieldset>
        
        <label>Zip</label>
        <input id="zip" type="text" value="" /><br />
        
        <label>2011 Income</label>
        <input id="income_2011" name="income[2011]" />
       
    </fieldset>  
    
    <p>Display cities only when zip is between 19100 and 19400</p>
   
    <fieldset class="cities">
        <label>Cities</label>
        <select id="cities_select">
            <option value=""></option>
            <option value="philadelphia">Philadelphia</option>
            <option value="media">Media</option>
            <option value="doylestown">Doylestown</option>
        </select>    
    </fieldset>
    
    <p>Display checkboxes only for Philadelphia and income less than 40000</p>
    <fieldset class="philly_middle_to_low_income">
        <input type="checkbox" /> Check One<br />
        <input type="checkbox" /> Check Two<br />
        <input type="checkbox" /> Check Three<br />
        <input type="checkbox" /> Check Four<br />
    </fieldset>   
   
   <p>Display checkboxes when zip is between 19000 and 20000 and income is lower than 25000<15000</p>
   <fieldset class="low_income_select_zips">
        <input type="checkbox" /> Check One<br />
        <input type="checkbox" /> Check Two<br />
        <input type="checkbox" /> Check Three<br />
        <input type="checkbox" /> Check Four<br />
    </fieldset>    
    
</form>

Need a review of a jQuery plugin that conditionally displays elements based on form values

$('.elements_to_display')
   .reactIf( '#some_form_element', SatisfiesFirstCondition)
   .reactIf( '#some_other_form_element', SatisfiesAnotherCondition)
   .reactIf( '#some_other_form_element', SatisfiesAnotherCondition);

Page JS

var IS = $.extend({}, $.fn.reactor.helpers);
  
$('.cities')    
    .reactIf('#zip', IS.Between(19100, 19400))
    .reactIf('#zip', IS.NotBlank);
        
$('.philly_middle_to_low_income')
    .reactIf('#income_2011', IS.LessThan(40000))
    .reactIf('#cities_select', IS.EqualTo('philadelphia'));
        
$('.low_income_select_zips')
    .reactIf('#income_2011', IS.LessThan(15000))
    .reactIf('#zip', IS.BetweenSameLength(19000, 20000))
    .reactIf('#zip', IS.NotBlank);
        
$('.reactor').trigger('change.reactor');

Plugin react.js

(function($){
    
    $.fn.reactTo = function(selector) {
        var $elements = $(selector),
            $reactor_element = $(this),
            _proxy_event = function() {
                $reactor_element.trigger('change.reactor');
            };

        $elements.filter('select').bind('change.reactor', _proxy_event);
        $elements.filter('input').bind('keyup.reactor', _proxy_event);  
            
        return this;
    };

    $.fn.reactIf = function(sel, exp_func) {
    
        var $sel = $(sel);
        var _func = function() {
            return exp_func.apply($sel);                               
        };
        
        this.each(function() {
            if (!$(this).hasClass('reactor')) { $(this).reactor(); }
            
            var conditions_arry = $(this).data('conditions.reactor');
            if (!$.isArray(conditions_arry)) { conditions_arry = []};
           
            conditions_arry.push(_func);

            $(this).data('conditions.reactor', conditions_arry);
        }); 

        $(this).reactTo(sel);
        
        return this;
    };
    
    $.fn.react = function() {
        
        this.each(function() {
           $(this).trigger('change.reactor')
        }); 

        return this;
    };
    
    $.fn.reactor = function(options) {
        var settings = $.extend({}, $.fn.reactor.defaults, options);
        
        this.each(function() {
            // var opts = $.meta ? $.extend({}, settings, $this.data()) : settings;
            
            var $element = $(this);
            
            if (!$element.hasClass('reactor')) { $element.data('conditions.reactor', []).addClass('reactor'); }
                        
            var is_reactionary = function() {  
                var conditionalArray = $(this).data('conditions.reactor'); 
                var r = true;
                                
                $.each(conditionalArray, function() {
                    r = (r && this.call());
                });
                
                
                
                return r;                                
            }
            
            var reaction = function(evt) {
                evt.stopPropagation();
                if (is_reactionary.apply(this)) {
                   settings.compliant.apply($element);
                } else {
                   settings.uncompliant.apply($element);
                }
            }
        
            $element.bind('change.reactor', reaction);
        });
                    
        return this;  
    };

    $.fn.reactor.defaults = {
        compliant: function() {
            $(this).show();
        },
        uncompliant: function() {
            $(this).hide();    
        }        
    };
    
    $.fn.reactor.helpers = {
    
        NotBlank: function() {
            return( $(this).val().toString() != "" )
        },
        
        Blank: function() {
            return( $(this).val().toString() == "" )
        },
        
        EqualTo: function(matchStr) {
            var _func = function() { 
                var v = $(this).val();
                if (v) { return( v.toString() == matchStr ); } 
                else { return false; }
            } 
            return _func;
        },
            
        LessThan: function(number) {
            var _func = function() {
                var v = $(this).val();
                return(!(v && parseInt(v) > number));
            }
            return _func;   
        },
            
        MoreThan: function(number) {
            var _func = function() {
                var v = $(this).val();
                return(!(v && parseInt(v) < number));
            }
            return _func;  
        },
                
        Between: function(min, max) {
            var _func = function() {
                var v = $(this).val();
                return(!(v && (parseInt(v) > max || parseInt(v) < min)));
            }
            return _func;
        },
            
        BetweenSameLength: function(min, max) {
            var len = min.toString().length;
            var _func = function() {
                var v = $(this).val();
                return(!(v && v.length == len && (parseInt(v) > max || parseInt(v) < min)));
            }
            return _func;
        }
    };

})(jQuery);
<form id="portfolio_form">
    <fieldset>
        
        <label>Zip</label>
        <input id="zip" type="text" value="" /><br />
        
        <label>2011 Income</label>
        <input id="income_2011" name="income[2011]" />
       
    </fieldset>  
    
    <p>Display cities only when zip is between 19100 and 19400</p>
   
    <fieldset class="cities">
        <label>Cities</label>
        <select id="cities_select">
            <option value=""></option>
            <option value="philadelphia">Philadelphia</option>
            <option value="media">Media</option>
            <option value="doylestown">Doylestown</option>
        </select>    
    </fieldset>
    
    <p>Display checkboxes only for Philadelphia and income less than 40000</p>
    <fieldset class="philly_middle_to_low_income">
        <input type="checkbox" /> Check One<br />
        <input type="checkbox" /> Check Two<br />
        <input type="checkbox" /> Check Three<br />
        <input type="checkbox" /> Check Four<br />
    </fieldset>   
   
   <p>Display checkboxes when zip is between 19000 and 20000 and income is lower than 25000</p>
   <fieldset class="low_income_select_zips">
        <input type="checkbox" /> Check One<br />
        <input type="checkbox" /> Check Two<br />
        <input type="checkbox" /> Check Three<br />
        <input type="checkbox" /> Check Four<br />
    </fieldset>    
    
</form>

Need a review of a jQuery plugin that conditionally displays elements based on form values [UPDATE]

ADDED CODE UPDATES

  • You can use two syntaxes with reactIf() (Hat tip: RoToRa)

    1. supply a function or helper, as original, or

    2. reference a helper with a string followed by arguments

      $('.cities')
      .reactIf($('#zip'), IS.NotBlank) .reactIf('#zip', 'Between', 19100, 19400);

  • helpers use this instead of $(this) (Hat tip: RoToRa)

  • checks for a data reference instead of class to find if initialized (still adds class) (Hat tip: RoToRa)

  • short-circuiting the $.each() loop (Hat tip: RoToRa)

  • verified using jquery objects as well as selector strings to find the element to watch (Hat tip: meo)

Links

Git Hub: https://github.com/natedavisolds/react.js

$('.elements_to_display')
   .reactIf( '#some_form_element', SatisfiesFirstCondition)
   .reactIf( '#some_other_form_element', 'SatisfiesAnotherCondition')
   .reactIf( '#some_other_form_element', 'SatisfiesAnotherCondition', args);

Page JS [UPDATED]

var IS = $.extend({}, $.fn.reactor.helpers);
  
$('.cities')    
   .reactIf('#zip', 'Between', 19100, 19400)
   .reactIf($('#zip'), IS.NotBlank);
        
$('.philly_middle_to_low_income')
    .reactIf('#income_2011', 'LessThan', 40000)
    .reactIf($('#cities_select'), IS.EqualTo('philadelphia'));
        
$('.low_income_select_zips')
    .reactIf('#income_2011', IS.LessThan(15000))
    .reactIf('#zip', 'Between', 19000, 20000)
    .reactIf($('#zip'), IS.NotBlank);
        
$('.reactor').trigger('change.reactor');

Plugin react.js [UPDATED]

 (function($){
    
    $.fn.reactTo = function(selector) {
        var $elements = $(selector),
            $reactor_element = $(this),
            _proxy_event = function() {
                $reactor_element.trigger('change.reactor');
            };

        $elements.filter('select').bind('change.reactor', _proxy_event);
        $elements.filter('input').bind('keyup.reactor', _proxy_event);  
            
        return this;
    };

    $.fn.reactIf = function(sel, exp_func) {
    
        var $sel = $(sel);   
        var args = Array.prototype.slice.call( arguments, 2 );
        
        var _func = function() {
            if ($.isFunction(exp_func)) {
               return exp_func.apply($sel);                               
            } else {
               var _returned = $.fn.reactor.helpers[exp_func].apply($sel, args);
               
               if ($.isFunction(_returned)) {
                  return _returned.apply($sel)
               } else {
                  return _returned;
               }
               
            }
        };
        
        this.each(function() {
            if (!$(this).hasClass('reactor')) { $(this).reactor(); }
            
            var conditions_arry = $(this).data('conditions.reactor');
            if (!$.isArray(conditions_arry)) { conditions_arry = []};
           
            conditions_arry.push(_func);

            $(this).data('conditions.reactor', conditions_arry);
        }); 

        $(this).reactTo(sel);
        
        return this;
    };
    
    $.fn.react = function() {
        
        this.each(function() {
           $(this).trigger('change.reactor')
        }); 

        return this;
    };
    
    $.fn.reactor = function(options) {
        var settings = $.extend({}, $.fn.reactor.defaults, options);
        
        this.each(function() {
            // var opts = $.meta ? $.extend({}, settings, $this.data()) : settings;
            
            var $element = $(this);
            
            if (!$.isArray($element.data('conditions.reactor'))) { $element.data('conditions.reactor', []).addClass('reactor'); }
                        
            var isReactionary = function() {  
                var conditionalArray = $(this).data('conditions.reactor'); 
                var r = true;
                                
                $.each(conditionalArray, function() {
                    r = this.call();
                    return r; // short circuits the loop when any value is false
                });
                
                return r;                                
            }
            
            var reaction = function(evt) {
                evt.stopPropagation();
                if (isReactionary.apply(this)) {
                   settings.compliant.apply($element);
                } else {
                   settings.uncompliant.apply($element);
                }
            }
        
            $element.bind('change.reactor', reaction);
        });
                    
        return this;  
    };

    $.fn.reactor.defaults = {
        compliant: function() {
            $(this).show();
        },
        uncompliant: function() {
            $(this).hide();    
        }        
    };
    
    $.fn.reactor.helpers = {
    
        NotBlank: function() {
            return( this.val().toString() != "" )
        },
        
        Blank: function() {
            return( this.val().toString() == "" )
        },
        
        Disabled: function() {
            return( this.filter(':disable').length > 0 );
        },
        
        Enabled: function() {
            return( this.filter(':enabled').length > 0 );
        },
        
        EqualTo: function(matchStr) {
            var _func = function() { 
                var v = this.val();
                if (v) { return( v.toString() == matchStr ); } 
                else { return false; }
            } 
            return _func;
        },
                    
        LessThan: function(number) {
            var _func = function() {
                var v = this.val();
                return(!(v && parseInt(v) > number));
            }
            return _func;   
        },
            
        MoreThan: function(number) {
            var _func = function() {
                var v = this.val();
                return(!(v && parseInt(v) < number));
            }
            return _func;  
        },
                
        Between: function(min, max) {
            var _func = function() {
                var v = this.val();
                return(!(v && (parseInt(v) > max || parseInt(v) < min)));
            }
            return _func;
        },
            
        BetweenSameLength: function(min, max) {
            var len = min.toString().length;
            var _func = function() {
                var v = this.val();
                return(!(v && v.length == len && (parseInt(v) > max || parseInt(v) < min)));
            }
            return _func;
        }
    };

})(jQuery);
<form id="portfolio_form">
    <fieldset>
        
        <label>Zip</label>
        <input id="zip" type="text" value="" /><br />
        
        <label>2011 Income</label>
        <input id="income_2011" name="income[2011]" />
       
    </fieldset>  
    
    <p>Display cities only when zip is between 19100 and 19400</p>
   
    <fieldset class="cities">
        <label>Cities</label>
        <select id="cities_select">
            <option value=""></option>
            <option value="philadelphia">Philadelphia</option>
            <option value="media">Media</option>
            <option value="doylestown">Doylestown</option>
        </select>    
    </fieldset>
    
    <p>Display checkboxes only for Philadelphia and income less than 40000</p>
    <fieldset class="philly_middle_to_low_income">
        <input type="checkbox" /> Check One<br />
        <input type="checkbox" /> Check Two<br />
        <input type="checkbox" /> Check Three<br />
        <input type="checkbox" /> Check Four<br />
    </fieldset>   
   
   <p>Display checkboxes when zip is between 19000 and 20000 and income is lower than 15000</p>
   <fieldset class="low_income_select_zips">
        <input type="checkbox" /> Check One<br />
        <input type="checkbox" /> Check Two<br />
        <input type="checkbox" /> Check Three<br />
        <input type="checkbox" /> Check Four<br />
    </fieldset>    
    
</form>
added 14 characters in body
Source Link
Loading
added 56 characters in body; edited title
Source Link
Loading
added 85 characters in body
Source Link
Loading
added 1 characters in body
Source Link
Loading
Source Link
Loading