Плагин, который условно отображает элементы на основе значения формы


Я только что выпустила плагин jQuery, который условно отображает элементы на основе значений формы. Я бы признателен за любые предложения о том, как улучшить код и его полезность.

Вот демо-страница

  1. Это было бы полезно для вас?
  2. Какие еще функции я должен включить?
  3. Любой рефакторинг или структурных изменений, что я должен сделать?
  4. Я беспокоюсь о разоблачении 4 различные функции. Разве это слишком много?

Цель

Плагин помогает в ситуациях, когда элемент должен скрывать или отображать на основе значений других элементов. В частности, он выделяется когда существует несколько условий, которые должны быть удовлетворены для того, чтобы скрыть или показать.

Дополнительные понятия иметь в виду

  • Использовать как плагин jQuery
  • Легко цепного правила
  • Понятно, прочитав строку кода
  • Можно создавать/добавлять пользовательские условия

Пример бизнес-правила, чтобы решить

Допустим, у нас есть следующие правила для элементов:

  • Дисплей набор чекбоксов, если

    1. Молния между 19000 и 20000
    2. Доход ниже 15000
  • Отобразить следующий набор чекбоксов, если

    1. Город 'Филадельфия'
    2. Доход ниже 40000
  • Дисплей-Сити выберите флажок, если

    1. Молния между 19100 19400 и

Идеальный образ

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

Страница с 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');

Плагин 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);

HTML-код react.html

<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>


1773
6
задан 24 июня 2011 в 07:06 Источник Поделиться
Комментарии
1 ответ


  • Синтаксис-это хорошо, но необходимости для пользователя, чтобы объявить это сами не идеал. Вы должны искать другое решение. Одна возможность могла бы поставить название условное функции как строку и ее аргументов в качестве дополнительных аргументов reactIf. Таким образом, условные функции больше не нужно иметь высшего порядка (не то что это плохо). Пример:

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

    // ...
    $.fn.reactIf = function(sel, exp_func) {

    var $sel = $(sel);
    var args = arguments.slice(2);
    var _func = function() {
    return $.fn.reactor.helpers[exp_func].apply($sel, args);
    };

    // ...
    }

    $.fn.reactor.helpers = {
    // ...
    Between: function(min, max) {
    var v = $(this).val();
    return(!(v && (parseInt(v) > max || parseInt(v) < min)));
    },
    // ...
    }


  • Это еще одна проблема, с условной функции: указать объект jQuery, как этот аргументприменяют, так это не нужно, чтобы обернуть это в другую в jQuery вызова внутри условной функции. Вы должны либо изменить, применить вызов:

    return exp_func.apply($sel[0]);

    или в условной функции:

    var v = this.val();

  • Я не уверен, если это хорошая идея, чтобы отметить элементы с классом. Это может пойти не так, например, если второй на JavaScript удаляет все классы из элемента. Вместо

     if (!$(this).hasClass('reactor')) { $(this).reactor(); }

    var conditions_arry = $(this).data('conditions.reactor');
    if (!$.isArray(conditions_arry)) { conditions_arry = []};

    Я хотел бы использовать

     var conditions_arry = $(this).data('conditions.reactor');
    if (!$.isArray(conditions_arry)) {
    $(this).reactor();
    conditions_arry = [];
    };

    и точно так же в реакторе().


  • Вы должны рассмотреть короткое замыкание $.каждый() цикл вызова условные функции (что также делает && ненужного):

      $.each(conditionalArray, function() {
    r = this.call();
    return r; // Stops the `each` loop if r is `false`
    });

5
ответ дан 28 июня 2011 в 02:06 Источник Поделиться