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();
};
...
};
Related
This should be trivial but I'm having issues...
Basically what I am trying to do is append a new "div" to "selected-courses" when a user clicks on a "course". This should happen if and only if the current course is not already in the "selected-courses" box.
The problem I'm running into is that nothing is appended to the "selected-courses" section when this is executed. I have used alert statements to make sure the code is in fact being run. Is there something wrong with my understanding of the way .on and .each work ? can I use them this way.
Here is a fiddle http://jsfiddle.net/jq9dth4j/
$(document).on("click", "div.course", function() {
var title = $( this ).find("span").text();
var match_found = 0;
//if length 0 nothing in list, no need to check for a match
if ($(".selected-course").length > 0) {
match_found = match(title);
}
if (matched == 0) {
var out = '<div class="selected-course">' + '' + title + ''+'</div>';
$("#selected-box").append(out);
}
});
//checks to see if clicked course is already in list before adding.
function match(str) {
$(".selected-course").each(function() {
var retval = 0;
if(str == this.text()) {
//course already in selected-course section
retval = 1;
return false;
}
});
return retval;
}
There was a couple of little issues in your fiddle.
See fixed fiddle: http://jsfiddle.net/jq9dth4j/1/
function match(str) {
var retval = 0;
$(".selected-course").each(function() {
if(str == $(this).text()) {
retval = 1;
return false;
}
});
return retval;
}
You hadn't wrapped your this in a jquery object. So it threw an exception saying this had no method text().
Second your retval was declared inside the each so it wasn't available to return outside the each, wrong scope.
Lastly the if in the block:
if (matched== 0) {
var out = '';
out += '<div class="selected-course">' + '' + title + ''+'</div>';
$("#selected-box").append(out);
}
was looking at the wrong variable it was looking at matched which didn't exist causing an exception.
Relying on checking what text elements contain is not the best approach to solve this kind of question. It is prone to errors (as you have found out), it can be slow, it gives you long code and it is sensitive to small changes in the HTML. I would recommend using custom data-* attributes instead.
So you would get HTML like this:
<div class="course" data-course="Kite Flying 101">
<a href="#">
<span>Kite Flying 101</span>
</a>
</div>
Then the JS would be simple like this:
$(document).on('click', 'div.course', function() {
// Get the name of the course that was clicked from the attribute.
var title = $(this).attr('data-course');
// Create a selector that selects everything with class selected-course and the right data-course attribute.
var selector = '.selected-course[data-course="' + title + '"]';
if($(selector).length == 0) {
// If the selector didn't return anything, append the div.
// Do note that we need to add the data-course attribute here.
var out = '<div class="selected-course" data-course="' + title + '">' + title + '</div>';
$('#selected-box').append(out);
}
});
Beware of case sensitivity in course names, though!
Here is a working fiddle.
Try this code, read comment for where the changes are :
$(document).on("click", "div.course", function () {
var title = $(this).find("span").text().trim(); // use trim to remove first and end whitespace
var match_found = 0;
if ($(".selected-course").length > 0) {
match_found = match(title);
}
if (match_found == 0) { // should change into match_found
var out = '';
out += '<div class="selected-course">' + '' + title + '' + '</div>';
$("#selected-box").append(out);
}
});
function match(str) {
var retval = 0; // this variable should place in here
$(".selected-course").each(function () {
if (str == $(this).find('a').text().trim()) { // find a tag to catch values, and use $(this) instead of this
retval = 1;
return false;
}
});
return retval; // now can return variable, before will return undefined
}
Updated DEMO
Your Issues are :
1.this.text() is not valid. you have to use $(this).text().
2.you defined var retval = 0; inside each statement and trying to return it outside each statement. so move this line out of the each statement.
3.matched is not defined . it should be match_found in line if (matched == 0) {.
4. use trim() to get and set text, because text may contain leading and trailing spaces.
Your updated JS is
$(document).on("click", "div.course", function () {
var title = $(this).find("span").text();
var match_found = 0;
if ($(".selected-course").length > 0) {
match_found = match(title);
}
if (match_found == 0) {
var out = '<div class="selected-course">' + '' + title + '' + '</div>';
$("#selected-box").append(out);
}
});
function match(str) {
var retval = 0;
$(".selected-course").each(function () {
if (str.trim() == $(this).text().trim()) {
retval = 1;
return false;
}
});
return retval;
}
Updated you Fiddle
I've got an issue with jQuery's autocomplete. What I am trying to do is show a suggestions list based on input. So, for instance, on input class="font" I want to have a list of font sizes and on input class="color" to have a list of color predictions.
Here is what I have:
function suggestions(input, element) {
var suggestions = [];
if (element.hasClass("color") !== -1) {
var i = 0;
while (i < 100) {
suggestions.push("color" + i.toString()); // for testing purpose
i++;
}
} else {
var nr = 1;
while (nr < 1025) {
suggestions.push(nr.toString() + "px");
nr = nr + 1;
}
}
$(element).autocomplete({
minLength: 1,
source: function (request, response) {
var counter = 0;
var filteredArray = $.map(suggestions, function (item) {
if (item.startsWith(request.term) && counter < 10) {
counter = counter + 1;
return item;
} else {
return null;
}
});
response(filteredArray);
},
autoFocus: true
});
}
The thing is, it works perfectly when I test it for inputs having any class except 'color'. When it detects a class with 'color', it will build the suggestions array accordingly but will refuse to get into the anonymous function inside autocomplete - source. Which is odd to me, 'cause the array is always constructed and the autocomplete should always be hit.
Any ideas?
Thanks!
jQuery's .hasClass() returns boolean value, so you code should look like:
if (element.hasClass("color")) { ... }
Try this JSFiddle (type symbol "c")
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.
I am trying to get this snip of code to work in a while loop instead of an if.
I need each instant of num_# to not be displayed if the printLoad_# val is empty. So if printLoad_1 value = nothing, the Num_1 would not be displayed, and then the printLoad_2 would check to see if its num_2 is empty and so on.
The problem I am having is the function stops before checking each section.
Im not sure if a do-while will work.
$(document).ready(function() {
if(document.getElementById("printLoad_1").value == "")
{
document.getElementById('num_1').style.display = 'none';
}
if(document.getElementById("printLoad_2").value == "")
{
document.getElementById('num_2').style.display = 'none';
}
if(document.getElementById("printLoad_3").value == "")
{
document.getElementById('num_3').style.display = 'none';
}
if(document.getElementById("printLoad_4").value == "")
{
document.getElementById('num_4').style.display = 'none';
}
if(document.getElementById("printLoad_5").value == "")
{
document.getElementById('num_5').style.display = 'none';
}
});
Have you considered just compositing the strings instead of this verbose construction? Something like this:
for( var i=1; i<=5; i++ ) {
if( document.getElementById('printLoad_'+i).value === '' ) {
document.getElementById('num_'+i).style.display = 'none';
}
}
Assuming you're using jQuery and that your elements are in order, I'd forget about ID's. If you use common classes, say .printload and .num, then you can easily target elements by index like:
$('.printload').each(function(i){
if (!this.value) $('.num').eq(i).hide();
});
if you have a variable amount of printLoad and num:
var i = 1,
pl=document.getElementById('printLoad_'+i),
num = document.getElementById('num_'+i);
while(pl !== null && num !== null){
if(pl.value === ""){
num.style.display = 'none';
}
i++;
pl=document.getElementById('printLoad_'+i),
num = document.getElementById('num_'+i);
}
Here is a slight modification of Ethan's answer that "works dynamically". I've also updated it to use jQuery. This could be handled cleaner if CSS classes and a hierarchy relationship were used, but that would affect how the DOM needed to be generated ..
for (var i = 1; /* break */; i++) {
var printEl = $('#printLoad_' + i)
if (printEl.length) {
if (!printEl.val()) {
$('#num_' + i).css({display: 'none'})
}
} else {
// No #printLoad_N, guess we're done looking
break
}
}
Per #elclanr 's answer:
Use common classes, and target elements by index, it'll be much simpler.
Set your "printLoad" elements to class='printLoad' and your "num" elements to class='num'. Then...
for (i=0;i<document.getElementByClass('printLoad').length;i++)
{
if (document.getElementByClass('printLoad')[i].value == "")
{
document.getElementByClass('num')[i].style.display='none';
}
}
I been researching on Show/Hide javascript and pushed it further with a mouseover effect to achieve what I want. I've set up a Fiddle for better accessibility. However, I now want to push it by having up to 4 different text areas ("Click here for more information"), and each text area would have more hover text as I tried to show in the HTML code itself. The javascript that I used and edited now has "ID"s corresponding to "0" and "1" which wouldnt work for my current HTML code as it has funky names like "uu3308-10" (made with Adobe Muse). Now, I'm wonder what variables would I have to change within the Javascript to make it function properly and is there a way to compile this code so it works with at least 11 other "Click here for more information" points?
Note: The current javascript makes showMoreText2 appear under both showMoreText areas (would like to make only one hover text appear at a time).
CLICK HERE FOR THE FIDDLE -- > http://jsfiddle.net/TPLOR/vy6nS/
Thanks, I hope this was helpful enough. =)
kinda hackish: (see http://jsfiddle.net/vy6nS/30/ )
window.onload = function() {
var elems1 = document.getElementsByClassName("expander");
for (i = 0; i < elems1.length; i++) {
elems2 = elems1[i].childNodes;
for (x = 0; x < elems2.length; x++) {
if (elems2[x].className == "toggle") elems2[x].onclick = function() {
showMore(0, this);
};
else if (elems2[x].className == "showMoreText") {
elems2[x].onmouseover = function() {
showChilds("block", this);
};
elems2[x].onmouseout = function() {
showChilds("none", this);
};
}
}
}
};
function get_nextsibling(n) {
x = n.nextSibling;
while (x.nodeType != 1) {
x = x.nextSibling;
}
return x;
}
function showChilds(disp, elem) {
get_nextsibling(elem).style.display = disp;
}
function showMore(disp, elem) {
var children = elem.parentNode.childNodes;
for (i = 0; i < children.length; i++) {
if (disp == 0 && children[i].className == "showMoreText") {
children[i].style.display = children[i].style.display == "none" ? "block" : "none";
}
}
}