material-components-web
material-components-web copied to clipboard
Can't switch between dynamically created tabs in MDCTabBar.
Hi guys,
In my element I'm displaying category titles as Tabs. The problem is that I can't switch between tabs which are rendered after the categories get fetched:
...
<div class="mdc-tab-bar" role="tablist">
<div class="mdc-tab-scroller">
<div class="mdc-tab-scroller__scroll-area">
<div class="mdc-tab-scroller__scroll-content">
<button class="mdc-tab mdc-tab--active"
role="tab" tabindex="0" aria-selected="true">
<span class="mdc-tab__content">
<!-- <span class="mdc-tab__icon material-icons">favorite</span> -->
<span class="mdc-tab__text-label">VIEW ALL</span>
</span>
<span class="mdc-tab-indicator mdc-tab-indicator--active">
<span class="mdc-tab-indicator__content mdc-tab-indicator__content--underline"></span>
</span>
<span class="mdc-tab__ripple"></span>
</button>
${Object.values(categories || []).map((category) => html`
<button class="mdc-tab"
role="tab" tabindex="0" aria-selected="false">
<span class="mdc-tab__content">
<!-- <span class="mdc-tab__icon material-icons">favorite</span> -->
<span class="mdc-tab__text-label">${category}</span>
</span>
<span class="mdc-tab-indicator">
<span class="mdc-tab-indicator__content mdc-tab-indicator__content--underline"></span>
</span>
<span class="mdc-tab__ripple"></span>
</button>
`)}
</div>
</div>
</div>
</div>
`;
}
...
stateChanged(state: RootState) {
this.categories = state.category.items;
}
firstUpdated(){
new MDCTabBar(this.shadowRoot.querySelector('.mdc-tab-bar'));
}
I've created a demo on glitch that demonstrates the issue, you can see the source here.
I've tried to look for answers on discord, but I got no proper answer there. Thanks!
Reproduction with vanilla MDC Web: https://glitch.com/edit/#!/mdc-web-4214
We're only ever instantiating tabs based on the DOM during initialize
. We would probably need to add an explicit addTab
(and removeTab
?) API that would receive an mdc-tab
element (or possibly an index for removal), or something like reinstantiateTabs
that would destroy all current tab instances and reinstantiate based on the current state of the DOM.
@kfranqueiro thanks for the clarification. Well as a workaround, I moved the 'static' tab inside the loop that generates the rest of the tabs after data gets fetched, now all tabs render simultaneously but I can see other cases where this wouldn't be an option so having an add/remove Tab
or reinstantiateTabs
method would be nice.
I think you might forget to import those files
import {MDCTabBar} from '@material/tab-bar'; const tabBar = new MDCTabBar(document.querySelector('.mdc-tab-bar'));
Is there any update on this.
It seems a lot of the mdc controls require that the data be statically passed to any implementation. It makes the controls rather unsuitable to use.
To work around this, I had to catch my tab-item render event, and hack the MDC tab into the tabList of the tabAdapter.
On top of this, there seems to be a global tracking of these tab items, so each tab-item must have a unique id globally.
const anyTabBar = this.TabBar as any;
anyTabBar.tabList.push(Tab);
const randomId = Math.round(Math.random() * Number.MAX_VALUE);
const id = `mdc-tab-${ randomId }`;
Tab.id = id;
Tab.root.id = id;
I am also interested in some kind of add/remove Tab
or reinstantiateTabs
solution.