Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If all conditions matches inside foreach

I have this type of html:

<p id="username_input" data-priority=""> 
    <label for="username">Username</label>
    <input type="text" class="input-text um-field " name="username" id="username" placeholder="" value="" required="required" data-label="Username">
</p>

<p id="firstname_input" data-priority=""> 
     <label for="firstname">First Name</label>
     <input type="text" class="input-text um-field " name="firstname" id="firstname" placeholder="" value="" required="required" data-label="FirstName">
</p>
<p class="form-row " id="radio_SXsPOwVSD_input"> 
   <input type="radio" class="input-radio um-field" value="Male" name="radio_SXsPOwVSD" id="radio_SXsPOwVSD_male">Male 
   <input type="radio" class="input-radio um-field" value="Female" name="radio_SXsPOwVSD" id="radio_SXsPOwVSD_Female">Female 
</p>

applyConditions array contains input, condition and value indexes. Could be any inputs and also many conditions. Suppose,

input = username
condition = 0 (is)
value = abc

input = firstname
condition = 1 (is not)
value = pqr

I need to do something(show/hide checkbox) if

username is abc and firstname isnot pqr

from the frontend. But could be input radio_sXsPOwVSD, condition 1 and value Male.

then,

applyConditions.forEach( function( item ) {

  if(item.condition == 0) {
    jQuery("#"+ item.input+"_input").on('change', ( function(  avalue ) {

        return function(e) {                
          if( e.target.value == avalue ) {
                //show checkbox
          }
          else {
                //hide checkbox
          }
        };
    })(item.value));
  }
  else if( item.condition == 1 ) {
        jQuery("#"+ item.input+"_input").on('change', ( function(  avalue ) {

        return function(e) {                
          if( e.target.value != avalue ) {
                //show checkbox
          }
          else {
           //hide checkbox
          }
        };
     })(item.value));
 }

});

However, this seems to be OR, if any matches, but I need all matches. I could count the matches and compare with array length, but with onChange count on same field seems to increase/decrease multiple times. What could be the solution? I am stuck on this for a while.

applyConditions = 
[
  {"input":"username","condition":"0","value":"abc"}, 
  {"input":"firstname","condition":"1","value":"pqr"}
];

could also be {"input":"radio_SXsPOwVSD","condition":"0","value":"Male"},

like image 393
micky Avatar asked Mar 31 '18 12:03

micky


4 Answers

Compare if ($(ele).val() == item.value) equals item.condition

to determine whether it matches the condition.

The following version now works on radio buttons and checkbox.

Well, I finally found that there're name attr on every input.

var applyConditions = [
    {
        'input': 'username',
        'condition': 0,
        'value': 'abc'
    },
    {
        'input': 'firstname',
        'condition': 1,
        'value': 'pqr'
    },
    {
        "input": "radio_SXsPOwVSD",
        "condition": 0,
        "value":"Male"
    }, 
    {
        "input": "check_box_XmNoe",
        "condition": 0,
        "value": "Apple"
    }
]

applyConditions.forEach(function(condition) {
    var targetInput = $('input[name='+condition.input+']');
    targetInput.on('change',function(){
        var results = $.map(applyConditions,(item, index)=>{
            var targetInput = $('input[name='+item.input+']');
            var type = targetInput.get(0).type;
            var check = false;
            if(type == "radio" || type == "checkbox"){
                var input = targetInput.get().find(x=>$(x).is(":checked") && $(x).val() == item.value)
                if (input)
                {
                    check = input.value == item.value != item.condition;
                }
                else{
                    // since 0 means equal, if there's no any radio button or checkbox is checked, check = false
                    check = item.condition ? true : false;
                }
            }
            else{
                check = (targetInput.val() == item.value) != item.condition;
            }

            if(check){
                // matches
            }
            else{
                // not matches
            }
            return check;
        })

        console.log(...results);
    })
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="username_input" data-priority=""> 
    <label for="username">Username</label>
    <input type="text" class="input-text um-field" name="username" id="username" placeholder="" value="" required="required" data-label="Username">
    ( ==abc )
</p>

<p id="email_input" data-priority=""> 
    <label for="username">Username</label>
    <input type="text" class="input-text um-field" name="email" id="email" placeholder="" value="" required="required" data-label="Email">
    ( no condition )
</p>

<p id="firstname_input" data-priority=""> 
     <label for="firstname">First Name</label>
     <input type="text" class="input-text um-field" name="firstname" id="firstname" placeholder="" value="" required="required" data-label="FirstName">
     ( !=pqr )
</p>
<p class="form-row" id="radio_SXsPOwVSD_input"> 
   <input type="radio" class="input-radio um-field" value="Male" name="radio_SXsPOwVSD" id="radio_SXsPOwVSD_male">Male 
   <input type="radio" class="input-radio um-field" value="Female" name="radio_SXsPOwVSD" id="radio_SXsPOwVSD_Female">Female 
   ( Male should be checked )
</p>

<p id="check_box_XmNoe_input">
    <label class="checkbox data-label=">Checkbox</label>
    <input type="checkbox" class="input-checkbox um-field" name="check_box_XmNoe" id="check_box_XmNoe_Apple" value="Apple"> Apple
    <input type="checkbox" class="input-checkbox um-field" name="check_box_XmNoe" id="check_box_XmNoe_Orange" value="Orange"> Orange 
    ( Apple should be checked )
</p>
like image 176
Hikarunomemory Avatar answered Nov 02 '22 05:11

Hikarunomemory


This is just an alternative algorithm.

var applyConditions = [
  {
    "input": "username",
    "condition": "0",
    "value": "abc",
  },
  {
    "input": "firstname",
    "condition": "1",
    "value": "pqr",
  },
  {
    "input": "radio_SXsPOwVSD",
    "condition": "0",
    "value": "Male"
  },
];
var totalConditions = applyConditions.length,
  conditionFulfilled = 0;

function compare($element, rule) {
  if ($element.length > 1) $element = $element.filter(':checked'); //radio
  return ($element.val() == rule.value) == (rule.condition == "0");
}

function setOK() {
  if (conditionFulfilled == totalConditions) $('#iresult').html('OK');
  else $('#iresult').html('Completed('+conditionFulfilled+'/'+totalConditions+')');
}

applyConditions.forEach(function(rule) {
  var $element = $('[name=' + rule.input + ']');
  var isConditionTrue = compare($element, rule);
  if (isConditionTrue) conditionFulfilled++;
  $element.change(function() {
    var updatedIsConditionTrue = compare($element, rule);
    if (isConditionTrue != updatedIsConditionTrue) {
      if (updatedIsConditionTrue) conditionFulfilled++;
      else conditionFulfilled--;
      isConditionTrue = updatedIsConditionTrue;
      setOK();
    }
  });
});
setOK();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="username_input" data-priority="">
  <label for="username">Username</label>
  <input type="text" class="input-text um-field " name="username" id="username" placeholder="value = abc" value="" required="required" data-label="Username">
</p>

<p id="firstname_input" data-priority="">
  <label for="firstname">First Name</label>
  <input type="text" class="input-text um-field " name="firstname" id="firstname" placeholder="value != pqr" value="" required="required" data-label="FirstName">
</p>
<p class="form-row " id="radio_SXsPOwVSD_input">
  <input type="radio" class="input-radio um-field" value="Male" name="radio_SXsPOwVSD" id="radio_SXsPOwVSD_male">Male
  <input type="radio" class="input-radio um-field" value="Female" name="radio_SXsPOwVSD" id="radio_SXsPOwVSD_Female">Female
</p>
<div>Result: <b id="iresult">Not OK</b></div>
like image 40
Munim Munna Avatar answered Nov 02 '22 05:11

Munim Munna


Removed the Array and used the data attribute instead.

  
        $(document).ready(function(){
       
            $('.validator').delegate('input', 'change', function(event){
                event.stopPropagation();
                var condition = $(this).closest('.validator').data('condition');
                var valueToCompare = $(this).closest('.validator').data('value');
                var result = "";
                if(condition  == "1"){
                    result = $(this).val().trim() == valueToCompare ? "Condition Satisfied" : "Condition Not Satisfied";
                }else{
                    result = $(this).val().trim() != valueToCompare ? "Condition Satisfied" : "Condition Not Satisfied";
                }
                console.log(result)
            });
        });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="validator" data-condition="1" data-value="Rony">
                <label for="username">First Name</label>
                <input type="text" >
        </div>
        <div class="validator" data-condition="0" data-value="White">
                <label for="username">Last name</label>
                <input type="text" >
        </div>
        <div class="validator" data-condition="1" data-value="Male">  
                <input type="radio" name="gender" value="Male">Male
                <input type="radio" name="gender" value="Female">Female
        </div>
        <div class="validator" data-condition="0" data-value="Banana">  
                <input type="radio" name="fruit" value="Apple">Apple
                <input type="radio" name="fruit" value="Banana">Banana
        </div>
like image 40
Kuldeep Dubey Avatar answered Nov 02 '22 06:11

Kuldeep Dubey


To test that every one of a set of conditions is true use Array.prototype.every.

This solution has a function, setRules, which accepts a set of rules in the above format and returns an object with an onChange property to add listeners. These listeners are triggered when any of the values changes and are passed the new boolean value. It would not be hard to keep a current value so that this only fires when it switches from true to false or vice-versa.

You can use it like this:

const ruleHandler = addRules(applyConditions);
ruleHandler.onChange(function(newValue) { /* do something */ }

(or simply chain these together like below.)

This also makes it easy to add new conditions, as they are simple functions that accept the current value and the entire rule (enhanced with a jQuery reference to the element.) You can add a condition like this:

'2': function(val, rule) {return val.length >= rule.minLength;}

And use it like this:

{input: "lastname", condition: "2", minLength: "4"},

This also points out that you could use arbitrary names for these conditions, rather than "0" and "1". Perhaps they could be eq, not_eq, and if you use that last one, minLength.

Most of this is reasonably simple. The only part that I think needs explanation is this:

var newVal = rules.every(function(rule) {
  var $elt = (rule.$elt.length > 1) ? rule.$elt.filter(':checked') : rule.$elt;
  return (conds[rule.condition] || function() {return true;})($elt.val(), rule);
})

Note first that we start by calling every on our rules.

In the second line we let radio buttons be represented by the :checked element and others by the only element in the $elt object.

The third line is the heart of this code: it finds the correct condition function by looking it up, or if it's not found, chooses a function that simply returns true. Then it calls this function with the value of the element and the rule itself.

var setRules = function(rules) {
  var listeners = [];
  var conds = {
    '0': function(val, rule) {return val === rule.value;},
    '1': function(val, rule) {return val !== rule.value;},
  }
  var test = function() {
    var newVal = rules.every(function(rule) {
      var $elt = (rule.$elt.length > 1) ? rule.$elt.filter(':checked') : rule.$elt;
      return (conds[rule.condition] || function() {return true;})($elt.val(), rule);
    })
    listeners.forEach(listener => listener(newVal));
  }
  rules.forEach(function(rule) {
    rule.$elt = $('[name=' + rule.input + ']').change(test);
  });
  return {
    onChange: function(listener) {
      listeners.push(listener); 
      test(); 
    }
  };
}

var applyConditions = [
  {input: "username", condition: "0", value: "abc"},
  {input: "firstname", condition: "1", value: "pqr"},
  {input: "radio_SXsPOwVSD", condition: "0", value: "Male"}
];

const $results = $('#result');

setRules(applyConditions).onChange(function(newVal) {
  $results.html(newVal ? 'OK' : 'Not OK');
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<p id="username_input" data-priority="">
  <label for="username">Username</label>
  <input type="text" name="username" id="username" value="abc">
</p>

<p id="firstname_input" data-priority="">
  <label for="firstname">First Name</label>
  <input type="text" name="firstname" id="firstname" value="pqr">
</p>

<p id="radio_SXsPOwVSD_input">
  <input type="radio" value="Male" name="radio_SXsPOwVSD" id="radio_SXsPOwVSD_male" checked>Male
  <input type="radio" value="Female" name="radio_SXsPOwVSD" id="radio_SXsPOwVSD_Female">Female
</p>

<div>Result: <b id="result">Not OK</b></div>

Also note that this would be cleaner and more readable if you were using ES6:

const setRules = (rules) => {
  const listeners = [];
  const conds = {
    '0': (val, rule) => val === rule.value,
    '1': (val, rule) => val !== rule.value
  }
  const test = () => {
    var newVal = rules.every(function(rule) {
      var $elt = (rule.$elt.length > 1) ? rule.$elt.filter(':checked') : rule.$elt;
      return (conds[rule.condition] || (() => true))($elt.val(), rule);
    })
    listeners.forEach(listener => listener(newVal));
  }
  rules.forEach((rule) => {
    rule.$elt = $('[name=' + rule.input + ']').change(test);
  });
  return {
    onChange: (listener) => {
      listeners.push(listener); 
      test(); 
    }
  };
}   
like image 38
Scott Sauyet Avatar answered Nov 02 '22 06:11

Scott Sauyet