The Menu supports data source bindings such as array of JavaScript objects
that can be structured as either hierarchical
or self-referential
data.
The Menu can be populated with hierarchical data source by assigning it to the items
property, and the fields with corresponding keys can be mapped to the
fields
property.
The Menu can generate its menu items through an array of complex data source by mapping fields
from the fields
property.
import { Component } from '@angular/core';
import { enableRipple } from '@syncfusion/ej2-base';
import { FieldSettingsModel } from '@syncfusion/ej2-angular-navigations';
// Import an array of JSON data from datasource.ts
import { dataSource } from './datasource';
enableRipple(true);
@Component({
selector: 'app-root',
template: `<ejs-menu [items]="data" [fields]='menuFields'></ejs-menu>`
})
export class AppComponent {
private menuFields: FieldSettingsModel = {
text: ['continent', 'country', 'language'],
children: ['countries', 'languages']
};
private data: { [key: string]: Object }[] = dataSource;
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { MenuModule } from '@syncfusion/ej2-angular-navigations';
import { AppComponent } from './app.component';
@NgModule({
imports: [BrowserModule, MenuModule],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
/**
* Menu Data source
*/
export let dataSource: { [key: string]: Object }[] = [
{
continent: 'Asia',
countries: [
{
country: 'China',
languages: [
{ language: 'Chinese' },
{ language: 'Cantonese' }
]
},
{
country: 'India',
languages: [
{ language: 'English' },
{ language: 'Hindi' },
{ language: 'Tamil' }
]
},
{
country: 'Japan',
languages: [
{ language: 'Japanese' }
]
}
]
},
{
continent: 'Africa',
countries: [
{
country: 'Nigeria',
languages: [
{ language: 'English' },
{ language: 'Hausa' }
]
},
{
country: 'Egypt',
languages: [
{ language: 'Arabic' }
]
},
{
country: 'South Africa',
languages: [
{ language: 'Tswana' },
{ language: 'Swati' }
]
}
]
},
{
continent: 'North America',
countries: [
{
country: 'Canada',
languages: [
{ language: 'French' }
]
},
{
country: 'Mexico',
languages: [
{ language: 'Spanish' }
]
},
{
country: 'USA',
languages: [
{ language: 'English' }
]
}
]
},
{
continent: 'South America',
countries: [
{
country: 'Brazil',
languages: [
{ language: 'Portuguese' }
]
},
{
country: 'Colombia',
languages: [
{ language: 'Spanish' }
]
},
{
country: 'Argentina',
languages: [
{ language: 'Spanish' }
]
}
]
},
{
continent: 'Oceania',
countries: [
{
country: 'Australia'
},
{
country: 'New Zealand'
},
{
country: 'Samoa'
},
]
}
];
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';
enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);
In application level, remote data binding can be achieved using DataManager
.
To create Menu, assign items property with resultant data from
callback
function.
The following example displays five employees’ FirstName from Employees table
and ShipName details from Orders table of the Northwind
Data Service.
import { Component, OnInit } from '@angular/core';
import { enableRipple } from '@syncfusion/ej2-base';
import { DataManager, Query, ODataAdaptor, ReturnOption } from '@syncfusion/ej2-data';
import { FieldSettingsModel } from '@syncfusion/ej2-angular-navigations';
enableRipple(true);
@Component({
selector: 'app-root',
template: `<ejs-menu *ngIf='menuItems' [items]='menuItems' [fields]='menuFields'></ejs-menu>`
})
export class AppComponent implements OnInit {
private SERVICE_URI: string = 'https://js.syncfusion.com/ejServices/Wcf/Northwind.svc/';
// Menu fields definition.
private menuFields: FieldSettingsModel = {
text: ['FirstName', 'ShipName'],
children: ['Orders']
};
private menuItems: { [key: string]: Object }[];
public ngOnInit(): void {
// Getting remote data using DataManager.
new DataManager({ url: this.SERVICE_URI, adaptor: new ODataAdaptor, crossDomain: true })
.executeQuery(
new Query().from('Employees').take(5).hierarchy(
new Query()
.foreignKey('EmployeeID')
.from('Orders').take(13),
function () {
return [1, 2, 3, 4, 5]
}
))
.then((e: ReturnOption) => {
//Assign result data to menu items
this.menuItems = e.result as { [key: string]: Object }[];
document.getElementById('loader').style.display = "none";
});
}
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { MenuModule } from '@syncfusion/ej2-angular-navigations';
import { AppComponent } from './app.component';
@NgModule({
imports: [BrowserModule, MenuModule],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';
enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);
Menu can be populated from self-referential data structure that contains array of JSON objects
with parentId
mapping.
You can directly assign self-referential data to the items
property, and map all the field members
with corresponding keys from self-referential data to fields property.
To render the root level nodes, specify the parentId
as null or no need to specify the parentId
in data source.
In the following example, the id, pId, and text columns from self-referential data have been mapped to the itemId
, parentId
, and text
fields, respectively.
import { Component } from '@angular/core';
import { enableRipple } from '@syncfusion/ej2-base';
import { FieldSettingsModel } from '@syncfusion/ej2-angular-navigations';
enableRipple(true);
@Component({
selector: 'app-root',
template: `<ejs-menu [items]='data' [fields]='menuFields'></ejs-menu>`
})
export class AppComponent {
//Menu datasource
private data: { [key: string]: Object }[] = [
{ id: 'parent1', text: 'Events' },
{ id: 'parent2', text: 'Movies' },
{ id: 'parent3', text: 'Directory' },
{ id: 'parent4', text: 'Queries', pId: null },
{ id: 'parent5', text: 'Services', pId: null },
{ id: 'parent6', text: 'Conferences', pId: 'parent1' },
{ id: 'parent7', text: 'Music', pId: 'parent1' },
{ id: 'parent8', text: 'Workshops', pId: 'parent1' },
{ id: 'parent9', text: 'Now Showing', pId: 'parent2' },
{ id: 'parent10', text: 'Coming Soon', pId: 'parent2' },
{ id: 'parent10', text: 'Media Gallery', pId: 'parent3' },
{ id: 'parent11', text: 'Newsletters', pId: 'parent3' },
{ id: 'parent12', text: 'Our Policy', pId: 'parent4' },
{ id: 'parent13', text: 'Site Map', pId: 'parent4' },
{ id: 'parent14', text: 'Pop', pId: 'parent7' },
{ id: 'parent15', text: 'Folk', pId: 'parent7' },
{ id: 'parent16', text: 'Classical', pId: 'parent7' }
];
//Menu fields definition
private menuFields: FieldSettingsModel = {
itemId: 'id',
text: 'text',
parentId: 'pId'
};
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { MenuModule } from '@syncfusion/ej2-angular-navigations';
import { AppComponent } from './app.component';
@NgModule({
imports: [BrowserModule, MenuModule],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';
enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);
The Menu can be customized using Essential JS2 Template engine to render the elements.
To customize menu items in your application, set your customized template string to the
template
property.
In the following example, the menu has been rendered with customized menu items.
import { Component, Inject } from '@angular/core';
import { FieldSettingsModel } from '@syncfusion/ej2-angular-navigations';
import { enableRipple } from '@syncfusion/ej2-base';
enableRipple(false);
@Component({
selector: 'app-root',
styleUrls: ['template.css'],
template: `
<div id="menuTemplate" class="menu-section">
<div class="menu-control">
<ejs-menu [items]='dataSource' [fields]='menuFields' [animationSettings]="animation" cssClass="e-template-menu">
<ng-template #template let-dataSource="">
{{dataSource.category}}
<div *ngIf="dataSource.value" style="width:100%;display:flex;justify-content:space-between;">
<img *ngIf="dataSource.url" class="e-avatar e-avatar-small"
src="src/images/platforms/{{dataSource.url}}.png" />
<span style="width:100%;">{{dataSource.value}}</span>
<span *ngIf="dataSource.count" class='e-badge e-badge-success'>{{dataSource.count}}</span>
</div>
<div *ngIf="dataSource.about" tabindex="0" class="e-card">
<div class="e-card-header">
<div class="e-card-header-caption">
<div class="e-card-header-title">About Us</div>
</div>
</div>
<div class="e-card-content">
{{dataSource.about.value}}
</div>
<div class="e-card-actions">
<button class="e-btn e-outline" style="pointer-events: auto;">
Read More
</button>
</div>
</div>
</ng-template>
</ejs-menu>
</div>
</div>
`
})
export class AppComponent {
constructor(@Inject('sourceFiles') private sourceFiles: any) {
sourceFiles.files = ['template.css'];
}
//Template datasource
private dataSource: { [key: string]: Object }[] = [
{
category: 'Products',
options: [
{ value: 'JavaScript', url: '../../../../../../menu/images/javascript' },
{ value: 'Angular', url: '../../../../../../menu/images/angular' },
{ value: 'ASP.NET Core', url: '../../../../../../menu/images/core' },
{ value: 'ASP.NET MVC', url: '../../../../../../menu/images/mvc' }
]
},
{
category: 'Services',
options: [
{ value: 'Application Development', count: '1200+' },
{ value: 'Maintenance & Support', count: '3700+' },
{ value: 'Quality Assurance' },
{ value: 'Cloud Integration', count: '900+' }
]
},
{
category: 'About Us',
options: [
{
id: 'about',
about: {
value: "We are on a mission to provide world-class best software solutions for web, mobile and desktop platforms. Around 900+ applications are desgined and delivered to our customers to make digital & strengthen their businesses."
}
}
]
},
{ category: 'Careers' },
{ category: 'Sign In' }
];
// Menu fields definition
private menuFields: object = {
text: ['category', 'value'],
children: ['options']
};
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { MenuModule } from '@syncfusion/ej2-angular-navigations';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
import { AppComponent } from './app.component';
@NgModule({
imports: [BrowserModule, MenuModule, ButtonModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [
{ provide: 'sourceFiles', useValue: {files: []} }]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';
enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);
/**
* ej2 Menu template styles
*/
#menuTemplate .menu-control {
margin-top: 45px;
text-align: center;
}
/**
* Common customization
*/
#menuTemplate .e-menu-wrapper.e-control ul.e-ul .e-menu-item {
display: flex;
height: auto;
padding: 0;
}
/**
* Avatar customization
*/
#menuTemplate .e-menu-wrapper ul .e-menu-item .e-avatar {
background-color: inherit;
background-position: 0;
background-size: 25px;
color: inherit;
font-size: inherit;
height: inherit;
justify-content: left;
margin: 0 10px;
width: 100%;
text-indent: 35px;
}
/**
* Badge customization
*/
#menuTemplate .e-menu-wrapper ul .e-menu-item ul li {
padding: 0 10px;
}
#menuTemplate .e-menu-wrapper ul .e-menu-item ul li .e-badge {
float: right;
margin: 13px 0px 0px 10px;
}
#menuTemplate .e-menu-wrapper ul .e-menu-item ul li:hover {
background-color: #eee;
}
/**
* Card customization
*/
#menuTemplate .e-menu-wrapper ul.e-ul .e-menu-item .e-card {
width: 290px;
font-size: inherit;
cursor: default;
background-color: inherit;
border-color: transparent;
}
#menuTemplate .e-menu-wrapper ul.e-ul .e-menu-item .e-card .e-card-content {
white-space: normal;
color: inherit;
padding-top: 0;
text-align: justify;
font-size: inherit;
}
#menuTemplate .e-menu-wrapper ul.e-ul .e-menu-item .e-card .cb-icons {
width: 30px;
font-size: 30px;
height: 30px;
}
#menuTemplate .e-menu-wrapper ul.e-ul .e-menu-item .e-card .e-card-btn {
background-color: inherit;
}
/* Common ul & li styles */
.e-bigger .e-template-menu.e-menu-wrapper ul.e-ul,
.e-template-menu.e-menu-wrapper ul.e-ul {
padding: 0;
}
.e-bigger .e-template-menu.e-menu-wrapper ul.e-ul .e-menu-item,
.e-template-menu.e-menu-wrapper ul.e-ul .e-menu-item {
display: flex;
padding: 0 10px;
outline-color: transparent;
}
/** Avatar customization */
.e-template-menu.e-menu-wrapper ul .e-menu-item .e-avatar {
background-color: inherit;
font-size: 8px;
margin-right: 8px;
align-self: center;
width: auto;
overflow: visible;
}
.e-bigger .e-template-menu.e-menu-wrapper ul .e-menu-item .e-avatar {
font-size: 10px;
}
/** Badge customization */
.e-template-menu.e-menu-wrapper ul .e-menu-item .e-badge {
margin-left: 10px;
align-self: center;
overflow: visible;
}
/** Card customization */
.e-template-menu.e-menu-wrapper ul.e-ul .e-menu-item .e-card {
width: 290px;
font-size: inherit;
background-color: inherit;
border-color: transparent;
}
/* custom code start*/
.e-bigger .e-template-menu.e-menu-wrapper ul.e-ul .e-menu-item .e-card {
width: 320px;
}
/* custom code end*/
.e-template-menu.e-menu-wrapper ul.e-ul .e-menu-item .e-card .e-card-content {
white-space: normal;
color: inherit;
padding-top: 0;
text-align: justify;
font-size: inherit;
}
.e-template-menu.e-menu-wrapper ul.e-ul .e-menu-item#about {
height: auto;
padding: 0;
}
.e-template-menu.e-menu-wrapper ul.e-ul .e-menu-item#about.e-focused {
background-color: transparent;
outline-color: transparent;
pointer-events: none;
}
To prevent sub menu closing, set
args.cancel
totrue
inbeforeClose
event.