How To Refactor This Repeating jQuery Code - javascript

I have a page with about 40 checkboxes and selects (all dynamically built by web app code) that I would like to use the following (working) piece of jQuery for. What I don't want to do is have to repeat this code for each and every checkbox, etc. I am not sure what the best way to approach this would be, as I am not a JavaScript/jQuery expert.
Does anyone have a suggestion for how the following code could be refactored to use with an arbitrary number of checkboxes and selects. The goal is to query a database and build the list of checkboxes and selects from it.
EDIT: This code needs to fire for the individual checkbox and its hidden select, as opposed to all of the checkboxes -- sorry I did not make that clear from the original post :)
$('#ssp_checkbox').change (function() {
$('#ssp_container').fadeIn();
});
$('#ssp_select').change(function() {
$('#ssp_addon').fadeIn().html('<i class="icon-ok"></i> ' + $('#ssp_select').val() + ' SSPs Ordered ' + '<button type="button" id="ssp_remove" class="btn btn-mini btn-danger">Remove</button>');
$('#ssp_container').fadeOut();
})
$(document).on('click', '#ssp_remove', function(){
$('#ssp_select').val('0');
$('#addons').find('#ssp_addon').fadeOut('slow');
$('#ssp_checkbox').attr('checked', false);
countChecked();
})
EDIT:
This is the snippet of HTML -- there are about 40 of these, and they are have different IDs, but are otherwise the same:
<!-- Civil Search / ServCode Prefix: civil / FIELDS: civil_checkbox, civil_select -->
<div class="row-fluid">
<div class="span12">
<!-- civil -->
<label class="checkbox">Civil Search
<input type="checkbox" class="" name="civil_checkbox" id="civil_checkbox">
</label>
</div><!--/Civil Search Span -->
</div><!--/Civil Search Row -->
<!-- Civil Search Select / FIELDS: civil_select -->
<div class="row-fluid addon-select-container" id="civil_select-container">
<div class="span12">
<!-- civil_select -->
<label for="">Number of Services to Add:</label>
<select class="span2" name="civil_select" id="civil_select">
<option value="0" selected>0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
</div><!--/Civil Search Addon Select Span -->
</div><!--/Civil Search Addon Select Row -->
Thanks!

I don't know exactly what your code needs to do, but I "think" I have a general idea of what you're going for.
I threw something together in a fiddle (below is the code). What it's doing is adding a data attribute to the input:checkbox elements with the div associated to the checkbox. Then it triggers a switch to show/hide the div tags. This will run across an unlimited number of checkboxes.
<!-- here are the 40 checkboxes, truncated for brevity -->
<label for="cb1">Check One</label>
<input type="checkbox" name="cb1" id="cb1" data-associated-div="a">
<label for="cb2">Check Two</label>
<input type="checkbox" name="cb2" id="cb2" data-associated-div="b">
<label for="cb3">Check Three</label>
<input type="checkbox" name="cb3" id="cb3" data-associated-div="c">
<!-- pretend these are big, convoluted drop down's -->
<div id="a" class="hidden">alpha</div>
<div id="b" class="hidden">bravo</div>
<div id="c" class="hidden">charlie</div>
$('body').ready(function(){
// hide all hidden elements by default
$('.hidden').hide();
});
$('input:checkbox').change(function () {
// get the target div from the data attribute 'associatedDiv'
var targetDiv = '#' + $(this).data('associatedDiv');
// if it's hidden, show it
if ($(targetDiv).is(":hidden")) {
$(targetDiv).fadeIn();
// if it's visible, hide it
} else {
$(targetDiv).fadeOut();
}
});

Instead of $('#ssp_checkbox')...
If you want all checkboxes then just select them all
$('input:checkbox')
or give each checkbox a class, e.g. 'mycheckbox' and use that..
$('.mycheckbox')
Same for the Selects.
$('select')
http://api.jquery.com/category/selectors/

Related

Dropdown selections jQuery

I am making a dropdown and want to show the div class="residential-options" when the id="residential" is selected and show the div class="commercial-options" when the id="commercial" is selected.
heres my HTML:
<div class= "row">
<select id='building-type'>
<option disabled selected value> -- select an option -- </option>
<option id="residential" value="residential" [...]>Residential</option>
<option id="commercial" value="commercial " [...]>Commercial</option>
<option id="corporate" value="corporate" [...]>Corporate</option>
<option id="hybrid" value="hybrid" [...]>Hybrid</option>
</select>
</div>
<div class="residential-options">
<div id="number-of-apartments" >
<label>N. of Apartments *</label>
<input [...]>
</div>
<div id="number-of-basements" >
<label>N. of Basements *</label>
<input [...]>
</div>
</div>
<div class="commercial-options">
<div id="number-of-floors" >
<label>N. of Floors *</label>
<input [...]>
</div>
heres my jQuery:
$("#building-type").change(function() {
($('#residential').is(':checked'))
$('.residential-options').show();
$('.commercial-options').hide();
$('.corporate-options').hide();
$('.hybrid-options').hide()
});
$("#building-type").trigger("change");
$("#building-type").change(function() {
($('#commercial').is(':checked'))
$('.commercial-options').show();
$('.residential-options').hide();
$('.corporate-options').hide();
$('.hybrid-options').hide()
});
$("#building-type").trigger("change");
it only shows the div class="commercial-options" whatever I click on. Thanks for your help!
Your code can be simplified greatly, including removing the .trigger() calls.
$("#building-type").change(function() {
$('div[class*="options"]').hide(); // hide all '*-option' divs
// Determine which option was selected and display the corresponding div:
['residential', 'commercial', 'corporate', 'hybrid'].forEach(function(base){
if ($('#' + base + ':checked').length) {
$(`.${base}-options`).show();
}
})
})
you can change your code to something like this:-
get the selected value from the building type .
compare the value using if, else if statements and inside if / else if statements show and hide your div's using class attribute.

Using two different SELECT elements depending on input value, but only second one in page posts correctly

I have an inventory form which I have been asked to improve. The user counts product and enters the new count into the form. Then, depending on whether the input is positive or negative, a select box appears with the list of reasons for the discrepancy. The UI is working perfectly, but the reason code will only pass for whichever select element is listed last.
Basically this works to ensure the user is entering negatives correctly so my default is to have the SELECT element for the negative reason second since it will be the one to work. I would appreciate any suggestions for a better approach.
$(document).ready(function () {
if ($("#invAmt").val()=='') {
$("#plus").hide();
$("#minus").hide();
}
//return false;
$(document).on('change', '#invAmt', function() {
if ($("#invAmt").val()>='1') {
$("#plus").show();
$("#minus").hide();
} else {
$("#plus").hide();
$("#minus").show();
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="form-group">
<label for="invDec">Enter Amount of Units to Adjust (+/-): </label>
<input name="invAmt" id="invAmt" style="width:50px" >
</div>
<label for="title">Reason for Adjustment:</label>
<div class="plus">
<select class="custom-select custom-select-md" name="reason" id="plus" style="width:370px">
<option value="">--- Select Reason ---</option>
<option value="30">Returned Product</option>
<option value="50">Other (explain in notes)</option></select>
</div>
<div class="minus">
<select class="custom-select custom-select-md" name="reason" id="minus" style="width:370px">
<option value="">--- Select Reason ---</option>
<option value="70">Recount (lost)</option>
<option value="75">Dumped / Died)</option>
<option value="90">Diseased / Pest</option>
<option value="65">Overgrown</option>
<option value="95">Overstock</option>
<option value="98">Loaned Out</option>
<option value="100">Other (explain in notes)</option></select>
</div>
if you want to select multiple options from your drop downs you need to add the "multiple" attribute to your two select statements. Like this:
<select class="custom-select custom-select-md" multiple name="reason" id="plus" style="width:370px">
also, you need to add a submit button.
If you are trying to get just one option for + and one option for - you need to use different names for each of your select boxes. If they are both name='reason' the last one will overwrite the first one. Try:
name='negReason'
name='posReason'

JS/jQuery: using dropdown box to set values in another field, is altering previous fields?

I have page with multiple drop down menus for employees to select a sales package, these drop down menus are completely identical.
Now when a user selects a sales package say packageA, it prefills a field on the page with the default amount for that package say $100. In the next dropdown packageA is available for selection again. In this next dropdown if a user selects PackageB it prefills the amount with the previous dropdowns value of $100, which is not the correct package price? Basically the money value autofill is only working with the first dropdown selection box on the page. Whatever is selected in the first dropdown changes every other packages money field value on the page?
I understand that by getting the element by ID is not efficient in the case here, yet getting by className does not work at all.
This HTML dropdown select box is repeated a few times on the page.
<!-- this is the dropdown -->
<select id="package-dropdown" class="selectpicker pkg-class">
<option value="">Select</option>
<option data-value="{{ django ID here }}" value="{{ django value here}}">{{django variable here}}.
<option data-value="{{ django ID here }}" value="{{ django value here}}">{{django variable here}}.
<option data-value="{{ django ID here }}" value="{{ django value here}}">{{django variable here}}.
</option>
</select>
<!-- where the monetary value gets prefilled -->
<div class="col-sm-5">
<input min="0" type="number" class="display-package-amount" class="form-control" placeholder="Amount">
</div>
// JS on change function
$(document).on('change','#package-dropdown', function(e) {
let package = document.getElementById("package-dropdown");
// This is where the price gets prefilled based off of the package selected
$(".display-package-amount").val(package.options[package.selectedIndex].getAttribute('data-value'));
});
Im struggling pretty bad on how to make these actually independent from each other to where each select box truly has nothing to do with the previous/next one. Any tips would be greatly appreciated!
You can't repeat ID in a page so use classes instead.
To get the associated input , traverse to a common parent with closest() then find() what you need within that parent
$(document).on('change', '.selectpicker', function() {
$(this).closest('.row').find('.display-package-amount').val(this.value)
})
.row {
padding: 1em;
border: 2px solid #ccc;
margin: 1em
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="row">
<select class="selectpicker pkg-class">
<option value="">Select</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<hr/>
<div class="col-sm-5">
<input min="0" type="number" class="display-package-amount" class="form-control" placeholder="Amount">
</div>
</div>
<div class="row">
<select class="selectpicker pkg-class">
<option value="">Select</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<hr/>
<div class="col-sm-5">
<input min="0" type="number" class="display-package-amount" class="form-control" placeholder="Amount">
</div>
</div>

Add .attr to button not working when called

Not sure if I formatted the question right. Have manually added the "data-next" and it is changing at the appropriate time, but still not changing. Have narrowed it down to the "showNext" function.
My objective is to iterate through the questions about the car the based on the number of cars the user enters. I was thinking a loop at first, but this seemed to be a cleaner way to do it. I'm new so I could be way off.
My problem is that while it does iterate through the correct number of times, and chrome shows that it is choosing that button as the "this" variable as I want it to, for some reason it is not adding the attribute. That line of code fires, I get no errors, but nothing happens.
I have tried using the exact id of the button, defining "this" as a variable (ie: var el = id of button) and a few other things I can't remember right now. Nothing has worked. Also I have used the same type of command in other areas and it worked just fine.
The rest of the code works fine and it does cycle through the correct number of times, but it will not add the attr. Any help would be greatly appreciated. If I have left anything out, please let me know. Thanks!
Here is the JS:
$(document).ready(function () {
// hide all 'hideFirst' elements, except the first one:
$('.hideFirst:not(:first)').hide();
// Method used to show/hide elements :
function showNext(el) {
// check if element has a 'data-next' attribute:
if (el.data('next')) {
// hide all elements with 'hideFirst' class:
$('.hideFirst').hide();
// show 'Back' button:
$('#backButton').show();
// show the element which id has been stored in 'data-next' attribute:
$(el.data('next')).show();
// push the parent element ('.hideFirst') into path array:
path.push(el.closest('.hideFirst'));
}
}
//Logs the number of cars in the household
$("#carAmount").click(function () {
numberOfCars = parseInt(document.getElementById("vehicleAmount").value);
showNext($(this));
});
//allow user to chose the type of car they drive
$("#carType").change(function () {
carChoice = $("#carType").val();
$("#carType").attr("data-next", "#" + carChoice);
showNext($(this));
});
//Decides whether the user has more cars to ask about
$(".carBtn").click(function () {
carCount++;
//asks about other cars
if (carCount < numberOfCars) {
$(this).attr('data-next', '#vehicleType');
$('#carType').prop('selectedIndex', 0);
}
//moves on to the next category
else {
$(this).attr('data-next', '#transportation');
}
showNext($(this));
});
});
And here is the HTML:
<div>
<form>
<div class="hideFirst" id="vehicleCount">
<label for="vehicleAmount">How many vehicles are there in your household?</label>
<input type="text" id="vehicleAmount" />
<button type="button" id="carAmount" data-next="#vehicleType" class="my-btn btnFoot"><i class="icon-footprint-right-d"></i></button>
</div>
<div class="hideFirst" id="vehicleType">
<label for="carType">What kind of car do you drive?</label>
<select id="carType">
<option disabled selected>--Choose One--</option>
<option value="gas">Gasoline</option>
<option value="diesel">Diesel</option>
<option value="cng">Natural gas</option>
<option value="hybrid">Hybrid</option>
<option value="elec">Electric</option>
<option value="hydrogen">Fuel Cell/Hydrogen</option>
</select>
</div>
<div class="hideFirst" id="gas">
<label for="fuelType">What type of fuel do you normally use??</label>
<select id="gasType">
<option disabled selected>--Choose One--</option>
<option value="e10">e10 (regular unleaded)</option>
<option value="e85">e85</option>
</select>
</div>
<div class="hideFirst" id="diesel">
<label for="carType">What type of diesel fuel do you normally use?</label>
<select id="dieselType" name="heatSource">
<option disabled selected>--Choose One--</option>
<option value="num5">Regular Diesel</option>
<option value="b10">B10 Biodiesel</option>
<option value="b100">B100 Biodiesel</option>
</select>
</div>
<div class="hideFirst" id="cng">
<label for="carCng">How much natural gas do you put in your car every month?</label>
<input type="text" id="carCng" />
<button type="button" id="propaneBill" class="carBtn btnFoot"><i class="icon-footprint-right-d"></i></button>
</div>
<div class="hideFirst" id="hybrid">
<label for="carType">What kind of car do you drive?</label>
<select id="carType" name="heatSource">
<option disabled selected>--Choose One--</option>
<option value="gas">Gasoline</option>
<option value="diesel">Diesel</option>
<option value="cng">Natural gas</option>
<option value="hybrid">Hybrid</option>
<option value="elec">Electric</option>
<option value="hydrogen">Fuel Cell/Hydrogen</option>
</select>
</div>
<div class="hideFirst" id="elec">
<label for="carElec">How many miles do you drive every month?</label>
<input type="text" id="carElec" />
<button type="button" id="elecMiles" class="carBtn btnFoot"><i class="icon-footprint-right-d"></i></button>
</div>
<div class="hideFirst" id="hydrogen">
<h2>Good for you, you produce no negative Co2 emission with your vehicle!</h2>
<button type="button" id="carsnow" class="carBtn btnFoot"><i class="icon-footprint-right-d"></i></button>
</div>
<div class="hideFirst" id="transportation">
<h2>Why won't I display?</h2>
<button type="button" data-next="" class="my-btn btnFoot"><i class="icon-footprint-right-d"></i></button>
</div>
</form>
<div>
<button id="backButton">Back</button>
</div>
</div>
Hoping to find some help here
OK, so it took a couple of days, but I figured this out.
The main problem is that the jquery .data- attributes are only read the very first time the property is accessed. So while I was changing them, at the right time, they weren't being read. It was also the reason that, while the back button worked it would not allow you to go to different divs when going back through the questions.
Here is the line from the jQuery documentation:
"The data- attributes are pulled in the first time the data property is
accessed and then are no longer accessed or mutated (all data values
are then stored internally in jQuery)."
Link to the page
By changing the .data- to a combination of .attr and .prop depending on the necessary functionality I was able to get it working.
As I mentioned in my original question, I'm very new so if I didn't provide enough info, please let me know.
Here is the code for it to work properly and a link to a fiddle.
var carCount = 0;
$(document).ready(function () {
// hide all 'hideFirst' elements, except the first one:
$('.hideFirst:not(:first)').hide();
var visited = [];
// Method used to show/hide elements :
function showNext(el) {
// check if element has a 'nextitem' attribute:
if (el.attr('nextitem')) {
// hide all elements with 'hideFirst' class:
$('.hideFirst').hide();
// show 'Back' button:
$('#backButton').show();
// show the element which id has been stored in 'nextitem' attribute:
$(el.attr('nextitem')).show();
// Push the parent element ('.hideFirst') into visited array:
visited.push(el.closest('.hideFirst'));
}
}
// click event for 'back' button:
$('#backButton').click(function () {
// hide all elements with 'hideFirst' class:
$('.hideFirst').hide();
// remove the last '.hideFirst' element from 'visited' array and show() it:
visited.pop().show();
// hide 'back' button if visited array is empty:
visited.length || $(this).hide();
}).hide(); // hide 'back' button on init
$(".myBtn").click(function () {
showNext($(this));
});
$("#amount").click(function () {
numberOfCars = parseInt(document.getElementById("inputNumber").value);
showNext($(this));
});
$("#typeA").change(function () {
carChoice = $("#typeA").val();
$("#typeA").attr("nextitem", "#" + carChoice);
showNext($(this));
//clears previous choices
$('#typeA').prop('selectedIndex', 0);
$('#typeB').prop('selectedIndex', 0);
$('#typeC').prop('selectedIndex', 0);
});
//Decides how many more times to iterate through
$(".carBtn").click(function () {
carCount++;
//asks about other cars
if (carCount < numberOfCars) {
$(this).attr('nextitem', '#main');
$("#bar").html(carCount);
$("#foo").html(numberOfCars);
}
//moves on to the next category
else {
$(this).attr('nextitem', '#last');
$("#bar").html(carCount);
}
showNext($(this));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<form>
<div class="hideFirst">
<label for="inputNumber">Number of times to iterate through</label>
<input type="text" id="inputNumber" />
<button type="button" nextitem="#main" class="myBtn" id="amount">Next</button>
</div>
<div class="hideFirst" id="main">
<select id="typeA">
<option disabled selected>--Choose One--</option>
<option value="b">Option B</option>
<option value="c">Option C</option>
</select>
</div>
<div class="hideFirst" id="b">
<label for="typeB">Type B</label>
<select id="typeB">
<option disabled selected>--Choose One--</option>
<option value="a">Option a</option>
<option value="b">Option b</option>
<option value="c">Option c</option>
</select>
<button type="button" class="carBtn">Next</button>
</div>
<div class="hideFirst" id="c">
<label for="typeC">Type C</label>
<select id="typeC">
<option disabled selected></option>
<option value="a">Option a</option>
<option value="b">Option b</option>
<option value="c">Option c</option>
</select>
<button type="button" class="carBtn">Next</button>
</div>
<div class="hideFirst" id="last">
<p>Done</p>
</div>
</form>
<div>
<br/>
<button id="backButton">Back</button>
</div>
<div>
<p>Number of times you asked for:<span id="foo"></span>
</p>
<p>Number of times around this form:<span id="bar"></span>
</p>
</div>

'fadeToggle' multiple div tags via drop down menu

I need to be able to hide/show multiple div tags on the same page via a drop down menu, but I want them to use the jQuery 'fadeToggle'. I can easily do this without 'fadeToggle' by using the following code:
function generateTask() {
document.getElementById('football').style.display = 'none';
document.getElementById('football2').style.display = 'none';
}
html:
<select name="something" id="something">
<option value="1" onclick="generateTask();">Football</option>
<option value="2" onclick="generateTask();">Cricket</option>
<option value="3" onclick="generateTask();">Baseball</option>
</select>
<div id="football">balls</div>
<div id="football2">shorts</div>
But this solution isn't as elegant. Any help would be appreciated.
The main complication is that the div tags "football" and "football2" might both be required for Cricket but only "football2" required for say Baseball.
You can try this
function generateTask(){ $('#football, #football2').toggle();}
Or yan can add classes on every elements that should be affected by your dropdown:
For example:
<div id="football" class="football">balls</div>
<div id="football2" class="football cricket">shorts</div>
<div id="cricket" class="cricket">stick</div>
And than target every element that's in link with your dropdown action.
If you can keep the value of the options as the ids of the divs then it will be much simpler.
Something like this
Markup
<select name="something" id="something">
<option value="football">Football</option>
<option value="cricket">Cricket</option>
<option value="baseball">Baseball</option>
</select>
<div id="football" class="content">Football content</div>
<div id="cricket" class="content">Cricket content</div>
<div id="baseball" class="content">Baseball content</div>
JS
$("#something").change(function(){
var id = "#"+this.value;
//This will hide all the divs with class content but not the selected option
$(".content").filter(":not("+id+")").hide();
$(id).fadeToggle();//This will toggle div based on the selected option
});

Categories

Resources