I have two components on the same page with identical sets of filter tabs. I’d like to synchronize the components so that clicking on a filter in one component selects the same/matching filter in the other component. I expect this might be possible with some custom javascript. Has anyone done something similiar?
anyone? @Chem?
Here’s some code that can help.
You basically put in all the IDs of the components. Then when you if you click on the nth filter tab, it will click on the nth filter tab of the other components.
Demo can be seen here:
Code:
var componentToSync = ['component_6', 'component_18']; // add a comma seperated list of component ids here.
jQuery('body').not('.not-assigned').on('click', '.filter-tabs > .nav.nav-tabs > li > a', function() {
if (jQuery(this).hasClass('justClicked')) {
jQuery(this).removeClass('justClicked');
return;
} else {
var ele = [];
for(var i in componentToSync) {
ele.push(componentToSync[i].split('component_').join(''));
}
var eleData = '[data-obj-id="'+ele.join('"],[data-obj-id="')+'"]';
if (jQuery(this).parents(eleData).length > 0) {
var index = jQuery(this).parent().index();
jQuery('[data-obj-id="'+ele.join('"] .filter-tabs > .nav.nav-tabs > li:eq('+index+') a,[data-obj-id="')+'"] .filter-tabs > .nav.nav-tabs > li:eq('+index+') a').not(this).addClass('justClicked').trigger('click');
}
}
}).addClass('not-assigned');
I hope this helps, let me know if you have any other questions.
Moe, this is fantastic.
Much appreciated!
var componentList = ['component_1', 'component_2', 'component_3'];
var cmp = [];
componentList.forEach(x => {
cmp.push('[data-obj-id="'+ x.replace('component_', '')+'"]');
});
cmp = cmp.join(',');
jQuery('body').on('click', '.filter-tabs > .nav.nav-tabs > li > a', function() {
if (jQuery(this).hasClass('clicked')) {
jQuery(this).removeClass('clicked');
return;
} else {
let curPos = $(this).parent().index(),
wrapper = jQuery(this).parents(cmp),
components = $(cmp).not(wrapper);
if(components.length){
components.find(".filter-tabs li:eq("+ curPos +") a").addClass('clicked').trigger("click")
}
}
});
Hi Moe,
Thanks so much for sharing this — your original solution using index-based tab syncing across components was incredibly helpful and got me 90% of the way there
I did run into an edge case when working with calendar components, where the tabs appear to be rendered outside the component_X
div or in a different DOM structure. This meant that matching by index wasn’t working reliably across different views (e.g. table vs. calendar).
To get around this, I ended up matching tabs by label text instead of index, using this:
$('body').not('.tabs-synced').on('click', 'a[ng-click*="setFilterTab"]', function () {
const clickedText = $(this).text().trim();
$('a[ng-click*="setFilterTab"]').each(function () {
const tab = $(this);
if (tab.text().trim() === clickedText && this !== event.target) {
this.click();
}
});
}).addClass('tabs-synced');
This approach has been working well even when the DOM structure between components differs.
Thanks again for the foundational approach — it made a huge difference.
Hope this update helps someone else too!
Best,
Graham