Automation of a series of similar operations

I have a series of input fields representing items. The relevant html looks like this:

<input type="text" name="items[][name]" id="items__name" value="" class="form-control">
<input type="text" name="items[][description]" id="items__description" value="" class="form-control">
<input type="text" name="items[][rate]" id="items__rate" value="" class="form-control calc">
<input type="text" name="items[][quantity]" id="items__quantity" value="" class="form-control calc">

      

The user can now add items. To do this, I just clone the wrapper over the fields and add to the last table of items.

So now I have an array of the text boxes I just added. as textFields

to which I need to add validation rules. I am using jQuery Validator

to check.

My code for this looks like this:

           $(textFields[0]).rules('add', {
                required: true,
                messages: {
                    required: I18n.t('orders.itemNameRequired')
                }
            });

            $(textFields[1]).rules('add', {
                required: true,
                messages: {
                    required: I18n.t('orders.itemDescriptionRequired')
                }
            });

            $(textFields[2]).rules('add', {
                required: true,
                number: true,
                messages: {
                    required: I18n.t('orders.itemRateRequired'),
                    number: I18n.t('orders.itemRateInvalid')
                }
            });

            $(textFields[3]).rules('add', {
                required: true,
                number: true,
                messages: {
                    required: I18n.t('orders.itemQuantityRequired'),
                    number: I18n.t('orders.itemQuantityInvalid')
                }
            });

      

It works fine now. But is there a DRY way using a loop or keeping the rules in a hash or something like that? Can't think of a way. Need a second person perspective here.

Thanks in advance.

+3


source to share


4 answers


I personally would do something like this to clean up the code ...

function addRule(element, number, messages) {
    $(element).rules("add", {
        required: true,
        number: number,
        messages: messages
    });
}

addRule(textFields[0], false, {
    required: I18n.t('orders.itemNameRequired')
});

addRule(textFields[1], false, {
    required: I18n.t('orders.itemDescriptionRequired')
});

addRule(textFields[2], true, {
    required: I18n.t('orders.itemRateRequired'),
    number: I18n.t('orders.itemRateInvalid')
});

addRule(textFields[3], true, {
    required: I18n.t('orders.itemQuantityRequired'),
    number: I18n.t('orders.itemQuantityInvalid')
});

      

However, for the html you provided, the following script will add the rules needed for those fields ...



$("input[name]").each(function() {
    var rule = {
        required: true,
        messages: {}
    };

    if (this.name.match("[name]").length) {
        rule.messages.required = I18n.t('orders.itemNameRequired');
    }
    else if (this.name.match("[description]").length) {
        rule.messages.required = I18n.t('orders.itemDescriptionRequired');
    }
    else if (this.name.match("[rate]").length) {
        rule.number = true;
        rule.messages.required = I18n.t('orders.itemRateRequired');
        rule.messages.number = I18n.t('orders.itemRateInvalid');
    }
    else if (this.name.match("[quantity]").length) {
        rule.number = true;
        rule.messages.required = I18n.t('orders.itemQuantityRequired');
        rule.messages.number = I18n.t('orders.itemQuantityInvalid');
    }

    $(this).rules("add", rule);
});

      

The advantage of the second approach is that you could add as many name, description, speed and quantity fields as you like on the page and apply all validations to them without having to change them. Any approach will work, so this is just a case of choosing the one that works best for the given scenario.

+2


source


Doesn't significantly reduce the number of lines of code, but you can use an array of rule config objects and loop over elements to add from the array. This would allow separation of business logic and configuration data if required, although

var fieldOpts = [{
    messages: {
        required: I18n.t('orders.itemNameRequired')
    }
}, {    
    messages: {
        required: I18n.t('orders.itemDescriptionRequired')
    }
}, {    
    number: true,
    messages: {
        required: I18n.t('orders.itemRateRequired'),
        number: I18n.t('orders.itemRateInvalid')
    }
}, {    
    number: true,
    messages: {
        required: I18n.t('orders.itemQuantityRequired'),
        number: I18n.t('orders.itemQuantityInvalid')
    }
}]

$(textFields).each(function(i){
    var rules = fieldOpts[i];
    rules.required=true; // common to all so am adding here instead of in array
    $(this).rules('add',rules)
});

      



note also that if all fields are required, you can put an attribute required

on the elements

+1


source


It works great, but you need to store the messages i18n

in the attributes of the input fields themselves. as

<input name="my_field" data-i18n-number-messages="This is a required field" />

<input name="my_field" data-i18n-required-messages="This is a required field" data-i18n-number-messages="This is a required field" />


Since you are cloning pre-existing fields, you only need to add the message once at compile / backend time.

code:

function addRule(targetHash){
        $.each(targetHash, function (element, options){
            var $element = $('input[name="' + element + '"]');
            var methods = {}
            var messages = {}
            $.each(options, function(method, trueFalse){
                methods[method] = trueFalse;
                if (trueFalse){
                    messages[method] = $element.attr('data-i18n-' + method + '-messages');
                }
            });
            var rules = $.extend({}, methods, {messages: messages});
            console.log(rules);
            $element.rules('add', rules);
        });
    }

    addRule({
        // textFields[3] should be the name of the fields
        'textFields[3]': {required: true, number: true},                
        'textFields[4]': {required: true}
    });

      

0


source


Provide a class in a numeric field. Let's say it's a numeric field. Here's just the pseudo code for that.

$("#input-container :input").each(function(){

  if(this.hasClass('numeric-field'){
    this.rules('add', {
            required: true,
            number: true,
            messages: {
                required: I18n.t('orders.itemRateRequired'),
                number: I18n.t('orders.itemRateInvalid')
            }
        });
   }
 else{
      this.rules('add', {
            required: true,
            messages: {
                required: I18n.t('orders.itemDescriptionRequired')
            }
        });
     }
});

      

-1


source







All Articles