0

I'm using the .each function to hide/show columns of a table. But the problem is that the code is very slow in IE. After searching on internet I saw that could be because of my .each() function and $(this).

For more information why I'm using this code, you can look at this post: Hide/show column

This is my old code: include JQuery.min.js on page

javascript:

$(function () {
    $('table th').each(function (_id, _value) {
    if(_id > 2){
        if($(this).find("a").text()){
            $('<span class="ShowHide"><div style="width:175px; display: inline-block;">- '+$(this).find("a").text()+'</div></span>').appendTo($("#togglers")).click(function (e) {
                $('table td:nth-of-type(' + parseInt(_id + 1) + '),table th:nth-of-type(' + parseInt(_id + 1) + ')').toggle();
                e.preventDefault();
            });
        }
        else{
            if($(this).find("div").text()){
                $('<span class="ShowHide"><div style="width:175px; display: inline-block;">- '+$(this).find("div").text()+'</div></span>').appendTo($("#togglers")).click(function (e) {
                $('table td:nth-of-type(' + parseInt(_id + 1) + '),table th:nth-of-type(' + parseInt(_id + 1) + ')').toggle();
                e.preventDefault();
                });
                }
            }
        }
    });

});

HTML:

<div id="togglers">Show/Hide columns<br/></div>

I tried to convert my javascript with this code (Source: jQuery very slow in IE), but I think there is still a problem with my i(or _id) and _value...

$(function () {
var items = $('table th');
var $currentItem;

    for (var i = 0, j = items.length; i < j; i++) {
        $currentItem = $(items[i]); // in place of $(this)
        function (i, _value) {
            if(i > 2){
                if($currentItem.find("a").text()){
                    $('<span class="ShowHide"><div style="width:175px; display: inline-block;">- '+$currentItem.find("a").text()+'</div></span>').appendTo($("#togglers")).click(function (e) {
                        $('table td:nth-of-type(' + parseInt(i + 1) + '),table th:nth-of-type(' + parseInt(i + 1) + ')').toggle();
                        e.preventDefault();
                    });
                }
                else{
                    if($currentItem.find("div").text()){
                    $('<span class="ShowHide"><div style="width:175px; display: inline-block;">- '+$currentItem.find("div").text()+'</div></span>').appendTo($("#togglers")).click(function (e) {
                    $('table td:nth-of-type(' + parseInt(i + 1) + '),table th:nth-of-type(' + parseInt(i + 1) + ')').toggle();
                        e.preventDefault();
                    });
                    }
                }
            }
        }
    }
});

It's possible that I need to use other code. Any suggestion is welcome! Tnx.

Community
  • 1
  • 1
endeka
  • 131
  • 1
  • 15
  • 4
    The reason it's slow is because your code is a mess. For instance why do you need to iterate at all when you know you only want the fourth TH element and up ? – adeneo Jul 07 '14 at 07:46
  • Why are you doing `parseInt(_id + 1)`? `_id`, and `1`, are both numbers already. All you need to do is: `(_id + 1)` and the parentheses are just prevent the variables being concatenated to the string itself, rather than added together. – David Thomas Jul 07 '14 at 07:55
  • Check other post why I'm using this code... (http://stackoverflow.com/questions/24568739/hide-show-column/24569240) – endeka Jul 07 '14 at 08:14
  • @endeka jQuery adds some overhead. But the real problem is the way you are using it. :) – Yury Tarabanko Jul 07 '14 at 08:19
  • @YuryTarabanko last question: I want to "group" different columns like for example Color and Number would be "More info" on top. So you see on top "More info" and if you click on it column Color and Number are visible. Is this possible? – endeka Jul 08 '14 at 08:06
  • @endeka I think so. :) Why not? – Yury Tarabanko Jul 08 '14 at 08:28
  • @YuryTarabanko ok, but how? Because I'm trying it here but I can't make it work for 100%... The rows are hiding/showing, but I can't make "More info" shown in grey... – endeka Jul 08 '14 at 08:33
  • @YuryTarabanko this is what I have http://jsfiddle.net/Ap9sQ/3/ But for some reason it don't want to work on jsFiddle, I get "SCRIPT5009: '$' is undefined ". On my site it's working, but not for 100% as mentioned before. – endeka Jul 08 '14 at 09:01
  • @endeka `$` is not defined because you haven't linked jquery library (notice dropdown in the top left corner). As your current question has nothing to do to the original one I recommend you to post a new question. :) – Yury Tarabanko Jul 08 '14 at 09:31
  • @YuryTarabanko I understand. Done: http://stackoverflow.com/questions/24628809/hide-show-columns-how-to-group-columns – endeka Jul 08 '14 at 09:54
  • @YuryTarabanko Tnx for the help here. Could you please check my other post? I think I have the solution but I just want to know if it's good (or not too bad) code. Tnx in advance! – endeka Jul 08 '14 at 13:54

1 Answers1

2

Performance issue has nothing to do with .each. DOM is tens of times slower than any way to iterate collection you choose.

Instead of iterating table on every toggle you can make CSS do it for you. Demo.

$(function() {
    var togglers = $('#togglers'), //cache toggler ref
        addToggler = function(idx, text) {
            togglers.append('<span class="toggler" data-id="' 
                              + idx + '">' + text + '</span>');    
        },
        table = $('#table'), //cache table ref
        columns = 0;

    //generate styles for 100 columns table :)
    (function generateStyleSheet(len){
        var styles = [], i = 0;

        for(; i < len; i++) {
            styles.push('.hide-' + i + ' .column-' + i + ' {display: none;}') ;
        }

        $('<style>' + styles.join('\n') + '</style>').appendTo(document.body);
    }(100)) 

    //bind on click once using event delegation
    togglers.on('click', '.toggler', function(e){
        var id = $(e.target).toggleClass('pressed').data('id');
        table.toggleClass('hide-' + id);
    }); 

    //generate all togglers and count em
    table.find('th').each(function(idx, header){ 
        header = $(header);
        addToggler(idx, header.text()); //make toggler
        header.addClass('column-' + idx); //add class column-i
        columns++;
    });

    //add column-i class to tds
    table.find('td').each(function(idx, td) { 
        $(td).addClass('column-' + (idx%columns));
    });

});
Yury Tarabanko
  • 44,270
  • 9
  • 84
  • 98
  • I'm trying to use your code but for some reason I'm not getting in the function "table.find('th').each(function(idx, header)". Tried to add some alerts to see if I'm going in each function... – endeka Jul 07 '14 at 08:30
  • http://jsfiddle.net/tarabyte/s8Qds/ - works here. If you are trying this code somewhere else make sure you do have table with id of `table` :) – Yury Tarabanko Jul 07 '14 at 08:33
  • Indeed, this was the problem. But I don't have the id in advance. I know the table is the div with ID ctl00_MSO_ContentDiv. I need to use this code on +50 pages and on every page the id is different... – endeka Jul 07 '14 at 08:38
  • @endeka Well, use whatever selector that finds the table you need. You can even make a plugin by generalizing this code a little. – Yury Tarabanko Jul 07 '14 at 08:47
  • it's what I did, changed the selector and now it's working and it's much faster! ;) Tnx! – endeka Jul 07 '14 at 08:54
  • You are welcome. And by the way it is a general performance advice: reduce the amount of DOM access/modifications. If something can be accomplished without javascipt - do not use javascript. Especially for older browsers (IE < 9) :) – Yury Tarabanko Jul 07 '14 at 09:02
  • 1
    @endeka More OOP example that allows you to hide columns by name. http://jsfiddle.net/tarabyte/s8Qds/3/ – Yury Tarabanko Jul 07 '14 at 09:54