Create Tabs Element with Data from Collection

Hi guys, anyone created a Tabs element with data from a collection? I am trying to create a tabs element where when you click a button it is disabled until you click another, and at the same time the content in the text box below changes accordingly. For the buttons I used a repeater and the text is a box linked to the collection, but wasn’t sure how to make everything work all together. I know the Change Layout example, but it is not dynamic and doesn’t draw data from a collection.
Pleaseeeee help.

Still stuck on this… anyone?

Hi @naama-t-l ,

I’ve created an example solution for tabs. It requires some setup and a little of code.

Given:

  1. A dataset #tabDataset connected to a collection with titles and contents for the tabs.
  2. A repeater #tabRepeater connected to the dataset.
  3. Two buttons inside the repeater item template — #deselectedTab and #selectedTab. The buttons should have the same size and position (i.e. they’re fully overlapped). #selectedTab is hidden on load. The buttons are connected to the dataset and linked to the title column.
  4. A text representing tab content. The text is connected to the dataset and linked to the content column.

Then add the following code to the page:

$w.onReady(() => {
  const tabDataset = $w("#tabDataset");
  const tabRepeater = $w("#tabRepeater");

  const updateSelectedTab = () => {
    tabRepeater.forEachItem(($item, itemData, index) => {
      if (tabDataset.getCurrentItemIndex() === index) {
        $item("#selectedTab").show();
      } else {
        $item("#selectedTab").hide();
      }
    });
  };

  tabDataset.onReady(() => {
    updateSelectedTab();
    
    tabRepeater.forEachItem(($item, itemData, index) => {
      $item("#deselectedTab").onClick(() => {
        tabDataset.setCurrentItemIndex(index);
      });
    });
    
    tabDataset.onCurrentIndexChanged(updateSelectedTab);
  });
});

I believe its self-explanatory.

Tell me if it works for you.

Thanks so much Yevhen!!!
It works like a charm.
Important to note for future references that anything we want to show when the button is clicked (text, images, etc.) are not to be placed inside the repeater, but in their own box outside of it :slight_smile:

Thanks again, this is so helpful!
Naama.

You’re welcome!

@Yevhen Pavliuk Hi again :slight_smile:
So far I have been having fun with this code, and it works well, apart from a couple of things I am scratching my head on.

  1. I The are 2 box elements in there, set to collapse on load, with code to expand if there’s data in the Image items that sit inside the boxes. It works well only if there is data, but if there isn’t - it will show the boxes empty, rather than collapse.

  1. For some reason when going to preview mode or live - there is a huge gap that opens under the whole box. Why is this happening?


Thanks in advance!

Here is the code I have on this page:

import wixData from 'wix-data';

$w.onReady(() => {
 const tabDataset = $w("#SuccessStoriesDataset");
 const tabRepeater = $w("#tabsRepeater");

 const updateclientTabDisabled = () => {
    tabRepeater.forEachItem(($item, itemData, index) => {
 if (tabDataset.getCurrentItemIndex() === index) {
        $item("#clientTabDisabled").show();
      } else {
        $item("#clientTabDisabled").hide();
      }
    });
  };

  tabDataset.onReady(() => {
    updateclientTabDisabled();
 
    tabRepeater.forEachItem(($item, itemData, index) => {
      $item("#clientTabSelect").onClick(() => {
        tabDataset.setCurrentItemIndex(index);
        updateclientTabDisabled();
      });
    });
 
    tabDataset.onCurrentIndexChanged(updateclientTabDisabled);
  });
});

$w.onReady(function () {
  $w('#SuccessStoriesDataset').getCurrentItem();
  showExistingMedia();

});

function showExistingMedia() {
  $w("#SuccessStoriesDataset").onReady(() => {
 if ($w("#image1").src !== null) $w("#imageBox1").expand();
 if ($w("#image2").src !== null) $w("#imageBox2").expand();
 else {
    $w("#imageBox1").collapse();
    $w("#imageBox2").collapse();
  }
    });
}

Hey @naama-t-l ,

Could you send me a link to your site?

@yevhen-pavliuk here you go https://tavas-online.wixsite.com/squareloot/copy-of-success-stories
(by the way, I also have difficulty with the shrinking header - which is different on homepage than the rest of the site. I have a seperate thread on this -https://www.wix.com/code/home/forum/community-discussion/shrinking-header-not-working-well)

Thanks :slight_smile:

@naama-t-l

  1. You need to update the visibility of your image boxes when the dataset is ready and after the current dataset item index changes (see updateImageVisibility function):
import wixData from "wix-data";

$w.onReady(() => {
  const tabDataset = $w("#SuccessStoriesDataset");
  const tabRepeater = $w("#tabsRepeater");

  const updateclientTabDisabled = () => {
    tabRepeater.forEachItem(($item, itemData, index) => {
      if (tabDataset.getCurrentItemIndex() === index) {
        $item("#clientTabDisabled").show();
      } else {
        $item("#clientTabDisabled").hide();
      }
    });
  };

  const updateImageVisibility = () => {
    const story = tabDataset.getCurrentItem();

    const imageBox1 = $w("#imageBox1");
    if (story.image1) {
      imageBox1.expand();
    } else {
      imageBox1.collapse();
    }

    const imageBox2 = $w("#imageBox2");
    if (story.image2) {
      imageBox2.expand();
    } else {
      imageBox2.collapse();
    }
  };

  tabDataset.onReady(() => {
    updateclientTabDisabled();
    updateImageVisibility();

    tabRepeater.forEachItem(($item, itemData, index) => {
      $item("#clientTabSelect").onClick(() => {
        tabDataset.setCurrentItemIndex(index);
        updateclientTabDisabled();
      });
    });

    tabDataset.onCurrentIndexChanged(() => {
      updateclientTabDisabled();
      updateImageVisibility();
    });
  });
});
  1. The gap happens because your content is inside a strip component. The component has its own height. When the content inside exceeds the limits of the strip, the strip expands. But if the content becomes smaller in height, the strip keeps its original height.

Instead of using a strip component as a container for your content that changes dynamically you may use a strip for the header and for the footer since their content is pretty much static. So the final structure should be: header strip, content between the header and the footer (not in a strip), footer strip.

@yevhen-pavliuk Once again. thanks so much. Both points works well. I do have a problem with number 2 only because it harms my design :frowning: The website is set to have a black gradient and the header and footer are transparent
. Based on your solution in point 2, it means that in order to have a white strip background to the table, I must color the page’s background in white, and this is not an option for me, design-wise. Any idea how to workaround it?

This is the correct design


Not good… (this is what happens when I remove the strip)


background set to white to try and solve the color behind the table - no no no no…

@naama-t-l

You can have a transparent sticky header with white page background. A workaround is to create a black empty strip and place it on the page below the header (not inside the header). I managed to do that.

@yevhen-pavliuk Yep, it worked. Too bad you cannot cheat the system the same way, with the footer. It forced me to make another slight design change. But, no biggy. It still looks good. Thanks again. You rock!

Hi @yevhen-pavliuk ,

I look through your explanation for the tab - maybe I can ask you too for support. I’d like to add a tab element like the screen. Can you maybe help quite simple how to create such a box? I have no experience.

Many thanks in advance