Filtering multiple columns

Filtering multiple columns

kthorngrenkthorngren Posts: 21,682Questions: 26Answers: 5,019

I'm trying to understand the second example here:
https://datatables.net/reference/api/filter()#Examples

var table = $('#example').DataTable();
 
var filteredData = table
    .columns( [0, 1] )
    .data()
    .eq( 0 )
    .filter( function ( value, index ) {
        return value > 20 ? true : false;
    } );

My lack of understanding is probably due to my entry level Javascript skills. I think my issue is understanding what .eq(0) is actually doing. What I see is only column 0 is evaluated in the filter function. Actually it looks like eq(0) references the first column listed in .columns( [0, 1] ). But if .eq(0) is removed then both columns would be evaluated in the function. That idea makes sense but I have a couple questions:

  1. I've read the eq() doc but seem to missing a key concept. If the above is evaluating the first element in .columns( [0, 1] ) then it would seem .eq(1) would evaluate the second. This actually returns a null value. This leads me to believe .eq(0) references something else but I'm not sure what.

  2. The above returns only the data from column 0 where I expected both 0 and 1. I understand that eq() affects the result set and thats probably why. How would this be restructured to return both columns?

Kevin

Answers

  • allanallan Posts: 64,028Questions: 1Answers: 10,555 Site admin
    Answer ✓

    My lack of understanding is probably due to my entry level Javascript skills.

    With respect, I rather think you levelled up a while back!

    I think my issue is understanding what .eq(0) is actually doing.

    Actually - I think its more that its a really bad example. It would be rewritten as table.column( 0 ).data().filter( ... ) because that is all that example is doing!

    Instead of using eq() it should really be using flatten()!

    What is happening is that the data structure returned by columns().data() reflects the multiple columns nature of the - i.e. it is 2D, so we can't just run filter() on it (at least not easily). Loop functions like filter() work best on 1D data arrays, so flatten() in this case will reduce the 2D array to 1D.

    For -eq() it was taking only the data from the first column, so the second was being ignored! The example was wrong (fix - thanks for flagging that up!).

    What might make more sense of all of the above is going to a DataTable example page and running table.columns( [ 0, 1 ] ).data() and have a look at the structure of the returned object in the browser's console - you'll see its 2D structure there.

    Allan

  • kthorngrenkthorngren Posts: 21,682Questions: 26Answers: 5,019

    table.columns( [ 0, 1 ] ).data() and have a look at the structure of the returned object in the browser's console - you'll see its 2D structure there

    Doing lots of that :-)

    I see how '-api flatten()` works, good to know. Two more questions:

    For this example is it expected that .eq(1) would make a 1D array of the 2nd column's values to filter?

    table.columns( [ 0, 1 ] ) returns a 2D array of the two columns. But table.columns( [ 0, 1 ] ).data().flatten().filter(...) returns a 1D array of the values that match. Initially I was expecting both columns to be returned if the filter matched. Guess its not a question just an observation.

    Thanks for the clarification.

    Kevin

  • allanallan Posts: 64,028Questions: 1Answers: 10,555 Site admin

    For this example is it expected that .eq(1) would make a 1D array of the 2nd column's values to filter?

    Basically yes. "Make an array" possibly isn't quite the right terminology. It pulls the array out of the existing structure (although it is a new DataTables API instance).

    returns a 1D array of the values that match

    Yes - because flatten() will make it a 1D array. The filter() method could be made to work on the 2D structure, you are absolutely correct in that regard. I just haven't done it that way so its as much like the Array.prototype.filter method as possible.

    Allan

  • kthorngrenkthorngren Posts: 21,682Questions: 26Answers: 5,019

    For this example is it expected that .eq(1) would make a 1D array of the 2nd column's values to filter?

    Basically yes. "Make an array" possibly isn't quite the right terminology. It pulls the array out of the existing structure (although it is a new DataTables API instance).

    When I try .eq(1) I get null instead of the 2nd column. I can build a test case if you want.

    Kevin

  • rmawanirmawani Posts: 6Questions: 1Answers: 1
    edited March 2017 Answer ✓

    Hey guys,

    Please check out this Fiddle for a test case...

    You'll see that if you try to replace the index within the eq() call with anything other than the first column, the result will be null.

    Riz

  • allanallan Posts: 64,028Questions: 1Answers: 10,555 Site admin
    Answer ✓

    Embarrassingly that's a bug in the eq() method.

    Although it might be a trivial fix in the code, conceptually how I've explained the method above doesn't exactly align with what the code currently does, and thus I'm slightly concerned about introducing backwards compatibility issues if I just fix it.

    I'm going to have to spend a little bit of time fiddling with it and making sure everything is on the straight and narrow.

    Thanks!

    Allan

  • kthorngrenkthorngren Posts: 21,682Questions: 26Answers: 5,019

    Just silently remove the example from the page and delete this thread ;-)

    In the meantime maybe providing a workaround example (Riz's code possibly) would be a great help to others.

    Kevin

  • rmawanirmawani Posts: 6Questions: 1Answers: 1
    edited March 2017

    Thanks for the headsup, Allan! Absolutely nothing to be embarrassed about here as bugs are a fact of life in our world.

    Thanks again for all your hard work, Allan. You've done an absolutely bang up job on this beautiful and ultra-useful JQuery plugin!

  • allanallan Posts: 64,028Questions: 1Answers: 10,555 Site admin

    Thank you both for your input :smile:. Its extremely rare that a thread gets deleted. And certainly not to cover up my mistakes ;-). I'm proud of some of them...

    The workaround is to use Array syntax:

    var table = $('#example').DataTable();
      
    var filteredData = table
        .columns( [0, 1] )
        .data();
    
    var column1Data = filteredData[1];
    

    column1Data is actually technically a plain Javascript array there rather than a DataTables API instance, but it will still have a filter method since that is available on the array.

    Allan

  • kthorngrenkthorngren Posts: 21,682Questions: 26Answers: 5,019

    Thank you both for your input :smile:. Its extremely rare that a thread gets deleted. And certainly not to cover up my mistakes ;-). I'm proud of some of them...

    Sorry, I was joking about covering up the problem because I know Allan wouldn't do that :-)

    Thanks for the help!

    Kevin

  • rmawanirmawani Posts: 6Questions: 1Answers: 1

    Thanks for your workaround Allan!

    It made me think about my previous workaround and got me to here which is by far more efficient, not to mention flexible, than what I had previously!

    Thanks again!

  • allanallan Posts: 64,028Questions: 1Answers: 10,555 Site admin
    edited May 2017 Answer ✓

    I'm back up to speed with this one. On reviewing the eq() method I had actually mistaken its purpose when I replaced before, completely forgetting what I had intended it for...

    Basically it is for use with DataTables API instance which contain multiple table references and you want to reduce it to just a single table (e.g. consider initialising two or more tables with $('table.dataTable').DataTable()).

    It was not intended to provide access to the underlaying data. For that array syntax is the way to do that at the moment.

    Having said that, I have just committed a new method called get() which is modelled of the jQuery method of exactly the same name and it just provides a different method to get the data - e.g. [0] would be the same as .get(0).

    This is the commit however it is on a separate branch, so it will be a little while before I merge it down into master and thus for it to appear in the nighties. (typo - nighlies)

    Regards,
    Allan

  • tangerinetangerine Posts: 3,365Questions: 39Answers: 395

    ....for it to appear in the nighties.

    Please, please don't let things start appearing in their nighties.

  • kthorngrenkthorngren Posts: 21,682Questions: 26Answers: 5,019

    Great, thanks for the update.

    Kevin

  • allanallan Posts: 64,028Questions: 1Answers: 10,555 Site admin
    edited May 2017

    One thing is for sure, I won't be appearing in my nightie. If anything is going to drive people away it would be that! ;-)

    edit - I don't have a nightie. Honest...

This discussion has been closed.