DataTables logo DataTables

via Ad Packs
ColVis: new plug-in for DataTables - user control of column visibility
  • allanallan
    Posts: 15,504
    Hello all,

    I'm pleased to announce the release of a new plug-in for DataTables called ColVis. ColVis will put a button next to the table, which when activated will show a list of the columns in the table, and provide the end-user with the option for showing, or hiding the columns. This can be particularly useful when there are a large number of columns, and you want to provide the end user with the option of selecting which columns they want to see.

    Example:
    http://datatables.net/release-datatables/extras/ColVis/

    Download (place the extracted folder into the "extras" folder in the DataTables distribution):
    http://datatables.net/releases/ColVis-1.0.1.zip

    Features:
    - Ability to exclude columns for the selection list
    - Button activation can be click or mouseover
    - Full style control

    Thanks to giorgio79 for the donation to make this plug-in possible :-)

    Enjoy!
    Allan
  • I really like this idea and especially the ease and looks of how it was implemented. Great job.

    I am going to test this later with the print functionality to see if the excluded columns are left out from the print button when using TableTools.
  • How can I preset column visibility when the table gets rendered on page load?

    I would like to have several column being deactivated and when activated will be shown (no exlusion for visibility toggle, just being in the invisible state).
  • allanallan
    Posts: 15,504
    http://datatables.net/usage/columns#bVisible allows control of this.

    Allan
  • I have a problem using both ColVis and jeditable as the callback defined in the jeditable init function seems to conflict with normal ColVis initialization.

    Here is the Firebug error:
    $(
    init_editable()servic...5603418 (Zeile 924)
    (?)(Object { name="json"})servic...5603418 (Zeile 1968)
    b()jquery...9223523 (Zeile 124)
    abort(Object { name="q"})jquery...9223523 (Zeile 129)
    [Break on this error] callback : function(value, settings) {}


    Has anyone succesfully used both ColVis and jeditable (the latter with a callback function) and can help me to fix this error?
  • Another problem using ColVis:

    In some datatables I get the following error when clicking the "Show/ Hide" Button:

    nButton is not defined
    [Break on this error] nHidden.style.top = (iDivY-iDivHeight-$(nButton).outerHeight())+"px";
    ColVis...5693097 (Zeile 471)
    >>> _fn_collections_show();
    ReferenceError: _fn_collections_show is not defined { message="_fn_collections_show is not defined", more...}
    >>> _fnCollectionShow();
    ReferenceError: _fnCollectionShow is not defined { message="_fnCollectionShow is not defined", more...}
  • The ColVis code seem to have a lot of references to TableTools classes. Is this an oversight? For example, I want ColVis to float left. But the div has a class of both ColVis and TableTools, makeing it trickier.
  • allanallan
    Posts: 15,504
    No this is intentional. The idea was that ColVis could take the same styling as TableTools if you wanted, so no need to include the ColVis stylesheet (although that is TableTools 2 - which is not yet released). They should be arranged such that any styling given to the ColVis classes will take priority.

    @jawosis: Can you give us a link please?

    Allan
  • I can't seem to get that to work. Do you have an example of using both TableTools and ColVis with independant formatting?
  • allanallan
    Posts: 15,504
    No I don't have an example of the two plug-ins working side by side on the web at the moment, but will look at putting one up at some point. Until then, editing the CSS is probably what it required, to separate the two out - just using additional constrains on the selectors for example.

    Allan
  • mshermsher
    Posts: 2
    I need to be able to toggle visibility of multiple groups of columns with one click.
    Is it possible to do? How would I do that?
  • allanallan
    Posts: 15,504
    It's not possible with the ColVis plug-in as it currently stands, but implementing your own method for doing that would simply be a case of setting the visibility on all the columns you want to show / hide in your group based on a single event action. It would probably be fairly straight forward to make ColVis do this if you poke around in the source.

    Allan
  • krojewkrojew
    Posts: 30
    I'm having "nButton is not defined" error every time I press the show/hide button. Is there a fix available?
  • allanallan
    Posts: 15,504
    Can you link us to an example of this happening please? I've not seen this happen with my own examples, so there could be something different about your setup.

    Allan
  • ColVis is a super neat plug-in, Thanks allan.

    A ColVis bug for you: When there are two databables and both tables have ColVis, the ColVis button on the 2nd table toggles the 1st table's columns. Tested in Firefox 3.6 and IE8
  • allanallan
    Posts: 15,504
    Hi genesplitter,

    Good call! Thanks for picking up on that. The problem comes about when initialising more than one table with a single DataTables call. What needs to happen is that the API index that DataTables is operating on should be changed as needed. This wasn't happening, but I've just committed a fix for it, which you can grab from here: http://github.com/DataTables/ColVis/blob/master/media/js/ColVis.js . It will be included in the next ColVis release.

    Regards,
    Allan
  • krojewkrojew
    Posts: 30
    @allan:
    Unfortunately I don't have a live example, but the problem can be tracked by looking at the source. In fnCollectionShow there is a reference to nButton in

    if ( iDivY + iDivHeight > iDocHeight )
    {
    	nHidden.style.top = (iDivY-iDivHeight-$(nButton).outerHeight())+"px";
    }
    

    but the variable is not set anywhere in the function. There is a reference to this.dom.button previously:

    var iDivY = parseInt(oPos.top + $(this.dom.button).outerHeight(), 10);
    

    So maybe nButton should be replaced by it?
  • allanallan
    Posts: 15,504
    Hi krojew,

    Good debugging - yup - that is exactly what it should be. Thanks for picking up on that! I've committed the fix to github (link above) and I'll publish it in a new version of ColVis soon.

    Thanks,
    Allan
  • Allan,

    sorry for the late reply.

    The nbutton bug is fixed in the latest release - thanks!

    The bug related to jeditable resolved itself changing the latest jquery.jeditable.js with the prior version.
  • PetahPetah
    Posts: 12
    Dont get me wrong, I love DataTables and this plugin is just what i need. But some of the names of your CSS classes are just insane.

    I mean:
    TableTools_Button
    TableTools_text_hover
    TableTools_collectionBackground
    Button
    disabled
    

    It doesn't look like your following any naming conventions, and classes like Button and disabled are bound to conflict with some peoples CSS.
  • allanallan
    Posts: 15,504
    Agreed - this is something that is going to be addressed soon. The next major release of DataTables is try to ensure that the class names are all brought into line. Frustrating that I didn't lay down hard guidelines for myself to follow initially, but something I intend to fix!

    Thanks for the feedback!

    Allan
  • lyiu18lyiu18
    Posts: 2
    I modified ColVis to have Group show/hide functionality. I am not a JavaScript pro, so may made some mistake here

    First define a data structure, user can enter with datatables init
    "aoGroups": [{"sName": "name display label here", "aiTargets": [list of int, col numbers]}]
    

    In ColVis
    		/**
    		 * List of columns (integers) which should be grouped together and use Group Name on the button
    		 *  @property aoGroups
    		 *  @type     Array
    		 *  @default  []
    		 */
    		"aoGroups": []
    

    Create a new method to loop through aoGroups, find out if a column is in the group, if it is first column of a group, return the Group, if it is in the Group but not the first one, ignore it, return null. If it is not in any Group, create a single element Group
    	/**
    	 * Loop through the columns in the table and as a new button for each one.
    	 *  @method  _fnFindGroup
    	 *  @param {int} target Column in question
    	 *  @returns {Node} Group
    	 *  @private 
    	 */
    	"_fnFindGroup": function ( target )
    	{
    		var
    			aiTargets, nGroup,
    			aoGroups = this.s.aoGroups;
    		
    		for ( var i=0, iLen=aoGroups.length ; i<iLen ; i++ )
    		{
    			nGroup = aoGroups[ i ];
    			aiTargets = nGroup.aiTargets;
    			if ((typeof aiTargets != "undefined")&&(aiTargets.length>0))
    			{
    				if (target == aiTargets[0])
    				{
    					if (typeof nGroup.sName == "undefined")
    					{
    						nGroup.sName = this.s.dt.aoColumns[target].sTitle;
    					}
    					
    					return nGroup;
    				}
    				else
    				{
    					if (typeof nGroup.extra == "undefined")
    					{
    						nGroup.extra = ","+aiTargets.slice(1).join(',')+",";
    					}
    					
    					if ( nGroup.extra.indexOf( ","+target+"," ) != -1 )
    					{
    						return null;
    					}
    				}
    			}
    		}
    		
    		return {"sName": this.s.dt.aoColumns[target].sTitle, "aiTargets": [target]};
    	},
    

    Modified the _fnAddButtons function
    	"_fnAddButtons": function ()
    	{
    		var
    			nGroup, nButton, 
    			sExclude = ","+this.s.aiExclude.join(',')+",";
    		
    		for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
    		{
    			if (( sExclude.indexOf( ","+i+"," ) == -1 )&&( (nGroup = this._fnFindGroup( i )) != null ))
    			{
    				nButton = this._fnDomColumnButton( nGroup );
    				this.dom.buttons.push( nButton );
    				this.dom.collection.appendChild( nButton );
    			}
    			else
    			{
    				this.dom.buttons.push( null );
    			}
    		}
    	},
    

    Modified the _fnDomColumnButton function to take Group as input
    	/**
    	 * Create the DOM for a show / hide button
    	 *  @method  _fnDomColumnButton
    	 *  @param {Node} nGroup Group in question
    	 *  @returns {Node} Created button
    	 *  @private 
    	 */
    	"_fnDomColumnButton": function ( nGroup )
    	{
    		var
    			that = this,
    		  nButton = document.createElement('button'),
    		  nSpan = document.createElement('span');
    		
    		nButton.className = !this.s.dt.bJUI ? "ColVis_Button TableTools_Button" :
    			"ColVis_Button TableTools_Button ui-button ui-state-default";
    		nButton.appendChild( nSpan );
    		$(nSpan).html(
    			'<span class="ColVis_radio"><input type="checkbox"></span>'+
    			'<span class="ColVis_title">'+nGroup.sName+'</span>' );
    		
    		$(nButton).click( function (e) {
    			var showHide = $('input',this).attr('checked')===true ? false : true;
    			if ( e.target.nodeName.toLowerCase() == "input" )
    			{
    				showHide = $('input',this).attr('checked');
    			}
    			
    			/* Need to consider the case where the initialiser created more than one table - change the
    			 * API index that DataTables is using
    			 */
    			var oldIndex = $.fn.dataTableExt.iApiIndex;
    			$.fn.dataTableExt.iApiIndex = that._fnDataTablesApiIndex.call(that);
    			for ( var i=0, iLen=nGroup.aiTargets.length ; i<iLen ; i++ )
    				that.s.dt.oInstance.fnSetColumnVis( nGroup.aiTargets[i], showHide );
    			$.fn.dataTableExt.iApiIndex = oldIndex; /* Restore */
    		} );
    		
    		return nButton;
    	},
    
  • allanallan
    Posts: 15,504
    Hi lyiu18,

    Very cool! Thanks for posting this! I'll have a look at how it might be integrated with the core code shortly! I'll post back when I've done that.

    Allan
  • bikabika
    Posts: 24
    I'm using ColVis with server side and I noticed it triggers an ajax call every time you check/uncheck a column.
    Is that necessary? can it be disabled via an option or a workaround?

    Overall a very good plug-in, really beneficial.
  • allanallan
    Posts: 15,504
    The reason it does an Ajax request is before of this code in fnSetColumnVis (which is a DataTables API function that the plug-in hooks into):

    			/* Do a redraw incase anything depending on the table columns needs it 
    			 * (built-in: scrolling) 
    			 */
    			_fnAjustColumnSizing( oSettings );
    			_fnDraw( oSettings );
    			_fnSaveState( oSettings );
    
    So it's needed to get the column sizes right, although we can get away without it when not using DataTables' scrolling options. At that point this code could be commented out. I've been thinking about making this an option in this function, and that could be passed up stream to ColVis. I've made a note in my to-do list.

    Regards,
    Allan
  • bikabika
    Posts: 24
    Thanks Allan.

    One more thing here, I use server-side on first call but if the # of rows is small I display all rows using "iDisplayLength": -1 and then I remove server-side via fnInitComplete like this:
    "fnInitComplete": function() {
    				this.fnSettings().oFeatures.bServerSide = false;
    				this.fnSettings().sAjaxSource = null;
    			},
    

    Now if I hide a column, no records are displayed (only displays the table headers) and it shows "showing 1 to 0 of x total records".

    Not sure if this is a bug or an invalid feature combination on my side
  • bikabika
    Posts: 24
    I think I know what happened.
    On first call with server-side on, the end count is like this:
    _fnDraw line 2920
    if ( oSettings.oFeatures.bServerSide )
    	{
    		iStart = 0;
    		iEnd = oSettings.aoData.length;
    }
    

    On subsequent calls now that I disabled server-side, iEnd = oSettings._iDisplayEnd; which somehow resolve to zero

    The work-around is I have to pass in _iDisplayEnd = number of rows along with disabling server-side
  • allanallan
    Posts: 15,504
    Yup this was a bug I found thanks to the unit tests the other day. If you use the nightly version of DataTables from the download page, it should address this issue.

    Regards,
    Allan
  • bikabika
    Posts: 24
    Until the new release comes in, I did a quick hack to prevent Ajax calls for col vis

    In Function: _fnDraw, I added noAjax
    function _fnDraw( oSettings, noAjax )
    

    A few lines down, check for its existence before doing the Ajax call:
    if ( oSettings.oFeatures.bServerSide && typeof noAjax == 'undefined' &&
    			     !_fnAjaxUpdate( oSettings ) )
    

    Then in Function: fnSetColumnVis, before it calls _fnDraw do the following:
    if ( oSettings.oFeatures.bServerSide ) {
    	_fnDraw( oSettings, true );
    }
    else {
    	_fnDraw( oSettings );
    }
    

    a little messy but did the trick for me.
  • When using ColVis together with a Footer Callback (for page analysis - not the whole table) the callback function doesn't work anymore as the corresponding column is out of scop: --> nCells[3] is undefined

    Any ideas to prevent this?
  • Hey Allan,

    Any luck on checking lyiu18's grouped column visibility code? I tried it out and it wasn't working for me; wondered if you had a chance yet to check it yourself.
  • erikdwerikdw
    Posts: 1
    hi Allan. Have you ever gotten back to looking at lyiu18's grouped column enhancement?

    I'm hopeful that the new 1.8 feature for grouping columns by colspan/rowspan might allow for this functionality, based on the wording here:
    http://datatables.net/beta/1.8/examples/advanced_init/complex_header.html

    It says: "In addition to the basic behaviour, DataTables can also take colspan and rowspans into account when working with hidden columns. The colspan and rowspan attributes for each cell are automatically calculated and rendered on the page for you. This also allows the ColVis extra for DataTables to work great with hidden columns."

    However, I'm not sure what those statements mean. I put one big th above all my other column headers (colspan 17 in my case) and it showed up, but it wasn't listed in the rows I can hide/show via ColVIs's menu above my table.
  • fhafha
    Posts: 4
    Hello Allan,

    I recently implemented this plug-in and due to my requirements I implemented also lyiu18's grouped column enhancement. For me it works just fine, he forgot to mention one important change for ColVis initialization, though. The following statement needs to be added to the _fnApplyCustomisation method:

    if ( typeof oConfig.aoGroups != 'undefined' )
    {
      this.s.aoGroups = oConfig.aoGroups;
    }

    If this whole enhancement is added to the main branch some people would highly appreciate it, I guess ;-)

    However, I found two more bugs in the recent version of ColVis, 1.0.4:

    1- I had to add the following statement in method _fnDomBackground after setting the opacity, because in IE7 (and IE8 in IE7 compatibility mode) neither a click on the Collection show/hide button nor somewhere else on the screen was hiding the Collection list of buttons:

    if ( jQuery.browser.msie && jQuery.browser.version == "7.0" ) {
        $(nBackground).css('background-color', 'white');
    }
    I honestly have no clue why exactly this works only with additional background set - I tried to debug it with some "hello world" output at first and wanted to emphasize its display with red background (IE7/IE8 debugging options are clearly devastating). As my application's background is mostly white or very light grey, setting this element's background to a fixed color didn't hurt me. But still: maybe there is a better solution available...


    2- Method _fnApplyCustomisation consists of two identical statements to set bRestore, I removed one of

    if ( typeof oConfig.bRestore != 'undefined' )
    {
      this.s.bRestore = oConfig.bRestore;
    }

    I didn't test this thoroughly though, maybe there needs to be another custom setting applied instead of the second bRestore? As for now, everything else works for me.

    Regards,
    fha
  • How do I get Colvis and Tabletools working together .... TAbletools looks fine , but the Colvis is displyaing the fields that i want to select/deselect , but I only see a small part of them , they are almost hidden behind the table that shows the data. Thanks for answer , but I made a mistake, spelled Colvis.css instead of ColVis.css . So now it works.

    But when using exclude columns via ColVis and exporting via TableTools , It doesn't work as I hoped.
    Print ok , PDF (almost looks ok, but text overlap ). Excel, csv and copy exports all columns also the excluded , unfortunately.
  • allanallan
    Posts: 15,504
    Sounds like it might be a z-index issue. Can you link to your page please?

    Allan
  • Hi, just wanted to say this is a great plugin. For all other users: you can create checkbox elements, assign the ID to the column ID (starting from 0), then use this snippet to toggle based on checkbox checked. Here's a quick example:

    <label><input type="checkbox" class="cb" id="0" checked="checked" /> Company</label>
    <label><input type="checkbox" class="cb" id="1" checked="checked" /> Description</label>
    <label><input type="checkbox" class="cb" id="2" checked="checked" /> URL</label>
    

    $("input[type='checkbox'].cb").change(function() {
      var checked = $(this).is(":checked");
      var id = $(this).attr("id");
      dTable.fnSetColumnVis(id, checked);
    });
    
  • semseosemseo
    Posts: 9
    Hi, Is there a way to get the users currently hidden columns e.g. 2,5,11 I want to store this to a database and then use
    aoColumnDefs": [ { "bVisible": false, "aTargets": [ 2,5,11 ] }
    so the selection is remembered between sessions... is this the best solution?

    Thanks, Chris.

    UPDATE
    Found a possible solution here:
    http://www.datatables.net/forums/discussion/3700/colvis-get-list-of-hidden-or-shown-columns/p1
  • GrantBGrantB
    Posts: 9
    Hm. When I click my checked boxes, nothing happens. They stay checked, and the column doesn't disappear. I don't see any errors in my JS console.

    Strangely, when I click an unchecked box, it works. (This column was set with bVisible=false.)

    So, somehow, I have a one-way checkbox (unchecked-to-checked). Anyone ever see this before?

    EDIT: Never mind, solved. I wasn't using the latest version of the plugin.
  • Do this work with server side??
  • allanallan
    Posts: 15,504
    @pajafumo - Yes

    @GrantB - Good to hear the latest versions work :-)

    Allan
  • I'm trying to use ColVis with FixedColumns. I've run into a few issues. When I select the Show/hide columns button, the fixed columns are still in the list (even thought they are fixed) and unchecked. I've fixed my first 2 columns on the left. If I accidentally check one of them in the Show/hide columns list, the column is inserted where my 3rd column is. This is strange. How do I a) remove fixed columns from the Show/hide list since they are always being shown and b) prevent fixed columns from being inserted in place of an existing column?

    Thank you in advance for your time and consideration.
  • Hi Allan,
    I have a requirement but not exactly the default design of colVis. In my requirement, I have to add a custom button on DataTables header (we call it Add remove column) on left side before starting the the first column. Click on that one Jquery dragable popup layer (using Jqyery UI) will open showing all the columns names with respective checkboxes. On right side the respective column position (header1, header2, etc) of each column will displayed. Now user can drag and drop any column upward/downward and place it there. So for example if column Username was at first position, now user can moved it at 5th position (assuming example datatable is having 5 or more columns). then user can make a choice of column visibility by checking corresponding checkbox. Till the time nothing will happen with data table. There will be a button called "Apply Changes". Clicking on that user made prefrences will be saved to database as well as datatable will re-arrange its columns according to user opted prefs. Dont know how to do or where to start.
    can you please suggest. Thanks in advance
  • ddudley3ddudley3
    Posts: 20
    I have a page right now, using ColVis, in which my grid and button are at the right most side of the screen, and my text is wrapping to the next line because of the length of the label and is either not readable or, if I set the option "sSize": "css", it's written on top of the border. and it looks bad.

    If I use firebug and manually adjust the width of the div and the left side of it it works... but these values seem to be calculated each time it drops down.

    So, my question is:

    Is it possible to set the ColVis Options in such a way as to have the Right side of the drop down to line up to the right side of the button and make the left value to be relative to the needed width of the div based on the text given?
  • ddudley3ddudley3
    Posts: 20
    btw you can see this behavior by going to

      http://live.datatables.net/evuwim/5
    

    and doing the real time preview
  • ddudley3ddudley3
    Posts: 20
    Setting the sAlign to right does make it align to the right side of the button, but it's still limiting the width too small.
  • wathertonwatherton
    Posts: 9
    can you prevent a user from deselecting all columns? When i deselect all available columns, my datatable, doesnt show that there are no results.
  • ddudley3ddudley3
    Posts: 20
    I adjusted the Show/Hide Button to the left of my grid and now the text is not wrapping...

    It's basing the drop down off the offset of the button. Can't tell if js is not adjusting the left of the div based on length of text or not.
  • jdpjdp
    Posts: 2
    This might be a silly question but how do I gain focus of the button and navigate it with keyboard only? I know how to do this with other jquery components (z-index, css focus) but I don't know how to do this with the sDom property alone?

    I also need to do this for the TableTools buttons as well?
  • allanallan
    Posts: 15,504
    You probably need to add a table index attribute to the buttons. They don't actually have this ability built in at the moment, but they should. I'll see about adding that ability for the next release of each package.

    Allan
  • jdpjdp
    Posts: 2
    Thanks for the quick reply. I've been looking into this feature all day. I added the tab index attributes. I had to put them on the inner buttons as well to get them to traverse ( I was hoping to not change the js file).

    My problem now is that I can't close the popup window. I think what I would have to do now is write my own key event listeners so this may be past my abilities.
  • allanallan
    Posts: 15,504
    Yes, you probably need to listen for key up and call a method to close the menu. It is unfortunate that the extras don't do that yet. They will at some point in future (I'm spending all my available time on DataTables 1.10 at the moment).

    Allan

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Support

Get useful and friendly help straight from the source.

In this Discussion