block by dhoboy 1ac430a7ca883e7a8c09

Sortable, Filterable Table

Full Screen

Sortable, Filterable table made with D3.js See the React.js version here

Note: This D3 version of the table doesn’t clear the search text onBlur. This allows you to sort the search results.

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
  background-color: #d1e5f0;
  font: 14px sans-serif;
}

#container {
  width: 100%;
  height: 100%;
  position: relative;
}

#title {
  font: 26px sans-serif;
  position: absolute;
  top: -40px;
  left: 450px;
}

#FilterableTable {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 40px;
  left: 20px;
}

.SearchBar { 
  display: inline; 
  position: relative;
  left: 1%;
}

.SearchBar input {
  position: relative;
  left: 2%;
}

table { 
  position: absolute;
  top: 40px;
  left: 20px;
  border-collapse: collapse;
  margin-bottom: 20px;
}

table a:link, a:visited { text-decoration: none; }

table a:hover, a:active { text-decoration: underline; }

table, th, td { border: 1px solid black; }

td, th {
  padding: 5px;
  text-align: center;
  height: 20px;
}

th {
  background-color: #4393c3;
  color: #d9f0a3;
}

td { background-color: #92c5de; }

tr:hover td { background-color: #edf8b1; }

</style>
<body>
<script src="//d3js.org/d3.v3.js"></script>
<script>

var column_names = ["Title","Views","Created On","URL"];
var clicks = {title: 0, views: 0, created_on: 0, url: 0};

// draw the table
d3.select("body").append("div")
  .attr("id", "container")

d3.select("#container").append("div")
  .attr("id", "FilterableTable");

d3.select("#FilterableTable").append("h1")
  .attr("id", "title")
  .text("My Youtube Channels")

d3.select("#FilterableTable").append("div")
  .attr("class", "SearchBar")
  .append("p")
    .attr("class", "SearchBar")
    .text("Search By Title:");

d3.select(".SearchBar")
  .append("input")
    .attr("class", "SearchBar")
    .attr("id", "search")
    .attr("type", "text")
    .attr("placeholder", "Search...");
  
var table = d3.select("#FilterableTable").append("table");
table.append("thead").append("tr"); 

var headers = table.select("tr").selectAll("th")
    .data(column_names)
  .enter()
    .append("th")
    .text(function(d) { return d; });

var rows, row_entries, row_entries_no_anchor, row_entries_with_anchor;
  
d3.json("data.json", function(data) { // loading data from server
  
  // draw table body with rows
  table.append("tbody")

  // data bind
  rows = table.select("tbody").selectAll("tr")
    .data(data, function(d){ return d.id; });
  
  // enter the rows
  rows.enter()
    .append("tr")
  
  // enter td's in each row
  row_entries = rows.selectAll("td")
      .data(function(d) { 
        var arr = [];
        for (var k in d) {
          if (d.hasOwnProperty(k)) {
		    arr.push(d[k]);
          }
        }
        return [arr[3],arr[1],arr[2],arr[0]];
      })
    .enter()
      .append("td") 

  // draw row entries with no anchor 
  row_entries_no_anchor = row_entries.filter(function(d) {
    return (/https?:\/\//.test(d) == false)
  })
  row_entries_no_anchor.text(function(d) { return d; })

  // draw row entries with anchor
  row_entries_with_anchor = row_entries.filter(function(d) {
    return (/https?:\/\//.test(d) == true)  
  })
  row_entries_with_anchor
    .append("a")
    .attr("href", function(d) { return d; })
    .attr("target", "_blank")
  .text(function(d) { return d; })
    
    
  /**  search functionality **/
    d3.select("#search")
      .on("keyup", function() { // filter according to key pressed 
        var searched_data = data,
            text = this.value.trim();
        
        var searchResults = searched_data.map(function(r) {
          var regex = new RegExp("^" + text + ".*", "i");
          if (regex.test(r.title)) { // if there are any results
            return regex.exec(r.title)[0]; // return them to searchResults
          } 
        })
	    
	    // filter blank entries from searchResults
        searchResults = searchResults.filter(function(r){ 
          return r != undefined;
        })
        
        // filter dataset with searchResults
        searched_data = searchResults.map(function(r) {
           return data.filter(function(p) {
            return p.title.indexOf(r) != -1;
          })
        })

        // flatten array 
		searched_data = [].concat.apply([], searched_data)
        
        // data bind with new data
		rows = table.select("tbody").selectAll("tr")
		  .data(searched_data, function(d){ return d.id; })
		
        // enter the rows
        rows.enter()
         .append("tr");
         
        // enter td's in each row
        row_entries = rows.selectAll("td")
            .data(function(d) { 
              var arr = [];
              for (var k in d) {
                if (d.hasOwnProperty(k)) {
		          arr.push(d[k]);
                }
              }
              return [arr[3],arr[1],arr[2],arr[0]];
            })
          .enter()
            .append("td") 

        // draw row entries with no anchor 
        row_entries_no_anchor = row_entries.filter(function(d) {
          return (/https?:\/\//.test(d) == false)
        })
        row_entries_no_anchor.text(function(d) { return d; })

        // draw row entries with anchor
        row_entries_with_anchor = row_entries.filter(function(d) {
          return (/https?:\/\//.test(d) == true)  
        })
        row_entries_with_anchor
          .append("a")
          .attr("href", function(d) { return d; })
          .attr("target", "_blank")
        .text(function(d) { return d; })
        
        // exit
        rows.exit().remove();
      })
    
  /**  sort functionality **/
  headers
    .on("click", function(d) {
      if (d == "Title") {
        clicks.title++;
        // even number of clicks
        if (clicks.title % 2 == 0) {
          // sort ascending: alphabetically
          rows.sort(function(a,b) { 
            if (a.title.toUpperCase() < b.title.toUpperCase()) { 
              return -1; 
            } else if (a.title.toUpperCase() > b.title.toUpperCase()) { 
              return 1; 
            } else {
              return 0;
            }
          });
        // odd number of clicks  
        } else if (clicks.title % 2 != 0) { 
          // sort descending: alphabetically
          rows.sort(function(a,b) { 
            if (a.title.toUpperCase() < b.title.toUpperCase()) { 
              return 1; 
            } else if (a.title.toUpperCase() > b.title.toUpperCase()) { 
              return -1; 
            } else {
              return 0;
            }
          });
        }
      } 
      if (d == "Views") {
	    clicks.views++;
        // even number of clicks
        if (clicks.views % 2 == 0) {
          // sort ascending: numerically
          rows.sort(function(a,b) { 
            if (+a.views < +b.views) { 
              return -1; 
            } else if (+a.views > +b.views) { 
              return 1; 
            } else {
              return 0;
            }
          });
        // odd number of clicks  
        } else if (clicks.views % 2 != 0) { 
          // sort descending: numerically
          rows.sort(function(a,b) { 
            if (+a.views < +b.views) { 
              return 1; 
            } else if (+a.views > +b.views) { 
              return -1; 
            } else {
              return 0;
            }
          });
        }
      } 
      if (d == "Created On") {
        clicks.created_on++;
        if (clicks.created_on % 2 == 0) {
          // sort ascending: by date
          rows.sort(function(a,b) { 
            // grep date and time, split them apart, make Date objects for comparing  
	        var date = /[\d]{4}-[\d]{2}-[\d]{2}/.exec(a.created_on);
	        date = date[0].split("-"); 
	        var time = /[\d]{2}:[\d]{2}:[\d]{2}/.exec(a.created_on);
	        time = time[0].split(":");
	        var a_date_obj = new Date(+date[0],(+date[1]-1),+date[2],+time[0],+time[1],+time[2]);
          
            date = /[\d]{4}-[\d]{2}-[\d]{2}/.exec(b.created_on);
	        date = date[0].split("-"); 
	        time = /[\d]{2}:[\d]{2}:[\d]{2}/.exec(b.created_on);
	        time = time[0].split(":");
	        var b_date_obj = new Date(+date[0],(+date[1]-1),+date[2],+time[0],+time[1],+time[2]);
			          
            if (a_date_obj < b_date_obj) { 
              return -1; 
            } else if (a_date_obj > b_date_obj) { 
              return 1; 
            } else {
              return 0;
            }
          });
        // odd number of clicks  
        } else if (clicks.created_on % 2 != 0) { 
          // sort descending: by date
          rows.sort(function(a,b) { 
            // grep date and time, split them apart, make Date objects for comparing  
	        var date = /[\d]{4}-[\d]{2}-[\d]{2}/.exec(a.created_on);
	        date = date[0].split("-"); 
	        var time = /[\d]{2}:[\d]{2}:[\d]{2}/.exec(a.created_on);
	        time = time[0].split(":");
	        var a_date_obj = new Date(+date[0],(+date[1]-1),+date[2],+time[0],+time[1],+time[2]);
          
            date = /[\d]{4}-[\d]{2}-[\d]{2}/.exec(b.created_on);
	        date = date[0].split("-"); 
	        time = /[\d]{2}:[\d]{2}:[\d]{2}/.exec(b.created_on);
	        time = time[0].split(":");
	        var b_date_obj = new Date(+date[0],(+date[1]-1),+date[2],+time[0],+time[1],+time[2]);
			          
            if (a_date_obj < b_date_obj) { 
              return 1; 
            } else if (a_date_obj > b_date_obj) { 
              return -1; 
            } else {
              return 0;
            }
          });
        }
      }
      if (d == "URL") {
        clicks.url++;
	    // even number of clicks
        if (clicks.url % 2 == 0) {
          // sort ascending: alphabetically
          rows.sort(function(a,b) { 
            if (a.thumb_url_default.toUpperCase() < b.thumb_url_default.toUpperCase()) { 
              return -1; 
            } else if (a.thumb_url_default.toUpperCase() > b.thumb_url_default.toUpperCase()) { 
              return 1; 
            } else {
              return 0;
            }
          });
        // odd number of clicks  
        } else if (clicks.url % 2 != 0) { 
          // sort descending: alphabetically
          rows.sort(function(a,b) { 
            if (a.thumb_url_default.toUpperCase() < b.thumb_url_default.toUpperCase()) { 
              return 1; 
            } else if (a.thumb_url_default.toUpperCase() > b.thumb_url_default.toUpperCase()) { 
              return -1; 
            } else {
              return 0;
            }
          });
        }	
      }      
    }) // end of click listeners
});
d3.select(self.frameElement).style("height", "780px").style("width", "1150px");	
</script>

data.json

 [
  {
   "thumb_url_default":"https://yt3.ggpht.com/-T0H7xR-9iA8/AAAAAAAAAAI/AAAAAAAAAAA/VA9CSBc5Q8A/s88-c-k-no/photo.jpg",
   "views":"105689500",
   "created_on":"2011-02-17T13:38:27Z",
   "title":"psychicpebbles",
   "id":"UC--BMyA2X4a9PGAo3lTuopg"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-Aqz_Yc964cU/AAAAAAAAAAI/AAAAAAAAAAA/0SkTB3eIHL8/s88-c-k-no/photo.jpg",
   "views":"229121344",
   "created_on":"2007-08-18T14:57:17Z",
   "title":"JustKiddingFilms",
   "id":"UC-A4oZF4AlOEdlyZWBCI0cQ"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-0b9t8DHdd-8/AAAAAAAAAAI/AAAAAAAAAAA/5xlL-R1Id1M/s88-c-k-no/photo.jpg",
   "views":"25690295",
   "created_on":"2006-07-05T08:01:16Z",
   "title":"Blue Table Painting",
   "id":"UC-aSLyvFLGEmNFcGomzL47w"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-_9beDwBjMJ4/AAAAAAAAAAI/AAAAAAAAAAA/Jv6rGoAyoz0/s88-c-k-no/photo.jpg",
   "views":18483830,
   "created_on":"2012-03-02T15:51:06Z",
   "title":"dillongoo",
   "id":"UC-B06UJxJ20HYv15lzrm9mA"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-JqTiqHU5_Hs/AAAAAAAAAAI/AAAAAAAAAAA/oGryI3Ig5U4/s88-c-k-no/photo.jpg",
   "views":197190215,
   "created_on":"2008-06-18T06:44:13Z",
   "title":"MoneySavingVideos",
   "id":"UC-dch3BP4gKHC4cec0PU1PA"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-o3Zx-Zz8bwA/AAAAAAAAAAI/AAAAAAAAAAA/ZHRS7TqQd8U/s88-c-k-no/photo.jpg",
   "views":430715,
   "created_on":"2006-08-03T11:22:11Z",
   "title":"SPLURT TV",
   "id":"UC-eeciTxV2kfY6teG3Hu_dQ"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-q03QTYLnRmM/AAAAAAAAAAI/AAAAAAAAAAA/6m7QYo0gRwA/s88-c-k-no/photo.jpg",
   "views":790458,
   "created_on":"2009-08-06T12:45:13Z",
   "title":"Adozie",
   "id":"UC-jDxvNUzbuFqDzRpAPbFYw"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-HozDGGP43lY/AAAAAAAAAAI/AAAAAAAAAAA/IKNqSHJZ4fw/s88-c-k-no/photo.jpg",
   "views":16371,
   "created_on":"2011-09-11T12:04:08Z",
   "title":"TheNoahHunt",
   "id":"UC-m0-lV8U6imr5zC-9RMlAA"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-nheWDZWkuaY/AAAAAAAAAAI/AAAAAAAAAAA/UUarZMj10wk/s88-c-k-no/photo.jpg",
   "views":7561518,
   "created_on":"2008-01-22T01:00:40Z",
   "title":"Karliene",
   "id":"UC-QCyIGEY6DzNyQOnyxIaEg"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-QgxITA1sSog/AAAAAAAAAAI/AAAAAAAAAAA/-fpVz4fdImg/s88-c-k-no/photo.jpg",
   "views":216964959,
   "created_on":"2013-08-13T02:42:23Z",
   "title":"RomanAtwoodVlogs",
   "id":"UC-SV8-bUJfXjrRMnp7F8Wzw"
  },
  {  
   "thumb_url_default":"https://yt3.ggpht.com/-qaWKaxiiuDc/AAAAAAAAAAI/AAAAAAAAAAA/0EoZzkJEUMc/s88-c-k-no/photo.jpg",
   "views":460971,
   "created_on":"2011-05-09T03:43:36Z",
   "title":"Donovan Dustin",
   "id":"UC-uzRXWfXKZWHDvTCAQRfWA"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-xSoc6icoyM0/AAAAAAAAAAI/AAAAAAAAAAA/WzMp9TXtYek/s88-c-k-no/photo.jpg",
   "views":55921,
   "created_on":"2013-11-27T03:22:11Z",
   "title":"Tab's Gaming Pad",
   "id":"UC-vkS8J9ovJFA7krXkbA90w"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-qrD04Q_Asr0/AAAAAAAAAAI/AAAAAAAAAAA/IQmGgs75q7o/s88-c-k-no/photo.jpg",
   "views":290726,
   "created_on":"2011-10-12T03:13:19Z",
   "title":"planethumanofficial",
   "id":"UC-WMky94nwO2V0j3yWzJJ5g"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-X_LNAKWmetg/AAAAAAAAAAI/AAAAAAAAAAA/dPPK1tgp6H8/s88-c-k-no/photo.jpg",
   "views":1786129,
   "created_on":"2010-01-24T19:43:24Z",
   "title":"vedrim",
   "id":"UC-zKPn4jKeg_sEYjoOFe13w"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-Xjk-VC5VItM/AAAAAAAAAAI/AAAAAAAAAAA/rrBWC34Z7iA/s88-c-k-no/photo.jpg",
   "views":7086046,
   "created_on":"2008-06-19T03:52:00Z",
   "title":"ABCD123toast",
   "id":"UC04ytXliFP2zZpyFiZYvLQA"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-i65yDNbvKjk/AAAAAAAAAAI/AAAAAAAAAAA/typlIFS918Q/s88-c-k-no/photo.jpg",
   "views":23180487,
   "created_on":"2009-09-12T11:04:24Z",
   "title":"MattKeck",
   "id":"UC04ZW2FS8RfUmJEa39_-JoA"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-aXujGP8Dyzs/AAAAAAAAAAI/AAAAAAAAAAA/dSDxODBTGfI/s88-c-k-no/photo.jpg",
   "views":666872,
   "created_on":"2012-02-28T00:49:50Z",
   "title":"Jesse Royal",
   "id":"UC0CohPJt1XAP0sAKazrsxIQ"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-dQFcuLsbK20/AAAAAAAAAAI/AAAAAAAAAAA/r9hmz7DWVSg/s88-c-k-no/photo.jpg",
   "views":294623,
   "created_on":"2011-05-03T05:07:35Z",
   "title":"Corrie Hegwood",
   "id":"UC0cuBvfn-k0mFkPI9ZeF5vA"
  },
  {
   "thumb_url_default":"https://yt3.ggpht.com/-A_J7gPmZf-Q/AAAAAAAAAAI/AAAAAAAAAAA/n8yz1SmTU_k/s88-c-k-no/photo.jpg",
   "views":643218,
   "created_on":"2011-02-04T03:04:04Z",
   "title":"laughspin",
   "id":"UC0D3tWXruCZrBZqw0ojzqJQ"
  },
  { 
   "thumb_url_default":"https://yt3.ggpht.com/-MdLmmFh3qjo/AAAAAAAAAAI/AAAAAAAAAAA/lcGE1l_gam4/s88-c-k-no/photo.jpg",
   "views":3106606,
   "created_on":"2009-06-11T04:06:53Z",
   "title":"Felicia Ricci",
   "id":"UC0KJrVR7lOqDTkH2S2tjo5Q"
  }
 ]