Working with change to 2 elements - javascript

I have the following code
jQuery(document).ready(function(jQ) {
jQ('.WorkType').on("change", function(){
if (jQ(this).val() == 'Standard Hours'){
jQ(this).closest('.DayTimeWrapper').find('.Hours').addClass("Calc_Hours");
jQ(this).closest('.DayTimeWrapper').find('.Hours').removeClass("Calc_Leave");
jQ(this).closest('.DayTimeWrapper').find('.Hours').removeClass("Calc_RDO");
}else if (jQ(this).val() == 'RDO'){
jQ(this).closest('.DayTimeWrapper').find('.Hours').addClass("Calc_RDO");
jQ(this).closest('.DayTimeWrapper').find('.Hours').removeClass("Calc_Leave");
jQ(this).closest('.DayTimeWrapper').find('.Hours').removeClass("Calc_Hours");
}else{
jQ(this).closest('.DayTimeWrapper').find('.Hours').addClass("Calc_Leave");
jQ(this).closest('.DayTimeWrapper').find('.Hours').removeClass("Calc_RDO");
jQ(this).closest('.DayTimeWrapper').find('.Hours').removeClass("Calc_Hours");
}
window.setTimeout(function () {
jQ(".Calc_Hours").sum("focusout", "#standard_hours");
jQ(".Calc_Leave").sum("focusout", "#leave_hours");
jQ(".Calc_RDO").sum("focusout", "#rdo_hours");
},1000);
})
})
This code traverses the dom on a change to the element with the class WorkType and modifies the class attributes of the Hours element situated within the div DayTimeWrapper. It then performs calculations and places the results to the elements with ID as specified.
It works perfectly
However i need to perform the same calculations on additional elements with the class set to setTime so i modified the code as follows
jQuery(document).ready(function(jQ) {
jQ('.WorkType,.setTime').on("change", function(){
if (jQ('.DayTimeWrapper').closest('.WorkType').val() == 'Standard Hours'){
jQ(this).closest('.DayTimeWrapper').find('.Hours').addClass("Calc_Hours");
jQ(this).closest('.DayTimeWrapper').find('.Hours').removeClass("Calc_Leave");
jQ(this).closest('.DayTimeWrapper').find('.Hours').removeClass("Calc_RDO");
if (jQ('.DayTimeWrapper').closest('.WorkType').val() == 'RDO'){
jQ(this).closest('.DayTimeWrapper').find('.Hours').addClass("Calc_RDO");
jQ(this).closest('.DayTimeWrapper').find('.Hours').removeClass("Calc_Leave");
jQ(this).closest('.DayTimeWrapper').find('.Hours').removeClass("Calc_Hours");
}else{
jQ(this).closest('.DayTimeWrapper').find('.Hours').addClass("Calc_Leave");
jQ(this).closest('.DayTimeWrapper').find('.Hours').removeClass("Calc_RDO");
jQ(this).closest('.DayTimeWrapper').find('.Hours').removeClass("Calc_Hours");
}
window.setTimeout(function () {
jQ(".Calc_Hours").sum("focusout", "#standard_hours");
jQ(".Calc_Leave").sum("focusout", "#leave_hours");
jQ(".Calc_RDO").sum("focusout", "#rdo_hours");
},1000);
})
})
This is not working and i am at pains to figure out why. The error in the console is
Uncaught SyntaxError: Unexpected token )
Any help to resolve this would be appreciated

You did not close the bracket after the first if statement. I've optimized your selectors for performance & readability:
jQuery(document).ready(function (jQ) {
jQ('.WorkType,.setTime').on("change", function () {
var $hours = jQ(this).closest('.DayTimeWrapper').find('.Hours');
var workType = jQ('.DayTimeWrapper').closest('.WorkType').val();
if (workType == 'Standard Hours') {
$hours.addClass("Calc_Hours");
$hours.removeClass("Calc_Leave");
$hours.removeClass("Calc_RDO");
} else if (workType == 'RDO') {
$hours.addClass("Calc_RDO");
$hours.removeClass("Calc_Leave");
$hours.removeClass("Calc_Hours");
} else {
$hours.addClass("Calc_Leave");
$hours.removeClass("Calc_RDO");
$hours.removeClass("Calc_Hours");
}
// The following code seems to be corrupt:
window.setTimeout(function () {
jQ(".Calc_Hours").sum("focusout", "#standard_hours");
jQ(".Calc_Leave").sum("focusout", "#leave_hours");
jQ(".Calc_RDO").sum("focusout", "#rdo_hours");
}, 1000);
})
});
Edit:
This seems to be what you want to do:
https://jsfiddle.net/mk07fof5/1/
$('.WorkType,.setTime').on("change", function() {
var $currRow = $(this).closest('.DayTimeWrapper'),
$allRows = $currRow.closest('.DayTimeTable').find('.DayTimeWrapper');
calculate($currRow); //pass the element which triggered the event
var CalcHours = 0,
MealHours = 0,
RdoHours = 0;
$allRows.each(function(i) {
$row = $(this);
var hours = ParseFloat($row.find('.Hours').val());
if(!hours) return;
var workType = $row.find('.WorkType').val();
switch (workType) {
case 'Standard Hours':
CalcHours += hours;
break;
case 'RDO':
RdoHours += hours;
break;
default:
MealHours += hours;
}
});
$("#standard_hours").html(CalcHours.toFixed(2));
$("#leave_hours").html(MealHours.toFixed(2));
$("#rdo_hours").html(RdoHours.toFixed(2));
});
Don't forget to wrap your table into this div:
<div class="DayTimeTable">[...]</div>

Related

Auto Nested Tree Auto Expand not working in IE11 but is working in Chrome

I have a nested tree which is an html table with buttons on each elements to get the child table via AJAX. This works when done manually in IE and in chrome but I have a link to "Expand All" which selects all down arrow images on the page and .click()'s them. This happens on a 600 millisecond loop until all images are clicked and tables are opened. Here is the code for the auto click loop.
function autoClick(searchElement, clickElement) {
setTimeout(function () {
if ($(searchElement).length > 0) {
$(searchElement).each(function () {
$(this).click();
});
$(clickElement).click();
}
}, 600);
return ($(searchElement).length);
}
It doesn't even to click the first levels of the tree because when I watch for the ajax calls on the network monitor, none are fired. Here is the expand and collapse functions which utilize the autoclick loop.
function expandClick() {
if (!collapseExecuting) {
expandExecuting = true;
numOfExpandElements = autoClick('img[src="../Images/details_open.png"]', '#expandLink');
if (numOfExpandElements == 0) {
expandExecuting = false;
}
}
}
function collapseClick() {
if (!expandExecuting) {
collapseExecuting = true;
numOfCollapseElements = autoClick('img[src="../Images/details_close.png"]', '#collapseLink');
if (numOfCollapseElements == 0) {
collapseExecuting = false;
}
}
}
Here's the Click event handler:
$('#requestsTable tbody td img[data-description="toggle"]').live('click', function () { //alt="expand/collapse"
// var nTr = this.parentNode.parentNode;
var parentid = this.parentNode.parentNode.parentNode.parentNode.id;
var item = this;
if (parentid == "requestsTable") {
getChild("request", requestTable, item, "RequestCustomers?RequestID=" + $(this).data("request"));
}
else if (parentid == "customerTable") {
getChild("customer", requestTable, item, ".." + $(this).data('url') + "?RequestID=" + $(this).data("customer"));
}
else if (parentid == "accountTable") {
getChild("account", requestTable, item, ".." + $(this).data('url') + "?AccountNum=" + $(this).data("account") + "&RequestID=" + $(this).data("request"));
}
});
If you need to see get child here it is too:
function getChild(details, rTable, item, getCall) {
var row = item.parentNode.parentNode;
var parentid = item.parentNode.parentNode.parentNode.parentNode.id;
var rowClass = 'accountDetails';
if (item.src.match('details_close')) {
/* This row is already open - close it */
item.src = "../Images/details_open.png";
$(item).attr('title', 'Expand');
rTable.fnClose(row);
}
else {
/* Open this row */
item.src = "../Images/details_close.png";
$(item).attr('title', 'Collapse');
//set the class of the row based on the model being returned.
if (details == 'request') {
rowClass = 'requestDetails';
} else if(details == 'customer') {
rowClass = 'customerDetails';
}
$.get(getCall, function (response) {
rTable.fnOpen(row, response, rowClass);
if (response.BatchComplete) {
$('#batchStatus').value('Batch Completed. Click here to send batch.');
}
});
}
}
I found what was happening. In my ExpandClick and CollapseClick functions I was selecting the elements via relative URLs in the SRC attribute. Apparently in IE (at least IE 11) these relative URLs are mapped and then displayed in the source as absolute URLs. In chrome it keeps the relative URLs as is in the source so my selector was able to target in Chrome but not IE.
Changed my selectors that I pass to the autoClick function and it worked:
function expandClick() {
if (!collapseExecuting) {
expandExecuting = true;
numOfExpandElements = autoClick('img[title="Expand"]', '#expandLink');
if (numOfExpandElements == 0) {
expandExecuting = false;
}
}
}
function collapseClick() {
if (!expandExecuting) {
collapseExecuting = true;
numOfCollapseElements = autoClick('img[title="Collapse"]', '#collapseLink');
if (numOfCollapseElements == 0) {
collapseExecuting = false;
}
}
}

Hiding columns in Dynatable

I'm hoping to replace my tables with Dynatable, but I need to be able to hide and show certain groups of columns to do so. I do this in the existing, regular html table by giving a group to each , for example:
<td class = "group1">cell value</td>
Then I have some hide and show javascript functions:
function hideCol(columnClass){
$('table .'+columnClass).each(function(index) {
$(this).hide();
});
$('ul#hiddenCols').append('<li id="'+columnClass+'">Show '+columnClass+'</li>');
}
function showCol(columnClass){
$('table .'+columnClass).each(function(index) {
$(this).show();
});
$('li#'+columnClass).remove();
}
$(document).ready(function() {
hideCol("Group2");
hideCol("Group3");
hideCol("Group4");
$('#radio1').click(function() {
/*$(this).parent().addClass("active").siblings().removeClass("active")*/
showCol("Group1");
hideCol("Group2");
hideCol("Group3");
hideCol("Group4");
});
Is there a reasonably straight forward way I can adapt Dynatable to do something similar? Is there a way I can assign classes to each and in a Dynatable?
Thanks a lot,
Alex
There is a setting that makes the data in each column inherit the class of the column's header. However, when doing this there appears to be a bug when sorting hidden columns, as I mention in this question.
I couldn't make this work with Dynatable, so I switched to Datatables, where hiding/sorting columns seems to be much more stable.
You can edit the source code of dynatable.js as follows and then use show() and hide() methods...
function DomColumns(obj, settings) {
...
this.hide = function(indexOrId) {
var columns = settings.table.columns;
if (typeof indexOrId == "number")
columns[indexOrId].hidden = true;
else {
for (var i = columns.length - 1; i >= 0; i--) {
if (columns[i].id == indexOrId) {
columns[i].hidden = true;
break;
}
}
}
obj.$element.find(settings.table.headRowSelector).children('[data-dynatable-column="' + indexOrId + '"]')
.first().hide();
obj.dom.update();
};
this.show = function(indexOrId) {
var columns = settings.table.columns;
if (typeof indexOrId == "number")
columns[indexOrId].hidden = false;
else {
for (var i = columns.length - 1; i >= 0; i--) {
if (columns[i].id == indexOrId) {
columns[i].hidden = false;
break;
}
}
}
obj.$element.find(settings.table.headRowSelector).children('[data-dynatable-column="' + indexOrId + '"]')
.first().show();
obj.dom.update();
};
...
};

how to attach click function to multiple divs without ID

I have a fade in function im trying to understand better. It works fine when I set up the
My question is if I have 8 links that already have the separate ID and class names how can I attach this function to each clickable link?
Is there a function to getElementbyClass or something and then just add the class to all my links?
here is my javascript:
var done = true,
fading_div = document.getElementById('fading_div'),
fade_in_button = document.getElementById('fade_in'),
fade_out_button = document.getElementById('fade_out');
function function_opacity(opacity_value) {
fading_div.style.opacity = opacity_value / 100;
fading_div.style.filter = 'alpha(opacity=' + opacity_value + ')';
}
function function_fade_out(opacity_value) {
function_opacity(opacity_value);
if (opacity_value == 1) {
fading_div.style.display = 'none';
done = true;
}
}
function function_fade_in(opacity_value) {
function_opacity(opacity_value);
if (opacity_value == 1) {
fading_div.style.display = 'block';
}
if (opacity_value == 100) {
done = true;
}
}
// fade in button
fade_in_button.onclick = function () {
if (done && fading_div.style.opacity !== '1') {
done = false;
for (var i = 1; i <= 100; i++) {
setTimeout((function (x) {
return function () {
function_fade_in(x)
};
})(i), i * 10);
}
}
};
// fade out button
fade_out_button.onclick = function () {
if (done && fading_div.style.opacity !== '0') {
done = false;
for (var i = 1; i <= 100; i++) {
setTimeout((function (x) {
return function () {
function_fade_out(x)
};
})(100 - i), i * 10);
}
}
};
Correcting the answer from BLiu1:
var fadeDivs = document.getElementsByClassName('fade');
for (var i=0, i<fadeDivs.length, i++){
// do stuff to all fade-divs by accessing them with "fadeDivs[i].something"
}
Have you considered using a javascript library like jQuery to manage this. They have some extensive, very easy to use "selectors" that allow you to easily get access to elements in the DOM and animate them with things like "fade ins" and "slides", etc. If you need more animations there are tons of plugins available for this. It also helps to deal with browser compatibility challenges too.
If you want to rely on pure JavaScript, you can use the document.getElementsByClassName() function defined here, but that function is only defined in IE9 and above as well as Safari, Chrome, FF, and Opera.
As said in the comments, there is a getElementsByClassName() method. Here is how you would use it.
for(var i=0; i<document.getElementsByClassName("fade").length; i++ ){
/*apply fade in function*/
}
I'm not sure whether getElementsByClassName() can detect one class name at a time. You might need regex for that.

jQuery "keyup" crashing page when checking 'Word Count'

I have a word counter running on a DIV and after typing in a few words, the page crashes. The browser continues to work (par scrolling) and no errors are showing in Chrome's console. Not sure where I'm going wrong...
It all started when I passed "wordCount(q);" in "keyup". I only passed it there as it would split-out "NaN" instead of a number to countdown from.
JS:
wordCount();
$('#group_3_1').click(function(){
var spliced = 200;
wordCount(spliced);
}) ;
$('#group_3_2').click(function(){
var spliced = 600;
wordCount(spliced);
}) ;
function wordCount(q) {
var content_text = $('.message1').text(),
char_count = content_text.length;
if (char_count != 0)
var word_count = q - content_text.replace(/[^\w ]/g, "").split(/\s+/).length;
$('.word_count').html(word_count + " words remaining...");
$('.message1').keyup(function() {
wordCount(q);
});
try
{
if (new Number( word_count ) < 0) {
$(".word_count").attr("id","bad");
}
else {
$(".word_count").attr("id","good");
}
} catch (error)
{
//
}
};
HTML:
<input type="checkbox" name="entry.3.group" value="1/6" class="size1" id="group_3_1">
<input type="checkbox" name="entry.3.group" value="1/4" class="size1" id="group_3_2">
<div id="entry.8.single" class="message1" style="height: 400px; overflow-y:scroll; overflow-x:hidden;" contenteditable="true"> </div>
<span class="word_count" id="good"></span>
Thanks in advanced!
This is causing an infinite loop if (new Number(word_count) < 0) {.
Your code is a mess altogether. Just study and start with more basic concepts and start over. If you want to describe your project to me in a comment, I would be glad to show you a good, clean, readable approach.
Update:
Part of having a good architecture in your code is to keep different parts of your logic separate. No part of your code should know about or use anything that isn't directly relevant to it. Notice in my word counter that anything it does it immediately relevant to its word-counter-ness. Does a word counter care about what happens with the count? Nope. It just counts and sends the result away (wherever you tell it to, via the callback function). This isn't the only approach, but I just wanted to give you an idea of how to approach things more sensefully.
Live demo here (click).
/* what am I creating? A word counter.
* How do I want to use it?
* -Call a function, passing in an element and a callback function
* -Bind the word counter to that element
* -When the word count changes, pass the new count to the callback function
*/
window.onload = function() {
var countDiv = document.getElementById('count');
wordCounter.bind(countDiv, displayCount);
//you can pass in whatever function you want. I made one called displayCount, for example
};
var wordCounter = {
current : 0,
bind : function(elem, callback) {
this.ensureEditable(elem);
this.handleIfChanged(elem, callback);
var that = this;
elem.addEventListener('keyup', function(e) {
that.handleIfChanged(elem, callback);
});
},
handleIfChanged : function(elem, callback) {
var count = this.countWords(elem);
if (count !== this.current) {
this.current = count;
callback(count);
}
},
countWords : function(elem) {
var text = elem.textContent;
var words = text.match(/(\w+\b)/g);
return (words) ? words.length : 0;
},
ensureEditable : function(elem) {
if (
elem.getAttribute('contenteditable') !== 'true' &&
elem.nodeName !== 'TEXTAREA' &&
elem.nodeName !== 'INPUT'
) {
elem.setAttribute('contenteditable', true);
}
}
};
var display = document.getElementById('display');
function displayCount(count) {
//this function is called every time the word count changes
//do whatever you want...the word counter doesn't care.
display.textContent = 'Word count is: '+count;
}
I would do probably something like this
http://jsfiddle.net/6WW7Z/2/
var wordsLimit = 50;
$('#group_3_1').click(function () {
wordsLimit = 200;
wordCount();
});
$('#group_3_2').click(function () {
wordsLimit = 600;
wordCount();
});
$('.message1').keydown(function () {
wordCount();
});
function wordCount() {
var text = $('.message1').text(),
textLength = text.length,
wordsCount = 0,
wordsRemaining = wordsLimit;
if(textLength > 0) {
wordsCount = text.replace(/[^\w ]/g, '').split(/\s+/).length;
wordsRemaining = wordsRemaining - wordsCount;
}
$('.word_count')
.html(wordsRemaining + " words remaining...")
.attr('id', (parseInt(wordsRemaining) < 0 ? 'bad' : 'good'));
};
wordCount();
It's not perfect and complete but it may show you direction how to do this. You should use change event on checkboxes to change wordsLimit if checked/unchecked. For styling valid/invalid words remaining message use classes rather than ids.
I think you should use radio in place of checkboxes because you can limit 200 or 600 only at a time.
Try this like,
wordCount();
$('input[name="entry.3.group"]').click(function () {
wordCount();
$('.word_count').html($(this).data('val') + " words remaining...");
});
$('.message1').keyup(function () {
wordCount();
});
function wordCount() {
var q = $('input[name="entry.3.group"]:checked').data('val');
var content_text = $('.message1').text(),
char_count = content_text.length;
if (char_count != 0) var word_count = q - content_text.replace(/[^\w ]/g, "").split(/\s+/).length;
$('.word_count').html(word_count + " words remaining...");
try {
if (Number(word_count) < 0) {
$(".word_count").attr("id", "bad");
} else {
$(".word_count").attr("id", "good");
}
} catch (error) {
//
}
};
Also you can add if your span has bad id then key up should return false;
See Demo

Js and Divs, (even <div> is difference)

I Have find a javascript code that works perfectly for showing a DIV.
but this code works only for showing one div for each page.
i want to include many DIVS for hiding and showing in the same page.
I was try to replace the div id and show/hide span id with a rundom php number for each include, but still is not working.
so how i have to do it?
the JS code:
var done = true,
fading_div = document.getElementById('fading_div'),
fade_in_button = document.getElementById('fade_in'),
fade_out_button = document.getElementById('fade_out');
function function_opacity(opacity_value) {
fading_div.style.opacity = opacity_value / 100;
fading_div.style.filter = 'alpha(opacity=' + opacity_value + ')';
}
function function_fade_out(opacity_value) {
function_opacity(opacity_value);
if (opacity_value == 1) {
fading_div.style.display = 'none';
done = true;
}
}
function function_fade_in(opacity_value) {
function_opacity(opacity_value);
if (opacity_value == 1) {
fading_div.style.display = 'block';
}
if (opacity_value == 100) {
done = true;
}
}
// fade in button
fade_in_button.onclick = function () {
if (done && fading_div.style.opacity !== '1') {
done = false;
for (var i = 1; i <= 100; i++) {
setTimeout((function (x) {
return function () {
function_fade_in(x)
};
})(i), i * 10);
}
}
};
// fade out button
fade_out_button.onclick = function () {
if (done && fading_div.style.opacity !== '0') {
done = false;
for (var i = 1; i <= 100; i++) {
setTimeout((function (x) {
return function () {
function_fade_out(x)
};
})(100 - i), i * 10);
}
}
};
Check out the Fiddle, you can edit code based on your needs ;)
$(function() {
$('.sub-nav li a').each(function() {
$(this).click(function() {
var category = $(this).data('cat');
$('.'+category).addClass('active').siblings('div').removeClass('active');
});
});
});
finaly i found my self:
<a class="showhide">AAA</a>
<div>show me / hide me</div>
<a class="showhide">BBB</a>
<div>show me / hide me</div>
js
$('.showhide').click(function(e) {
$(this).next().slideToggle();
e.preventDefault(); // Stop navigation
});
$('div').hide();
Am just posting this in case someone was trying to answer.

Categories