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