jQuery append class to parent TD of input if val is present - javascript

Pretty much what the title says; I am trying to add icons to shipping selections in Woocommerce, since sometimes the form is filled in on page load. I've created this
$(document).ready( function () {
$('.shipping_method').each( function () {
$this = $(this).closest('td');
if ( this.value = 'table_rate_shipping_freship' ) $this.addClass('shipups');
});
});
This doesn't work, and I'm not sure why.
An additional point is that the shipping method value can change based on information entered further up the form. So would having something like the following be okay?
$(document).ready( function () {
$('.shipping_method').each( function () {
$this = $(this).closest('td');
if ( this.value = 'table_rate_shipping_freship' ) $this.addClass('shipups');
});
});
$(document).ready( function () {
$('.shipping_method').change(function() {
$this = $(this).closest('td');
if ( this.value = 'table_rate_shipping_freship' ) $this.addClass('shipups');
});
});
I'm guessing not since it's basically doing what's been done before but adding a .change() to it. Any help would be really appreciated.
Thanks.
Edit: By request, the HTML from the Woocommerce checkout relating to shipping method:
<tr class="shipping">
<th>Shipping and Handling</th>
<td>
UPS Next Working Day (Free) <input type="hidden" name="shipping_method[0]" data-index="0" id="shipping_method_0" value="table_rate_shipping_freship" class="shipping_method">
</td>
</tr>

$("input[value='table_rate_shipping_freship']").parent().addClass('shipups');
try this. it will add class to parent td

posted answer working fine,
But if you need something general, here you go :)
function addCustomClass(target, className, valueToCheck) {
$("input[value='" + valueToCheck + "']").closest(target).addClass(className);
}
Usage:
addCustomClass('td', 'shipups', 'table_rate_shipping_freship');

Related

jquery function to handle a series of href in div rows

Imagine a table (actually constructed of divs) with rows and in the final cell in each row, I have an input text and a link that look like this:
<input type="text" name="message" id="message_#Model.IncidentId" value="">
Send a Comment
After each row (the parent div), I have a chunk of code like the following to ajaxify the link and text input:
$('#send_#Model.IncidentId').click(function () {
var msg = $('#message_#Model.IncidentId').val();
if (msg != '') { $(this).attr('href', this.href + '?msg=' + msg) }
$.post(this.href, function (json) {
if (json.jsonResult === null) {
$("#msg_#Model.IncidentId").html("Sent...");
} else {
window.location.href = json.jsonResult;
}
});
return false;
});
It works. However, there are at least 10 of these on each page. What I'm trying to do is consolidate the jquery into one function to handle all the links. Can I use jquery "this" or pass the IncidentId to the jquery function or something? It seems like "this" would not work because the input text is outside of the link? How can I do this to have one function for the entire page?
Keep in mind it's not imperative that I splash everything with the IncidentId. So, if I need to make one or more of the ids or names generic, that would be ok. It just needs to not get confused about what pair it's handling. I've seen some comments that a form might help, but 10+ forms on a page is ok? Plus, as it stands, there will never be any other input fields than what is shown above.
I appreciate your help. Thanks.
Update: So, I basically used Søren's recommended html5 data-* (data-id) attribute in my link, gave it a class name, and then moved my url down to the function as well...and then simply replaced all my #Model.IncidentIds. The one catch is that I had to use the following to register my click event:
$(document).on('click', ".ajax-link", function () {
I guess because I'm using handlebars to dynamically generate the page? I hadn't tested the original function since I moved it to my infinite scroll layout mentioned in the comments. Thanks all for replying.
Try this:
<input type="text" name="message" data-input-id="1" value="">
<a class="ajax-link" href="#" data-link-id="1">Send a Comment</a>
$('.ajax-link').click(function () {
var id = $(this).attr('data-link-id');
var msg = $('[data-link-id='+id+']').val();
if (msg != '') { $(this).attr('href', this.href + '?msg=' + msg) }
$.post(this.href, function (json) {
if (json.jsonResult === null) {
$("[data-link-id='+id+']").html("Sent...");
} else {
console.debug(json.jsonResult);
}
});
return false;
});
Make sure the link and field have the same id
First, make sure you have some useful class name's in place. E.g.,
<input type="text" class="incident-message" name="message" id="message_#Model.IncidentId" value="">
Send a Comment
That should allow you to create a nice, row-generic script like this:
$('.incident-link').click(function(e) {
e.preventDefault();
var $this = $(this),
$row = $this.closest('div'),
$msg = $row.find('.incident-message');
var msg = $msg.val();
if (msg != '') {
$this.attr('href', $this.attr('href') + '?msg=' + msg);
}
$.post($this.attr('href'), function (json) {
if (json.jsonResult === null) {
// I didn't see any markup for your #msg element, but assuming
// that you give it a useful classname, you can do something
// similar to this:
$row.find('.some-msg-className').html('Sent...');
} else {
window.location.href = json.jsonResult;
}
});
});
As far as grouping the events to a single handler, just use a class instead of id's.
$('.thisKind').click(function () {
or if the content is dynamic, use a single event for the parent with a selector in the on() method
$('#parentId').on("click", ".thisKind", function() {
As far as the this usage, you should familiarize yourself with jquery's DOM traversal using closest() to go up the tree and find() to go down

Varying ID's, One JQuery Function

I have to use ID instead of something repeatable like class, just because of the way the plugin I'm calling works. So below, I am having to create two different functions in order to force the bootstrapValidator in a particular field upon clicking a checkbox. I can't use something like
'revalidateField', 'availmon[] || availtue[]'
but is there some other method or variable I can use so I'm not doing this same function 7x?
Here is a JSFiddle with all of the external resources attached for seeing what I'm actually doing.
$(function () {
$('#checkallmon').on('click', function () {
$(this).closest('fieldset').find(':checkbox').prop('checked', this.checked);
$('#app').bootstrapValidator('revalidateField', 'availmon[]');
});
});
$(function () {
$('#checkalltue').on('click', function () {
$(this).closest('fieldset').find(':checkbox').prop('checked', this.checked);
$('#app').bootstrapValidator('revalidateField', 'availtue[]');
});
});
And if you do something like this:
$(function() {
$(".checkall").on('click', function() {
var elem = $(this);
var validationRule = elem.data('validation-rule');
elem.closest('fieldset').find(':checkbox').prop('checked', this.checked);
$('#app').bootstrapValidator('revalidateField', validationRule+'[]');
});
});
And in the HTML you do it like this:
<label class="checkbox-inline preferred">
<input type="checkbox" id="checkallmon" class="checkall" name="availmon[]" data-validation-rule="availmon" value="open">Fully Available
</label>
Didn't try this, but it should work. So it's bound to a class (used your checkall class) and the function gets the validation rule from the data attribute validation-rule. So you just have to assign checkall as class and data-validation-rule with the name of the rule to any checkbox.
You could also use the .attr('name') to use the name as "rule", but in my opinion the data attribute is a much cleaner way.
I hope I understood your question in the right way.

Get Closest Form to an Element in jQuery

I have this js/jquery script i wrote to check all checboxes with in a form. It works well but this checks all checkboxes that are on page irrespective of the form wrapper they are.
here is the function
function toggleCheck(state)
{ var checkboxes = jQuery("form input:checkbox");
if(state==true){checkboxes.prop('checked',true); }
if(state==false){ checkboxes.prop('checked',false); }
}
usage
<a id="check" href="#" onclick="javascript:toggleCheck(true);" class="btn">Select All</a>
<a id="uncheck" href="#" onclick="javascript:toggleCheck(false);" class="btn">Deselect All</a>
Note this works well but my problem is if i have
<form action="myaction-page">//some form elements and checkboxes </form>
and
<form action="myaction-page-2">//some form elements and checkboxes </form>
and i click the check all link in form1, all checkboxes gets check including those in form2.
Is there a way to separate them without introducing form ids or names?..this is because i have used it extensively in production code and to rewrite all will be trouble.
Any Help will be greatly appreciated.
P.S it is worth noting that the select all and deselect all are within both forms and both forms are on the same page.
Assuming your select/deselect links are inside the form, do:
function toggleCheck(state,elem) {
jQuery(elem).closest("form").find("input:checkbox").prop('checked', state);
}
And change your link JS to (passing the appropriate true/false parameter):
onclick="javascript:toggleCheck(false,this);"
jsFiddle example
The answer is: it depends on your DOM. If your <a> elements are inside the form, you could use $.closest():
function toggleCheck(state) {
$(this)
.closest("form")
.find("input[type=checkbox]")
.prop('checked', state);
}
I slightly altered your code to increase readability, performance (see the additional notes regarding the :checkbox selector) and be more "jQuery"-like.
[edit]
After reading the comments I rewrote the function, still on the assumption that the <a> elements are inside the <form>, this time also with a working jsFiddle:
function toggleCheck(state) {
$(document).find(event.target)
.closest("form")
.find("input[type=checkbox]")
.prop('checked', state);
}
[edit2]
And for the sake of completness regarding my comment about the order of the elements (jsFiddle):
function toggleCheck(state) {
var pos = $(document).find(event.target.localName + "." + event.target.className).index(event.target);
var $form = $($(document).find("form").get(Math.floor(pos/2)));
$form
.find("input[type=checkbox]")
.prop('checked', state)
}
[edit3]
The last edit, I promise. This time I ignore the default callback and do my own thing:
function toggleCheck(state) {
// either write the s tate now in a variable for
// the next callback
}
$(document).on("click", "a.btn", function(e) {
var $ele = $(this);
// or do some string exploration
var toggle = $ele.attr("onclick").indexOf("true") > -1;
var pos = $(document).find("a.btn").index($ele);
var $form = $($(document).find("form").get(Math.floor(pos/2)));
$form
.find("input[type=checkbox]")
.prop('checked', toggle);
});
Works without having to touch anything. But I wouldn't want to use this. ;-)
the .closest method will do what you want.
onclick:
onclick="toggleCheck.call(this,true);"
js:
function toggleCheck(state) {
var checkboxes = jQuery(this).closest("form").find("input:checkbox");
checkboxes.prop('checked',state || false);
}
You can also just apply a data-target to your anchors and eval based on the action of your form elements:
... data-target='myaction-page' ...
... checkboxes[i].form.getAttribute( 'action' ) ...
Shown in detail on this JSFiddle

retrieve the saved state for a collection of checkboxes from local storage after page reload

i've got a collection of 20 checkboxes like this here:
<div class="cbcell">
<input type="checkbox" class="checkbox" id="home_swimming_pool" name="Basen" value="35"> Basen
</div>
<div class="cbcell">
<input type="checkbox" class="checkbox" id="home_sauna" name="Sauna" value="45"> Sauna
</div>
with the following code i am saving and removing the checkbox state in the local storage which works very fine, also the filter function of dataTables works fine.
<script type="text/javascript" >
$(':checkbox').click(function(){
var name = $(this).attr('name');
var value = $(this).val();
if($(this).is(':checked')){
console.log( name, value ); // <- debug
oTable.fnFilter(name, value,false,true,false,true);
localStorage.setItem(this.name,'checked');
} else {
console.log( name, value ); // <- debug
oTable.fnFilter('',value,false,true,false,true);
localStorage.removeItem(this.name);
}
//})
});
</script>
Please tell me how to retrieve the state of each checkbox after a page reload. I tried it already with several functions and my last stand is:
$(document).ready(function() {
if (localStorage.getItem(this.value) == 'checked'){
$(this).attr("checked",true)
}
})
any help is highly appreciated.
Try this
$(':checkbox').each(function() {
$(this).prop('checked',localStorage.getItem(this.name) == 'checked');
});
In $(document).ready() function, this refers to the document, not to a checkbox, like in the $(':checkbox').click(). Plus if you think about it, you really need a way to iterate through your checkboxes. This is where .each() comes in. Inside the $(':checkbox').each() function, this will refer to a specific checkbox
Also it would be a good idea to check that localStorage is actually supported by the browser the code is running on, otherwise you will be getting errors.
a simple way is to wrap everything in an if (window.localStorage) { /* code here */}
Improved version
if (window.localStorage) {
$('.cbcell').on('click',':checkbox',function(){
var name = this.name;
var value = this.value;
if($(this).is(':checked')){
oTable.fnFilter(name, value,false,true,false,true);
//shorthand to check that localStorage exists
localStorage && localStorage.setItem(this.name,'checked');
} else {
oTable.fnFilter('',value,false,true,false,true);
//shorthand to check that localStorage exists
localStorage && localStorage.removeItem(this.name);
}
});
$(document).ready(function () {
$(':checkbox').each(function() {
$(this).prop('checked',localStorage.getItem(this.name) == 'checked');
});
});
}
Finally may I suggest spending some time going through the excellent Try jQuery tutorial at http://try.jquery.com/

Javascript modify parameters of an element's event function

I'm wondering if there is a more elegant means of modifying the parameter of an onclick event. I have a table that I am dynamically adding/removing elements from and I re-index the rows. Each row has a delete link that has the row's index (and a duplicate link) that needs to update its parameter to match the modified row id.
Currently my code looks like (simplified)
<a onclick="delRow(1)">delete</a>
and the javascript:
...
html = element.innerHTML;
html = html.replace(/dupRow(\\d+)/g, "dupRow(" + newIndex + ")");
html = html.replace(/delRow(\\d+)/g, "delRow(" + newIndex + ")");
element.innerHTML = html
and I would like it to become something along the lines of
if (element.onclick != null) {
element.onclick.params[0] = newIndex;
}
Any such way of accomplishing this? I also have jQuery if this helps.
Updates:
So thanks to the glorious help of #rich.okelly I have solved my issue
<script>
...
var newRow = '\
<tr>\
<td class="index" col="0">0</td>\
<td>this is content...</td>\
<td>Del</td>\
</tr>';
// re-index table indices in a non-efficient manner
function reIndexTable() {
$("#rpc-builder-table").find('.index').each(function (i) {
$(this).html(i)
})
}
// add row
function addRow() {
for (i = 0; i < $('#addRowCount').attr("value"); i++) {
$("#rpc-builder-table").append(newRow);
}
reIndexTable();
}
$(document).ready(function () {
// add row button
$('#addRowsButton').on('click', function () {
addRow();
});
// delete row
$('#rpc-builder-table').on('click', 'td a[row-delete="true"]', function () {
$(this).closest('tr').remove();
reIndexTable();
});
...
}
</script>
...
<div>
<label>Rows to add: </label>
<input id="addRowCount" value="1" size="2" />
<button id="addRowsButton">Add Row(s)</button>
</div>
<div><table id="rpc-builder-table"><tbody>
<tr>
<th>Idx </th>
<th>Some content (1)</td>
</tr>
</tbody></table></div>
...
I used the .on() function instead of the suggested .delegate() function since it is deprecated. Solution works well - hope it helps someone :)
If you change your html to something similar to:
<tr>
<td>
delete
</td>
</tr>
Then your javascript can be something like:
$('td a[data-delete="true"]').on('click', function() {
$(this).closest('tr').remove();
});
Update
If rows are added dynamically to a pre-exising table (table is interchangeable for any parent element), you can use the delegate method like so:
$('table').delegate('td a[data-delete="true"]', 'click', function() {
$(this).closest('tr').remove();
});
Instead of inline handlers, use event delegation to attach event handlers
$("#tableID").delegate("a", "click", delRow);
$("#tableID").on("click", "a", delRow); //jQuery 1.7
Inside the handler,
var row = $(this).closest("tr").index(); //Get the index of the parent row
Inline handlers get parsed into a function:
function onclick() {
delRow(1);
}
so changing them is difficult. Your example rewrites the entire row with the new parameter, which is bad practice.
The most brain dead solution is getting rid of the parameters and setting a variable isntead.
var row_to_dup = 42;
$("#a_row_dupper").bind('click', function (){
dupItem(row_to_dup);
});
//changing the row to dup
row_to_dup = 17;

Categories