I'm working on creating a video directory, using HubDB to store the details for each video.
I'm looking for a way where a user can filter the results iterated from HubDB by interacting with HTML checkboxes like this:
The issue I'm having at the moment is that I don't see a straightforward way to connect the user interacting with checkboxes and the HubDB filter queries.
I tried using javascript for if conditionals and use HubL code inside, but it seems that the HubL code regardless if it passes the logic test or not. I have since removed that and I am a little stuck.
Below I've dropped in a basic template code that I built for a POC and learning experience for myself. You'' have to excuse the mess haha.
This is purely a JS solution, I might have a HUBL excusive solution that I will continue to look for.
I have clarified any comments I had left in the code to help understand what is going on / the thought process.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>{{ content.html_title }}</title>
<meta name="description" content="{{ content.meta_description }}">
{{ standard_header_includes }}
<style>
img {
max-width: 200px;
}
.grid {
display: grid;
grid-gap: 0;
grid-template-columns: repeat(auto-fill,minmax(220px,1fr));
}
ul {
padding: 0px;
}
</style>
</head>
<body>
<form name="filters-form"></form>
{% if dynamic_page_route_level == 0 %}
<h1>Gallery - 0</h1><!-- For tracking purpose - remove for production -->
<div class="grid">
{% set rows = hubdb_table_rows(1056514) %}
{% for row in rows %}
<a class="gallery-1 gallery-card" href="{{ request.path }}/{{ row.hs_path }}" data-filter="{{row.tags}}">
<img src="{{row.image.url}}" alt="" />
<h2>{{ row.hs_name }}</h2>
<p>{{row.tags}}</p>
</a>
{% endfor %}
</div>
{% endif %}
{% if dynamic_page_route_level == 1 %}
<h1>Gallery - 1</h1><!-- For tracking purpose - remove for production -->
<h2>{{dynamic_page_hubdb_row.hs_name}}</h2>
{% set rows = hubdb_table_rows(dynamic_page_hubdb_row.hs_child_table_id) %}
<ul class="grid">
{% for row in rows %}
<a class="gallery-1 gallery-card" href="{{ request.path }}/{{ row.hs_path }}" data-filter="{{row.tags}}">
<img src="{{row.image.url}}" alt="" />
<h2>{{ row.hs_name }}</h2>
<p>{{row.tags}}</p>
</a>
{% endfor %}
</ul>
{% endif %}
<script>
$(document).ready(function() {
var filterValues = [];
// Get all filters and place into an array
function getAllFilters() {
var returnArray = [];
$('.gallery-card').each( function() {
var c = $(this).data('filter').split(' ');
console.log(c);
returnArray = returnArray.concat(c).unique(); ;
});
return returnArray;
}
// Prevent duplicates in the filters
Array.prototype.unique = function() {
var a = this.concat();
for(var i=0; i<a.length; ++i) {
for(var j=i+1; j<a.length; ++j) {
if(a[i] === a[j])
a.splice(j--, 1);
}
}
return a;
};
// Populate the filters in to the form
function popFilters(filArray) {
for (i=0; i<filArray.length; i++) {
var checkbox = '<label><input type="checkbox" value="' + filArray[i] + '">' + filArray[i] + '</label>';
$('[name="filters-form"]').append(checkbox);
}
}
// Initialize the filters
popFilters(getAllFilters());
// Watch the filters form for changes
$('form[name="filters-form"]').change(function () {
// collect array of all "checked" checkboxes
//var appliedFilters = getFiltersForm();
// pass array into filter function
// function hides and shwos based on arry
updateUi( getFiltersForm() );
});
// Collect the checked filters
function getFiltersForm() {
var filters = [];
$('form[name="filters-form"] input[type="checkbox"]:checked').each( function() {
var value =$(this).val();
filters.push(value);
console.log('filters = ' + filters);
});
return filters;
}
// Check if values are in an array
function isInArray(needles, haystack){
for(var i = 0 , len = needles.length; i < len; i++){
if($.inArray(needles[i], haystack) == -1) return false;
}
return true;
}
// Update the gallery the UI
function updateUi(b) {
if (b.length <=0) {
$('.gallery-card').show();
} else {
$('.gallery-card').each( function() {
var a = $(this).data('filter').split(' ');
console.log(isInArray(b,a));
if ( isInArray(b,a) != true ) {
$(this).hide();
} else if ( isInArray(b,a) == true ) {
$(this).show();
}
});
}
}
// NEXT STEPS
// Add querystring recognition and history API states
});
</script>
{{ standard_footer_includes }}
</body>
</html>
A few things to note:
- I'm pretty sure this POC uses an Additive Filtering model, it's been some time since I've been in it.
- This was also built for a multi level UI (terminology?), meaning it used nested database tables.
- This uses the html markup as the data source…slaps self on the wrist. This would ideally use JSON produced by HUBL and opperate more like a true micro SPA.
- My POC did not have filter categories as your UI shows, but I'm positive with a little logic this can be solved easily.
- The plan for this piece when in production was to do 2 additional things that aren't included here: 1) Use the history api so the user can use the back and forward buttons. 2) Use a query string to allow deep linking.
EDIT:
After rereading the initiasl post I'm not positive this was a solution for you, but I hope it at least gets you going in the right direction.
Below I've dropped in a basic template code that I built for a POC and learning experience for myself. You'' have to excuse the mess haha.
This is purely a JS solution, I might have a HUBL excusive solution that I will continue to look for.
I have clarified any comments I had left in the code to help understand what is going on / the thought process.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>{{ content.html_title }}</title>
<meta name="description" content="{{ content.meta_description }}">
{{ standard_header_includes }}
<style>
img {
max-width: 200px;
}
.grid {
display: grid;
grid-gap: 0;
grid-template-columns: repeat(auto-fill,minmax(220px,1fr));
}
ul {
padding: 0px;
}
</style>
</head>
<body>
<form name="filters-form"></form>
{% if dynamic_page_route_level == 0 %}
<h1>Gallery - 0</h1><!-- For tracking purpose - remove for production -->
<div class="grid">
{% set rows = hubdb_table_rows(1056514) %}
{% for row in rows %}
<a class="gallery-1 gallery-card" href="{{ request.path }}/{{ row.hs_path }}" data-filter="{{row.tags}}">
<img src="{{row.image.url}}" alt="" />
<h2>{{ row.hs_name }}</h2>
<p>{{row.tags}}</p>
</a>
{% endfor %}
</div>
{% endif %}
{% if dynamic_page_route_level == 1 %}
<h1>Gallery - 1</h1><!-- For tracking purpose - remove for production -->
<h2>{{dynamic_page_hubdb_row.hs_name}}</h2>
{% set rows = hubdb_table_rows(dynamic_page_hubdb_row.hs_child_table_id) %}
<ul class="grid">
{% for row in rows %}
<a class="gallery-1 gallery-card" href="{{ request.path }}/{{ row.hs_path }}" data-filter="{{row.tags}}">
<img src="{{row.image.url}}" alt="" />
<h2>{{ row.hs_name }}</h2>
<p>{{row.tags}}</p>
</a>
{% endfor %}
</ul>
{% endif %}
<script>
$(document).ready(function() {
var filterValues = [];
// Get all filters and place into an array
function getAllFilters() {
var returnArray = [];
$('.gallery-card').each( function() {
var c = $(this).data('filter').split(' ');
console.log(c);
returnArray = returnArray.concat(c).unique(); ;
});
return returnArray;
}
// Prevent duplicates in the filters
Array.prototype.unique = function() {
var a = this.concat();
for(var i=0; i<a.length; ++i) {
for(var j=i+1; j<a.length; ++j) {
if(a[i] === a[j])
a.splice(j--, 1);
}
}
return a;
};
// Populate the filters in to the form
function popFilters(filArray) {
for (i=0; i<filArray.length; i++) {
var checkbox = '<label><input type="checkbox" value="' + filArray[i] + '">' + filArray[i] + '</label>';
$('[name="filters-form"]').append(checkbox);
}
}
// Initialize the filters
popFilters(getAllFilters());
// Watch the filters form for changes
$('form[name="filters-form"]').change(function () {
// collect array of all "checked" checkboxes
//var appliedFilters = getFiltersForm();
// pass array into filter function
// function hides and shwos based on arry
updateUi( getFiltersForm() );
});
// Collect the checked filters
function getFiltersForm() {
var filters = [];
$('form[name="filters-form"] input[type="checkbox"]:checked').each( function() {
var value =$(this).val();
filters.push(value);
console.log('filters = ' + filters);
});
return filters;
}
// Check if values are in an array
function isInArray(needles, haystack){
for(var i = 0 , len = needles.length; i < len; i++){
if($.inArray(needles[i], haystack) == -1) return false;
}
return true;
}
// Update the gallery the UI
function updateUi(b) {
if (b.length <=0) {
$('.gallery-card').show();
} else {
$('.gallery-card').each( function() {
var a = $(this).data('filter').split(' ');
console.log(isInArray(b,a));
if ( isInArray(b,a) != true ) {
$(this).hide();
} else if ( isInArray(b,a) == true ) {
$(this).show();
}
});
}
}
// NEXT STEPS
// Add querystring recognition and history API states
});
</script>
{{ standard_footer_includes }}
</body>
</html>
A few things to note:
- I'm pretty sure this POC uses an Additive Filtering model, it's been some time since I've been in it.
- This was also built for a multi level UI (terminology?), meaning it used nested database tables.
- This uses the html markup as the data source…slaps self on the wrist. This would ideally use JSON produced by HUBL and opperate more like a true micro SPA.
- My POC did not have filter categories as your UI shows, but I'm positive with a little logic this can be solved easily.
- The plan for this piece when in production was to do 2 additional things that aren't included here: 1) Use the history api so the user can use the back and forward buttons. 2) Use a query string to allow deep linking.
EDIT:
After rereading the initiasl post I'm not positive this was a solution for you, but I hope it at least gets you going in the right direction.