Skip to content

Platform: Mega Menu component Technical Design

Frantisek Kolar edited this page Oct 2, 2019 · 10 revisions

Mega Menu Component

Summary

The mega menu is a menu with a multi-level hierarchy. It has a top-level menu and submenus. The expand icon beside a menu item triggers the submenu.

Like the Menu Component, Mega Menu can also contain icons, separators, and grouped items. A Mega Menu can be nested up to 2 levels.

The items in the parent menu can be grouped(still part of parent-menu), have children(the sub-menu), be selected, have custom labels and can have callbacks for specific click actions.

Design:

<fdp-mega-menu 
        #megaMenuData 
        [separator]='true|false'
        [scrolling]='true|false' 
        [scrollLimit]='any number' 
        [width]="'width-in-px'" >
</fdp-mega-menu>

Template Local Variable

#megaMenuData : MegaMenuItems[] or MegaMenuSubItems[]

is a local reference variable which consists of items of type MegaMenuItems or MegaMenuSubItems.

MegaMenuItems
MegaMenuItems consists of: 
* `label`- the name of the parent item or group header. (Required)
* `icon`- icon to display for all items part of this group. (Optional)
* `customLabel`- a customized label to show up on tooltip that is different from `label`. (Optional)
* `groupItems`- all the **MegaMenuItems** that are part of this group. (Optional)
* `children`- all the **MegaMenuSubItems** that will form the sub-menu. (Optional)
* `callback`- the function to be called when this item is clicked. Could navigate to another page or do any other action. (Required)

Note:

-callback should not be allowed if item has children, since clicking on parent item only opens sub-menu and does nothing else. Similarly, callback should not be allowed if item has groupItems, since clicking on group header does nothing else.

-MegaMenuItems with children cannot be selectable or disabled.

MegaMenuSubItems
MegaMenuSubItems consists of: 
* `label`- the name of the item. (Required)
* `selectable`- menu item selectable. If item is selectable, then it will display selected/non-selected state when toggled. (Optional)
* `selected`- if this item is selected. (Optional)
* `icon`- icon to display in front of the menu label. (Optional)
* `secondaryIcon`- another icon to display at the other end of the item. (Optional)
* `disabled`- if this item is to appear in disabled state. (Optional)
* `customLabel`- a customized label to show up on tooltip that is different from `label`. (Optional)
* `callback()`- the function to be called when this item is clicked. Could navigate to another page or do any other action. (Required)
* `children`- sub-sub-items for this child menu. (Optional)

An example of how menuData would look like is:

const data = [{
        label: 'First Parent Item',
        icon: 'sap-icon--vehicle-repair',
        children: [{                        //Represents sub-menu items
              label: 'First Parent Sub Item 1',
              selectable: true,
              selected: true,
              callback: () => {
                alert("First Parent Sub Item 1 called");
              }
            },
            {
              label: 'First Parent Sub Item 2',
              disabled: true,
              customLabel: 'Second level item',
              callback: () => {
                alert("First Parent Sub Item 2 called");
              }
            }]
      },
      {
        label: 'Parent Group 1',
        groupItems: [                    //Represents group header and its items in parent menu
           {
              label: 'Item 1 in Group 1',
              disabled: true,
              callback: () => {
                alert("Item 1 in Group 1 called");
              }
           },
           {
              label: 'Item 2 in Group 1',
              customLabel: 'Another item',
              callback: () => {
                alert('Item 2 in Group 1');
              }
           }
        ]
      },
      {
        label: 'Third Parent Item',
        icon: 'sap-icon--grid',
        callback: () => {
          alert('Third parent item called');
        }
      }]

Property Bindings

separator: boolean

separator specifies if a separating line should be added between menu items. This field is optional. Default is set to false.

scrolling: boolean

scrolling specifies if the menu should scroll. This will apply scrolling to Mega Menu globally; to parent and its sub-menus. This field is optional. Default is set to false.

scrollLimit: number

scrollLimit specifies the number of items to be displayed after which scrolling begins. This will apply scrolling to Mega Menu globally; to parent and its sub-menus. This field is optional. Default is set to the total number of items in order to display all items.

width: string

width specifies the maximum width the Menu and sub-menu should take. Minimum width is set to 192px. This field is optional.


Event Bindings

N/A


Two-Way Bindings

N/A


Content Projection

N/A


Interfaces

MegaMenuItems

export interface MegaMenuItems {
    label: string;

    icon?: string;

    customLabel?: string;

    children: MegaMenuSubItems[];

    groupItems?: MegaMenuItems[];

    callback()?: void;
}

MegaMenuSubItems

export interface MegaMenuSubItems {
    label: string;

    selectable?: boolean;

    selected?: boolean;

    icon?: string;

    secondaryIcon?: string;

    disabled?: boolean;

    customLabel?: string;

    callback(): void;

    children: MegaMenuSubItems[];
}

Related Modules

N/A

Additional Notes


Questions

For Manju-

  1. Does the child menu also need to be grouped? It can become more complex than it already is.

--- The child menu need not be grouped, since it already defines 'menu items of a particular type'. Groups can remain in parent level alone.

  1. FRD specifies max of 2-level nesting. What do we mean by 2-level nesting; 2 sub-sub-levels or 1 parent and 1 sub-level?

--- 2-level means parent->sub-menu->sub-sub-menu.

  1. Since it is 2-level nesting, should sub-items themselves have children->sub-sub-items?

--- yes, same as above, but not more than that.

  1. Are we defining scrolling for sub-menus as well? If yes, we need to think how user will specify scrolling for sub-menu and if he can give separate values to parent menu and sub-menu. i.e. scrolling false for parent, and true for sub-menu.

--- Two ways to go about this:

1. scrolling should be present for child as well as parent, but how will we customise scrolling and scrollLimit for parent and child separately? - low priority

2. same values of scrollLimit apply across all levels. For now, we should implement this.

  1. What if user does not specify any child elements? Are we forcing user to specify children to qualify as mega menu? Should children be mandatory for at least one item?

--- children need not be mandatory. It can be optional, but it should look like a normal menu component. We are not enforcing any restriction to enforce Mega Menu, it is just a guideline.

  1. Parent menu that has children(sub-menu) cannot be selectable or disabled, or can it be? Is there a requirement that if parent is marked as selected or disabled, its child sub-menu items are all marked disabled/selected?

--- Parent item can be marked as disabled. However, it does not affect the children(sub-menu), since mouse pointer anyway does not work. However, children can individually be marked disabled and need not reflect the same to parent(in case for 3 child-items, all 3 are marked disabled, the parent item need not be marked disabled).

Parent cannot be marked as selectable, but its children can be.


Comments

@Frank

  • There already some similar component and we shoudl sync up. Like tabs. All have could have MenuItems and MegaMenu is really similar
  • How do you pass items into it? You probably forget a binding - lets call it [list]="menuItems"
  • Let;s just call the MegaMenuItems => MenuItem without the s
  • You dont need to have subitems type you can use the same time Menu Item
    • see following properties for the Menu Item
      • label,
      • icon,
      • id
      • routerList?, I can click and navigate to some route
      • itemns - the same type as root type
      • definitelly your callback, but I would call it command or action, plus some others you have
      • expanded - when this one has subm menu items you want to also keep some state about expansion .
  • Binding separator should be more descriptive - showXXX, hasXXXX

    • Since the default behavior is False, it should be called showSeparator to turn it on
  • Binding separator should be more descriptive - showXXX, hasXXXX

  • Do you have some exmaples (pictures) how it looks when it scrolls? and some usecases?

  • I would not limit this only to pixes.

  • If the customLabel is just a tooltip/hint, let;s just call this hint or description

  • We shoudl try to reuse some elementary component and Menu/MegaMenu share the same

  • Once you start with menu not MegaMenu as MegaMenu should use menu you will then be able to also template rendered item

   <fdp-mega-menu 
        [list]="items"
        [showSeparator]='true'>
           <ng-template #item let-item>
               <menu-item ...
           </ng-template>
</fdp-mega-menu>

  • core also support custom separator for menu - this can be done with the same ng-template mechanism
Clone this wiki locally