Velo Tutorial: Creating an Expanding Mega Menu

9 min read
Visit the Velo by Wix website to onboard and continue learning.
This article describes how you can create an expanding menu based on visitors' selections. We're going to explain how we set up the sample site, and provide explanations and tips to help you understand the code.

Overview

In this example, we created a menu that branches into submenus. The choices available in each submenu are customized based on the visitor’s previous selections. In the final submenu (Submenu 2), each menu button links to a page with product listings.
Our site includes the following:
  • Three menu levels: Main menu, Submenu 1, and Submenu 2. We used repeaters to create the menus.
  • Two collections to store the content for menu labels and links.
Then we added code to do the following:
  1. Identify the visitor's choice for each menu.
  2. Filter the collection data for the next submenu based on the visitor's choice.
  3. Load the submenu repeater button labels with the filtered collection data. For the final menu, also load the repeater buttons with links to product listing pages.
Important
We placed the code in masterPage.js in the Page Code section of the sidebar, and not the page's tab of the code panel. This way you can add the menu to any page of your site.

Add Collections

We added the following collections to our site:
The menu collection contains Main menu data, and includes the following field:
  • rootTitles: Choices for Main menu (Men, Women)

SubTitles Collection

The subTitles collection contains data for the submenus and includes the following fields:
  • subTitles: Labels for Submenu 1
  • menu: Reference to the Main menu collection. This field is used to filter the collection data according to the visitor's Main menu choice.
  • img1: Image displayed in Submenu 2
  • subSubItems1: Data for Submenu 2 Shop by Product repeater
  • subSubItems2: Data for Submenu 2 Shop by Brand repeater

The subSubItems fields contain arrays of JSON objects stored as text. They define the button label and link for each button in Submenu 2.
Tip
You can link your final menu buttons to dynamic pages or Stores product pages which display your products, events, services, etc. Paste the URLs into the JSON objects in the subSubItems fields.

Set Up the Home Page

On the Home page we added the following:
  • Main menu: A repeater with buttons
  • Submenu 1: A repeater with buttons, hidden on load, and a text element that shows the Main menu selection (Men or Women).
  • Submenu 2: A container box, hidden on load, containing the following elements:
    • Shop by Product repeater with a button for each choice
    • Shop by Brand repeater with a button for each choice
    • Image

Add Code

Use the comments, notes, and explanations in the sections below to better understand the code for this example.

Step 1: Imports and Global Variables

1//-------------Imports-------------//
2import wixData from 'wix-data';
3
4//-------------Global Variables-------------//
5
6//Number of Submenu 2 repeaters.
7const subLevel2RepeaterCount = 2;
8
9//Object containing all menu data from subTitles database collection.
10let menuData;

The subLevel2RepeaterCount variable represents the number of repeaters in Submenu 2. We'll use this variable later (Step 2) when we loop through the repeaters to populate them with data.

Step 2: When the Page Loads

1$w.onReady(async () => {
2  //Get the menu data from the collection.
3  menuData = await wixData.query("subTitles").find().then(result => result.items);
4
5  //Set up each Submenu 2 repeater as it is loaded.
6  for (let i = 1; i <= subLevel2RepeaterCount; i++) {
7    $w(`#repeaterSubSub${i}`).onItemReady(($item, itemData, index) => {
8      //Get the repeater button from its ID.
9      const repeaterButton = $item(`#buttonSubLevelTwo${i}`)
10      //Set the item label.
11      repeaterButton.label = itemData.label;
12      //Set the item link.
13      repeaterButton.link = itemData.url;
14    });
15  }
16});

When the page loads, we get all the data required to build the submenus from the subTitles collection. Later we'll filter this data according to the visitor's menu choices.

Note on Populating Repeaters

Populating a repeater with data is a 2-step process:

  1. Set the repeater’s data using .data. This triggers the second step for all items with a new ID in the data array.
  2. Populate the repeater with data from the new items using the onItemReady function.

In this example, we load the repeaters with data using 2 different methods:

  • Submenu 1: We use the simpler method of wiring an onItemReady event handler to the repeater using the Properties & Events panel (in Steps 3 and 6).
  • Submenu 2: Because there is more than 1 repeater, we populate the repeaters using a loop and call onItemReady inside our loop (see Line 7 above). Note that although this code is in the onReady function, it's only triggered later when the data for the Submenu 2 repeaters is set (Step 8).

Step 3: Main Menu Button Clicked

1//Set actions that occur when the main menu button is clicked.
2export function buttonMainMenu_click(event) {
3    $w("#title").show();
4    $w("#title").text = event.target.label
5 $w("#boxSubSubMenu").hide();
6 //Get the ID of the clicked main menu button.
7 const selectedMainMenuId = event.context.itemId;
8 //Get all the data of the Submenu 1 related to the main menu selection.
9 const repeaterData = menuData.filter(item => item.menu === selectedMainMenuId);
10 //Set the data to the Submenu 1 repeater.
11 $w('#repeaterSubLevelOne').data = repeaterData;
12 //Show the repeater of Submenu 1.
13 $w('#repeaterSubLevelOne').show();
14}

In this event handler, we use event.target and event.context to grab and use information based on the visitor's selection in the Main menu.

Then we use the JavaScript filter function to filter the menuData object based on the clicked button's ID. menuData contains all the data from the subTitles collection.

We use the filtered data to load the labels for Submenu 1. Note that by setting the data for the repeater in Line 11, we trigger the onItemReady event handler in Step 6.

Step 4: Hover over Submenu 1 Button

1//Set an action that occurs when the mouse hovers over a Submenu 1 button.
2export function buttonSub_mouseIn(event) {
3 //Get the ID of the Submenu 1 button the mouse hovers over.
4 const selectedRootId = event.context.itemId;
5 //Get all the data of the Submenu 2 related to Submenu 1.
6 const repeaterData = menuData.filter(item => item._id === selectedRootId)[0];
7 //Set up the box element corresponding to the selected button in Submenu 2.
8 setSubSubMenu(repeaterData); 
9 //Show the Submenu 2 box.
10 $w('#boxSubSubMenu').show();
11    }

Here we run similar code as for Step 3. One difference is that since there are 2 repeaters in Submenu 2, we need to run a loop to load the repeaters with data. For that we call the setSubSubMenu function (Step 8).

Step 5: Hide Submenu 2 When Mouse Moves Away

1//Set an action that occurs when the mouse pointer is moved away from the Submenu 2 box.
2export function boxSubSubMenu_mouseOut(event) {
3 $w('#boxSubSubMenu').hide();
4}
When the visitor moves their mouse away from the Submenu 2 container box, the submenu is hidden.

Step 6: Populate Submenu 1 Repeater

1//Set up each item in the Submenu 1 repeater as it is loaded.
2export function repeaterSubLevelOne_itemReady($item, itemData, index) {
3 $item('#buttonSub').label = itemData.subTitles;
4}

This onItemReady event handler is triggered when the data for the Submenu 1 repeater is set in Step 3.

Step 7: Create a Unique ID for Submenu 2 Repeater Items

1//-------------Utility Functions for Repeater Setup-------------//
2
3function createUniqueId() {
4 //Creating a Unique Id for each of the menu sub-items by getting the current millisecond and adding a random number from 1 to 1000
5 let id = String(+new Date() + Math.floor(Math.random() * 1000))
6 return id;
7}

When loading data into a repeater, new repeated items are created only for objects with an _id value not already present in the current array of data objects. Since only items with IDs will populate repeaters, we used JavaScript Date and Math functions to create a unique ID for each of the Submenu 2 items. This function is used in Step 8.

Step 8: Set Up Submenu 2

1function setSubSubMenu(repeaterData) {
2 //Set the image of the Submenu 1
3 $w('#image1').src = repeaterData.img1;
4 for (let i = 1; i <= subLevel2RepeaterCount; i++) {
5  //Convert the Submenu 2 string to a Javascript object.
6  const dataSubSub = JSON.parse(repeaterData[`subSubItems${i}`]);
7  //Set a unique ID for each item.
8  dataSubSub.forEach(subSubItem => {
9   subSubItem._id = createUniqueId();
10  })
11  //Set the Submenu 2 data in the repeater.
12  $w(`#repeaterSubSub${i}`).data = dataSubSub;
13 }
14}

Here we set up the final submenu.

This function takes repeaterData as a parameter, which is the data from the subTitles collection that's been filtered according to the visitor's 2 previous selections.

The function does the following:

  1. Sets the image for Submenu 2.
  2. Runs a loop to convert the subSubItems JSON objects into JavaScript objects so they can be used in the code.
  3. Calls the createUniqueId function (Step 7) to create a unique ID for each item in Submenu 2.
  4. Sets the data for the Submenu 2 repeaters. This triggers the onItemReady function in Step 2 and the Submenu 2 repeaters are populated.

Learn More

Check out a similar example that includes a site template with code: Mega Menu.

See the following sections of the Velo API Reference:

Did this help?

|