Hubdb Filter module category + partitial filtering

Hello,
I am stuck! I need a filter for my projects but I get them from my hubdb but made a repeater field to filter with a selectbox but now I want to add a filter on text. so If I type in a part of the job_position it should give me back the ones that match.
So now I need to add a input field to search with.
and need it in my macro to also work.
this is the module code I also use a macro file with this.

{{ require_css(get_asset_url('/hlb-website-demo/web/assets/styles/generic/3-components/pagination.css'), { async: true }) }}
{{ require_css(get_asset_url("/hlb-website-demo/web/modules/listing-filtered-vacancies/style/listing-filtered-vacancies.css"), { async: true} ) }}

{% from '/hlb-website-demo/web/modules/listing-filtered-vacancies/macros/listing-filtered-vacancies.html' import create_filter_url %}
{% from '/hlb-website-demo/web/modules/listing-filtered-vacancies/macros/listing-filtered-vacancies.html' import create_excluding_filter_url %}
{% from '/hlb-website-demo/web/modules/listing-filtered-vacancies/macros/listing-filtered-vacancies.html' import add_filters %}

{# page number #}
{% set page_num_filter = 'list_page_num' %}
{% set page_num = request.query_dict[page_num_filter] ? request.query_dict[page_num_filter]|int : 1 %} 
{# categories order #}

{# output #}
{% set output = {} %}
{% set list_tags = [{title: '', column_name: 'category', excluding: false},{title: '', column_name: 'experience_type', excluding: true}] %}
{{ add_filters(module.vacancies_table, list_tags, module.filters, output, page_num_filter) }}

{% set module_classes = module.module_settings.top_padding %}
{% set module_classes = module.module_settings.bottom_padding ~ ' ' ~ module_classes %}

<section {{ 'id="{{ module.module_settings.section_id }}"' if module.module_settings.section_id }} class="m-listing-filtered-vacancies {{ module_classes }}" {{ 'data-has-filters="true"' if request.query_dict.used_filters or request.query_dict[page_num_filter] }}>
 {% if module.title %}
 <div class="container m-listing-filtered-vacancies__title">
 <h2>{{ module.title }}</h2>
 </div>
 {% endif %}

 <div class="m-listing-filtered-vacancies__filters">
 <div class="container">
 <div class="m-listing-filtered-vacancies__filter-categories">
 <div class="m-listing-filtered-vacancies__filter-select-wrapper">
 <div class="m-listing-filtered-vacancies__filter-select">
 {% for category in output.filter_categories|selectattr('type', 'equalto','select') %}
 <div>
 <select data-filter-category>
 <option value="{{ create_filter_url(page_num_filter, 1, category.name)|trim }}" {{ 'selected disabled' if not request.query_dict[category.name] }}>{{ request.query_dict[category.name] is defined ? module.translations.reset : category.label }}</option>
 {% set sorter = category.name == 'experience_type' || category.name == 'education_level' ? 'order' : 'text' %}
 {% for item in category.filters|sort(false,false,sorter) %}
 <option value="{{- item.url|trim -}}" {{ 'selected' if item.text|replace('&', '') == request.query_dict[category.name]|replace('&', '') }}>{{ item.text }}</option>
 {% endfor %}
 </select>

 <select class="display_is-hidden" data-filter-hidden>
 <option></option>
 </select>
 </div>
 {% endfor %}
 </div>
 {# Sort by newest/oldest #}
 <div class="m-listing-filtered-vacancies__sort">
 <select data-filter-category>
 <option {{ 'selected' if request.query_dict.order_by == 'date' or request.query_dict.order_by is not defined }} value="{{ create_filter_url('order_by', "date", page_num_filter)|trim }}">{{ module.translations.sort_by_newest }}</option>
 <option {{ 'selected' if request.query_dict.order_by == 'az' }} value="{{ create_filter_url('order_by', "az", page_num_filter)|trim }}">{{ module.translations.sort_alphabetically }}</option>
 </select>
 </div>
 </div>
 </div>
 </div>
 </div>

 <div class="m-listing-filtered-vacancies__results">
 <div class="container">
 {% if output.results|length > 0 %}
 {% set ordered_results = output.results %}
 {% set order_by_newest = request.query_dict.order_by is not defined or request.query_dict.order_by == 'date' %}
 {% if order_by_newest %}
 {% set ordered_results = ordered_results|sort(True, False, 'date_posted') %}
 {% elif request.query_dict.order_by == 'az' %}
 {% set ordered_results = ordered_results|sort(False, False, 'job_position') %}
 {% endif %}

 {% set pages = ordered_results|slice(module.results_per_page, ' ') %}
 {% for current_page in pages %}
 {% if loop.index == page_num %} 
 <p class="m-listing-filtered-vacancies__results-count"><strong>{{ ordered_results|length }}</strong> {{ module.translations.results_text }}</p>
 {% for item in current_page|selectattr('hs_id', "defined") %}
 <div class="m-listing-filtered-vacancies__vacancy-card">
 {% if item.featured_image.url %}
 <div class="m-listing-filtered-vacancies__visual">
 <picture class="m-listing-filtered-vacancies__thumbnail media_image-cover">
 <img class="media_image-responsive" src="{{ item.featured_image.url }}" alt="{{ item.job_position }}" loading="lazy" width="990">
 {% if item.overlay_image.url %}
 <img class="media_image-responsive overlay-image" src="{{ item.overlay_image.url }}" alt="{{ item.job_position }}" loading="lazy" width="990">
 {% endif %}
 </picture>
 </div>
 {% endif %}
 <div class="m-listing-filtered-vacancies__job-description">
 <div class="top-row">
 <div class="job-description">
 <div class="job-header">
 {% for tag in item.category %}
 <span>{{ tag.name }}</span>
 {% endfor %}
 <h3 class="keep-default">{{ item.job_position }}</h3>
 </div>
 </div>
 </div> 

 <div class="bottom-row">
 <div class="job-meta">
 {% if item.education_level %}
 <p class="keep-default education">{{ item.education_level|map('name')|join(', ') }}</p>
 {% endif %}

 {% if item.city|length > 0 %}
 <p class="keep-default location">
 {% for city in item.city %}
 {{ city.name }}{{ ',' if not loop.last }}
 {% endfor %}
 </p>
 {% endif %}

 {% if item.contract_type %}
 <p class="keep-default time">{{ item.contract_type|map('name')|join(', ') }}</p>
 {% endif %}
 </div>

 {% from '/hlb-website-demo/web/macros/shared.html' import add_cta_button %}
 {% set link = { url : { href: item.vacancy_detail_url } } %}
 {{ add_cta_button("button", null, null, "alternative button__icon button__icon--circle-arrow", module.translations.button_text, link, "keep-default") }}
 </div>
 </div>
 </div>
 {% endfor %}
 {% endif %}
 {% endfor %}
 {% elif module.message_for_no_results %}
 <div class="rich-text-container">
 {{ module.message_for_no_results }}
 </div>
 {% endif %} 
 </div>
 </div>

 {# Pagination #} 
 {% from '/hlb-website-demo/web/modules/listing-filtered-vacancies/macros/listing-filtered-vacancies.html' import add_pagination %}
 {{ add_pagination(output.results, module.results_per_page, page_num, module.translations.more_results, page_num_filter, "m-listing-filtered-vacancies__pagination") }}
 {# End Pagination #}

</section>

Macro code:

{# Construct url #}
{% macro create_filter_url(replace_key, replace_value, ignore_key) -%}
 {% set constructed_url = request.full_url %} 
 {% set urlObj = {} %}
 {% set operator = {} %}
 {% set known_keys = request.query_dict.items()|map("key") %}

 {% for key in known_keys %}
 {% set operator_value = (operator.value is not defined or operator.value == '') ? '?' : '&' %}
 {% do operator.update({value: operator_value}) %}

 {% if loop.first && key == ignore_key %}
 {% do operator.update({value: ''}) %}
 {% endif %}

 {% if key == replace_key %}
 {% set constructed_url = constructed_url ~ operator.value ~ key ~ '=' ~ replace_value %}
 {% do urlObj.update({value: constructed_url}) %}
 {% elif key != ignore_key %}
 {% set constructed_url = constructed_url ~ operator.value ~ key ~ '=' ~ request.query_dict[key]|replace('&','&')|urlencode %}
 {% do urlObj.update({value: constructed_url}) %}
 {% endif %}
 {% endfor %}

 {% if replace_key is not within known_keys %}
 {% set operator_value = (operator.value is defined and operator.value != '') ? '&' : '?' %}
 {% set constructed_url = urlObj.value ~ operator_value ~ replace_key ~ '=' ~ replace_value %}
 {% do urlObj.update({value: constructed_url}) %}
 {% endif %}

 {% if 'used_filters' is not within known_keys and key != ignore_key %}
 {% do urlObj.update({value: urlObj.value ~ '&used_filters=true'}) %}
 {% endif %}

 {{ urlObj.value }}
{%- endmacro %}
{# End construct url #}

{# Construct excluding url #}
{% macro create_excluding_filter_url(new_key, new_value) -%}
 {% set constructed_url = request.full_url %}
 {% set urlObj = {} %}
 {% set operator = {} %}
 {% set known_keys = request.query_dict.items()|map("key") %}

 {% if 'hs_preview' in known_keys %}
 {% set operator_value = operator.value is not defined ? '?' : '&' %}
 {% do operator.update({value: operator_value}) %}
 {% set constructed_url = constructed_url ~ operator.value ~ 'hs_preview=' ~ request.query_dict.hs_preview %}
 {% do urlObj.update({value: constructed_url}) %}
 {% endif %}

 {% set operator_value = operator.value is defined ? '&' : '?' %}
 {% set constructed_url = urlObj.value ~ operator_value ~ new_key ~ '=' ~ new_value|replace('&','&')|escapejs %}
 {% do urlObj.update({value: constructed_url }) %}

 {% if new_key is defined %}
 {% do urlObj.update({value: urlObj.value ~ '&used_filters=true' }) %}
 {% endif %}

 {{ urlObj.value }}
{%- endmacro %}
{# End construct excluding url #}

{# Add filter #}
{% macro add_filter(row, filter_list, filter, fallback_filter) -%}
 {% if request.query_dict.experience_type and filter.name != 'experience_type' %}
 {% if request.query_dict.experience_type is within row.experience_type|map('name') %}
 {% for value in row[filter.name] %}
 {% set filter_val = value.name ? value.name : value %}
 {% if filter_val is not within filter_list|map('text') %}
 {% set filter_url = (filter.type == 'list' and filter.excluding == true) ? create_excluding_filter_url(filter.name, filter_val|urlencode) : create_filter_url(filter.name, filter_val|urlencode, fallback_filter) %}
 {% do filter_list.append({ url: filter_url, text: filter_val, order: value.order }) %}
 {% endif %}
 {% endfor %}
 {% endif %}
 {% else %}
 {% for value in row[filter.name] %}
 {% set filter_val = value.name ? value.name : value %}
 {% if filter_val is not within filter_list|map('text') %}
 {% set filter_url = (filter.type == 'list' and filter.excluding == true) ? create_excluding_filter_url(filter.name, filter_val|urlencode) : create_filter_url(filter.name, filter_val|urlencode, fallback_filter) %}
 {% do filter_list.append({ url: filter_url, text: filter_val, order: value.order }) %}
 {% endif %}
 {% endfor %}
 {% endif %}

{%- endmacro %}
{# End add filter #}

{# Add filters #}
{% macro add_filters(hubdb_table_id, list_column_names, select_column_names, output, page_num_filter="list_page_num") -%}

 {% set filters = [] %}

 {% for column in list_column_names %}
 {% do filters.append({name: column.column_name, label: column.title, type: 'list', excluding: column.excluding}) %}
 {% endfor %}

 {% for column in select_column_names %}
 {% do filters.append({name: column.column_name, label: column.title, type: 'select'}) %}
 {% endfor %}

 {% set all_filters = [] %}

 {% set query = '&vacancy_detail_url__not_null=' %}
 {% set table_rows = hubdb_table_rows(hubdb_table_id, query) %}
 {% set unfiltered_rows = table_rows %} 

 {% for item in filters %}
 {% set filters = [] %}
 {% for row in table_rows %}
 {{ add_filter(row, filters, item, page_num_filter) }}
 {% endfor %}

 {% do all_filters.append({ name: item.name, label: item.label, filters: filters, type: item.type }) %}
 {% endfor %}

 {# filtered results #} 
 {% set indexesToRemove = [] %}
 {% for item in all_filters %} 
 {% if request.query_dict[item.name] is defined %}
 {% for row in unfiltered_rows %}
 {% set atLeastOneMatch = {value: false } %}

 {% for val in row[item.name] %} 
 {% set filter_name = val.name ? val.name : val %} 
 {% if request.query_dict[item.name]|replace('&', '') == filter_name|replace('&', '') %}
 {% do atLeastOneMatch.update({value: true}) %}
 {% endif %}
 {% endfor %}
 {% if !atLeastOneMatch.value %}
 {% do indexesToRemove.append(row.hs_id) %}
 {% endif %}
 {% endfor %}
 {% endif %}
 {% endfor %}

 {% set filtered_rows = indexesToRemove|length > 0 ? unfiltered_rows|rejectattr("hs_id", "within", indexesToRemove) : unfiltered_rows %}

 {% do output.update({ filter_categories: all_filters, results: filtered_rows }) %}
{%- endmacro %}
{# End Add filters #}

{# Pagination #}
{% macro add_pagination(results, limit, page_num, title="", page_num_filter = 'list_page_num', extra_classes="") %}

 {% set total_pages = 1 %}

 {% if limit %}
 {% set total_pages = ((results | length) / limit) | round(0, 'ceil') %}
 {% endif %}

 {% set more_pages = total_pages - page_num %}

 {% if total_pages > 1 %}
 {% set first_page_url = create_filter_url(page_num_filter, 1) %}

 <div class="{{ extra_classes }}"> 
 <div class="container">
 <div class="pagination">
 {% if title %}
 <p class="pagination__title">{{ title }}</p>
 {% endif %}
 <ul>

 {% if page_num > 1 %}
 <li><a class="prev" href="{{ create_filter_url(page_num_filter, page_num - 1) }}"></a></li>
 {% endif %}

 {% if more_pages == 0 %}
 {% if page_num - 3 == 1 %}<li><a href="{{ first_page_url }}">{{ page_num - 3 }}</a></li>{% endif %}
 {% if page_num - 3 > 1 %}<li><a href="{{ create_filter_url(page_num_filter, page_num - 3) }}">{{ page_num - 3 }}</a></li>{% endif %}
 {% endif %}

 {% if more_pages <= 1 %}
 {% if page_num - 2 == 1 %}<li><a href="{{ first_page_url }}">{{ page_num - 2 }}</a></li>{% endif %}
 {% if page_num - 2 > 1 %}<li><a href="{{ create_filter_url(page_num_filter, page_num - 2) }}">{{ page_num - 2 }}</a></li>{% endif %}
 {% endif %}

 {% if page_num - 1 == 1 %}<li><a href="{{ first_page_url }}">{{ page_num - 1 }}</a></li>{% endif %}
 {% if page_num - 1 > 1 %}<li><a href="{{ create_filter_url(page_num_filter, page_num - 1) }}">{{ page_num - 1 }}</a></li>{% endif %}

 <li class="active"><a
 href="{% if page_num==1 %}{{ first_page_url }}{% else %}{{ create_filter_url(page_num_filter, page_num) }}{% endif %}">{{ page_num }}</a>
 </li>

 {% if page_num + 1 <= total_pages %}<li><a href="{{ create_filter_url(page_num_filter, page_num + 1) }}">{{ page_num + 1 }}</a></li>{% endif %}
 {% if page_num + 2 <= total_pages %}<li><a href="{{ create_filter_url(page_num_filter, page_num + 2) }}">{{ page_num + 2 }}</a></li>{% endif %}

 {% if page_num == 1 %}
 {% if page_num + 3 <= total_pages %}<li><a href="{{ create_filter_url(page_num_filter, page_num + 3) }}">{{ page_num + 3 }}</a></li>{% endif %}
 {% endif %}

 {% if more_pages > 0 %}
 <li><a class="next" href="{{ create_filter_url(page_num_filter, page_num + 1) }}"></a></li>
 {% endif %}
 </ul>
 </div>
 </div>
 </div>

 {% endif %}
{% endmacro %}
{# End Pagination #}

Hi, @BBecker1 :waving_hand: Thanks for your question. I have a few questions to help the community:

  • what is the error you are receiving? Are you getting anything specific when you try to use your code?
  • have you tried any other approaches?
  • do you have a clue where in your code block the issue might be? Even if we don’t know how to fix it yet? Having a targeted example helps the community focus in on the main issue

Thanks for the additional information.

Best,

Jaycee