Home > OS >  How to enable and disable input radio buttons according to array with JQuery?
How to enable and disable input radio buttons according to array with JQuery?

Time:08-11

I'm using the following code to enable/disable radio buttons according to the radio button value which I clicked.

$(document).ready(function(){
//array
var data = [ 
    {"fruit": "apple", "quantity": "5", "package": "bag"}, 
    {"fruit": "apple", "quantity": "10", "package": "bag"}, 
    {"fruit": "apple", "quantity": "15", "package": "bag"}, 
    {"fruit": "grapes", "quantity": "10", "package": "box"}, 
    {"fruit": "mango", "quantity": "5", "package": "bag"}, 
    {"fruit": "mango", "quantity": "10", "package": "bag"},
    {"fruit": "mango", "quantity": "15", "package": "box"},
    {"fruit": "mango", "quantity": "20", "package": "box"},
    {"fruit": "pineapple", "quantity": "5", "package": "bag"},
    {"fruit": "pineapple", "quantity": "10", "package": "bag"},
    {"fruit": "pineapple", "quantity": "15", "package": "box"},
    {"fruit": "pineapple", "quantity": "20", "package": "box"} 
];

function info(cat,value){
    var filteredValue = data.filter(function (item) {
          return item[cat]==value;
    });

    var vf = filteredValue;

    for(var i=0; i<vf.length;i  ){
        var obj = vf[i];

        for(var key2 in obj){

            if(key2!=cat){
                //console.log(key2);
                var obj2 = obj[key2];
                //console.log(obj2);

                $("input[name='opt_" key2 "'][value!='" obj2 "']").prop("disabled","disabled");


            }
            
        }
    }
}

$(".info input[type='radio']").click(function(){
    var value = $(this).val();
    var cat = $(this).attr("data-cat");

    info(cat,value);

});




    
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA 058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">


<div >
<div >
<div >

<div>Fruit</div>
<div >
  <label >
    <input type="radio"  data-cat="fruit" name="opt_fruit" value="apple">Apple
  </label>
</div>
<div >
  <label >
    <input type="radio"  data-cat="fruit" name="opt_fruit" value="grapes">Grapes
  </label>
</div>
<div >
  <label >
    <input type="radio"  data-cat="fruit" name="opt_fruit" value="mango">Mango
  </label>
</div>
<div >
  <label >
    <input type="radio"  data-cat="fruit" name="opt_fruit" value="pineapple">Pineapple
  </label>
</div>

</div>

<div >

<div>Quantity</div>
<div >
  <label >
    <input type="radio"  data-cat="quantity" name="opt_quantity" value="5">5
  </label>
</div>
<div >
  <label >
    <input type="radio"  data-cat="quantity" name="opt_quantity" value="10">10
  </label>
</div>
<div >
  <label >
    <input type="radio"  data-cat="quantity" name="opt_quantity" value="15">15
  </label>
</div>
<div >
  <label >
    <input type="radio"  data-cat="quantity" name="opt_quantity" value="20">20
  </label>
</div>

</div>

<div >

<div>Package</div>
<div >
  <label >
    <input type="radio"  data-cat="package" name="opt_package" value="bag">Bag
  </label>
</div>
<div >
  <label >
    <input type="radio"  data-cat="package" name="opt_package" value="box">Box
  </label>
</div>

</div>



</div>
</div>

As you can see, the problem is when I click a radio button input, the others turn disabled incorrectly:

enter image description here

And I want to get this result, for example, if I click on "apple", it must enable only quantity and package radio buttons available for that value according to data array like this:

enter image description here

How can I fix it? I'd like to receive your help.

CodePudding user response:

for(var i=0; i<vf.length;i  ){
    var obj = vf[i];

    for(var key2 in obj){

        if(key2!=cat){
            //console.log(key2);
            var obj2 = obj[key2];
            //console.log(obj2);

            $("input[name='opt_" key2 "'][value!='" obj2 "']").prop("disabled","disabled");
        }
            
    }
}

In this loop, each data in obj make other inputs which have different value disabled.
For example, when you click 'apple', obj will be like below.
{fruit: 'apple', quantity: '5', package: 'bag'}
{fruit: 'apple', quantity: '10', package: 'bag'}
{fruit: 'apple', quantity: '15', package: 'bag'}
And in the for loop,
quantity: '5' makes input[name='opt_quantity'] which has value '10', '15', '20' disabled
quantity: '10' makes input[name='opt_quantity'] which has value '5', '15', '20' disabled
quantity: '15' makes input[name='opt_quantity'] which has value '5', '10', '20' disabled
As a result, all input[name='opt_quantity'] disabled.

You can simply disabled all input first, and then change "disable" prop false according to the clicked radio button value.

$(document).ready(function(){
//array
var data = [ 
    {"fruit": "apple", "quantity": "5", "package": "bag"}, 
    {"fruit": "apple", "quantity": "10", "package": "bag"}, 
    {"fruit": "apple", "quantity": "15", "package": "bag"}, 
    {"fruit": "grapes", "quantity": "10", "package": "box"}, 
    {"fruit": "mango", "quantity": "5", "package": "bag"}, 
    {"fruit": "mango", "quantity": "10", "package": "bag"},
    {"fruit": "mango", "quantity": "15", "package": "box"},
    {"fruit": "mango", "quantity": "20", "package": "box"},
    {"fruit": "pineapple", "quantity": "5", "package": "bag"},
    {"fruit": "pineapple", "quantity": "10", "package": "bag"},
    {"fruit": "pineapple", "quantity": "15", "package": "box"},
    {"fruit": "pineapple", "quantity": "20", "package": "box"} 
];

function info(cat,value){
    var filteredValue = data.filter(function (item) {
          return item[cat]==value;
    });
    
    $("input[name!='opt_"   cat   "']").prop("disabled", true); // disable all input except clicked category input

    var vf = filteredValue;

    for(var i=0; i<vf.length;i  ){
        var obj = vf[i];

        for(var key2 in obj){

            if(key2!=cat){
                var obj2 = obj[key2];

                $("input[name='opt_" key2 "'][value='" obj2 "']").prop(
            "disabled", false
          );

            }
        }
    }
}

$(".info input[type='radio']").click(function(){
    var value = $(this).val();
    var cat = $(this).attr("data-cat");

    info(cat,value);

});




    
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA 058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">


<div >
<div >
<div >

<div>Fruit</div>
<div >
  <label >
    <input type="radio"  data-cat="fruit" name="opt_fruit" value="apple">Apple
  </label>
</div>
<div >
  <label >
    <input type="radio"  data-cat="fruit" name="opt_fruit" value="grapes">Grapes
  </label>
</div>
<div >
  <label >
    <input type="radio"  data-cat="fruit" name="opt_fruit" value="mango">Mango
  </label>
</div>
<div >
  <label >
    <input type="radio"  data-cat="fruit" name="opt_fruit" value="pineapple">Pineapple
  </label>
</div>

</div>

<div >

<div>Quantity</div>
<div >
  <label >
    <input type="radio"  data-cat="quantity" name="opt_quantity" value="5">5
  </label>
</div>
<div >
  <label >
    <input type="radio"  data-cat="quantity" name="opt_quantity" value="10">10
  </label>
</div>
<div >
  <label >
    <input type="radio"  data-cat="quantity" name="opt_quantity" value="15">15
  </label>
</div>
<div >
  <label >
    <input type="radio"  data-cat="quantity" name="opt_quantity" value="20">20
  </label>
</div>

</div>

<div >

<div>Package</div>
<div >
  <label >
    <input type="radio"  data-cat="package" name="opt_package" value="bag">Bag
  </label>
</div>
<div >
  <label >
    <input type="radio"  data-cat="package" name="opt_package" value="box">Box
  </label>
</div>

</div>



</div>
</div>

*Additionally, it seems to need multiple conditions filtering data when 2 or more category( if you make more than 3 category ) have value.

CodePudding user response:

Your requirements required involving multiple steps to achieve this.

Start with defining which properties will included in the filter:

const properties = ['fruit', 'quantity', 'package']

Add a click event to detect user selection:

$('[name^="opt_"]').click(event => {
    /* code... */
})

Every time when user select an option, based on your properties defined above, loop through each property and get their current selected value:

const filter = properties.reduce((filter, property) => {
    return { ...filter, [property]: $(`[name="opt_${property}"]:checked`).val() }
}, {})

This will return a filter data object:

{
    "fruit": "pineapple",
    "quantity": "10",
    "package": undefined
}

Filter the fruits data by using the filter data object. Following function will loop through each item and compare every filter property:

const filtered = data.filter(row => {
    const isMatched = properties.reduce((match, property) => {
        return match && (!filter[property] || row[property] == filter[property])
    }, true)

    return isMatched
})

Next let's get the available options (enabled radio buttons) array from the filtered results by using this method:

const pluckWithoutDuplicate = (array, key) => array.reduce((result, item) => {
    if (!result.includes(item[key])) {
        result.push(item[key])
    }
    return result
}, [])

The returned available options array will looks like this:

["bag", "box"]

Finally update the radio buttons status using the available options array:

const syncRadioButton = (property, availableValues) => {
    if (property == selectedProperty) {
        return
    }

    $(`[name="opt_${property}"]`).each((index, element) => {
        const radioButton = $(element)
        const value = radioButton.val()
        const available = availableValues.includes(value)
        
        radioButton.prop('disabled', !available)
    })
}

Demo:

const data = [{
    "fruit": "apple",
    "quantity": "5",
    "package": "bag"
  },
  {
    "fruit": "apple",
    "quantity": "10",
    "package": "bag"
  },
  {
    "fruit": "apple",
    "quantity": "15",
    "package": "bag"
  },
  {
    "fruit": "grapes",
    "quantity": "10",
    "package": "box"
  },
  {
    "fruit": "mango",
    "quantity": "5",
    "package": "bag"
  },
  {
    "fruit": "mango",
    "quantity": "10",
    "package": "bag"
  },
  {
    "fruit": "mango",
    "quantity": "15",
    "package": "box"
  },
  {
    "fruit": "mango",
    "quantity": "20",
    "package": "box"
  },
  {
    "fruit": "pineapple",
    "quantity": "5",
    "package": "bag"
  },
  {
    "fruit": "pineapple",
    "quantity": "10",
    "package": "bag"
  },
  {
    "fruit": "pineapple",
    "quantity": "15",
    "package": "box"
  },
  {
    "fruit": "pineapple",
    "quantity": "20",
    "package": "box"
  }
]

const properties = ['fruit', 'quantity', 'package']

/* listen to click event of elements that have name with prefix "opt_" */
$('[name^="opt_"]').click(event => {
  /* get selected property by extract the value from name "opt_{property}" */
  const selectedProperty = $(event.currentTarget).attr('name').replace('opt_', '')
  const propertyIndex = properties.indexOf(selectedProperty)

  /* get properties that come after the selected property */
  const propertiesToReset = properties.slice(propertyIndex   1)

  /* this is optional, whether reset the selection every time or only when selected property was "fruit" */
  if (selectedProperty == 'fruit') {
    /* loop through properties that come after the selected property */
    propertiesToReset.forEach(property => {
      /* reset the property selection */
      $(`[name="opt_${property}"]`).prop('checked', false)
    })
  }

  /* get all properties selected values and used as filter data */
  const filter = properties.reduce((filter, property) => {
    return { ...filter,
      [property]: $(`[name="opt_${property}"]:checked`).val()
    }
  }, {})

  /* loop through each data item */
  const filtered = data.filter(row => {
    /* loop through each property */
    const isMatched = properties.reduce((match, property) => {
      /* check whether the data item's property is match with the filter data's property  */
      return match && (!filter[property] || row[property] == filter[property])
    }, true)

    /* append to the filtered result if this item is matched */
    return isMatched
  })

  /* this function is to get specific key's value from multidimensional array, without duplicated value  */
  const pluckWithoutDuplicate = (array, key) => array.reduce((result, item) => {
    if (!result.includes(item[key])) {
      result.push(item[key])
    }
    return result
  }, [])

  /* this function is to control whether the radio buttons are avaialble based on available values */
  const syncRadioButton = (property, availableValues) => {
    /* no need to disable current selected property  */
    if (property == selectedProperty) {
      return
    }

    /* loop through the property radio buttons */
    $(`[name="opt_${property}"]`).each((index, element) => {
      const radioButton = $(element)
      const value = radioButton.val()
      const available = availableValues.includes(value)

      /* enable based on if the value is available */
      radioButton.prop('disabled', !available)
    })
  }

  /* get available values of the properties */
  const availableQuantities = pluckWithoutDuplicate(filtered, 'quantity')
  const availablePackages = pluckWithoutDuplicate(filtered, 'package')

  /* sync the radio buttons based on available values */
  syncRadioButton('quantity', availableQuantities)
  syncRadioButton('package', availablePackages)
})
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA 058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<div >
  <div >
    <div >
      <div>Fruit</div>
      <div >
        <label >
                        <input type="radio"  data-cat="fruit" name="opt_fruit" value="apple">
                        Apple
                    </label>
      </div>
      <div >
        <label >
                        <input type="radio"  data-cat="fruit" name="opt_fruit" value="grapes">
                        Grapes
                    </label>
      </div>
      <div >
        <label >
                        <input type="radio"  data-cat="fruit" name="opt_fruit" value="mango">
                        Mango
                    </label>
      </div>
      <div >
        <label >
                        <input type="radio"  data-cat="fruit" name="opt_fruit" value="pineapple">
                        Pineapple
                    </label>
      </div>
    </div>
    <div >
      <div>Quantity</div>
      <div >
        <label >
                        <input type="radio"  data-cat="quantity" name="opt_quantity" value="5">5
                    </label>
      </div>
      <div >
        <label >
                        <input type="radio"  data-cat="quantity" name="opt_quantity" value="10">10
                    </label>
      </div>
      <div >
        <label >
                        <input type="radio"  data-cat="quantity" name="opt_quantity" value="15">15
                    </label>
      </div>
      <div >
        <label >
                        <input type="radio"  data-cat="quantity" name="opt_quantity" value="20">20
                    </label>
      </div>
    </div>
    <div >
      <div>Package</div>
      <div >
        <label >
                        <input type="radio"  data-cat="package" name="opt_package" value="bag">Bag
                    </label>
      </div>
      <div >
        <label >
                        <input type="radio"  data-cat="package" name="opt_package" value="box">Box
                    </label>
      </div>
    </div>
  </div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

  • Related