Make it drop-down if more than 1 sub-menu? - javascript

I am working on a project with Mean JS and I am using the template offered by them at https://github.com/meanjs/mean .
Basically I want to do:
if (more than 1 sub-menus)
make it drop-down
else
make just a button and if that button clicked take it to state of the sub menu.
A button on the navigation bar will be defined as drop-down. It will have 2 sub-menus. This main button will be visible to all types of user. However, only 1 sub-menu on the drop down will be visible to general users. All 2 sub-menus will be visible to the admin users. I want to define it as drop down, but if there is only 1 sub-menu, don't show it as drop-down. When a user clicks on the main button it will take it to the page defined in the sub-menu.
Here is the code that is in the header.client.view.html (This is from the template, I have not change it.)
<nav class="collapse navbar-collapse" collapse="!isCollapsed" role="navigation">
<ul class="nav navbar-nav" ng-if="menu.shouldRender(authentication.user);">
<li ng-repeat="item in menu.items | orderBy: 'position'" ng-if="item.shouldRender(authentication.user);" ng-switch="item.type" ng-class="{ active: $state.includes(item.state), dropdown: item.type === 'dropdown' }" class="{{item.class}}" dropdown="item.type === 'dropdown'">
<a ng-switch-when="dropdown" class="dropdown-toggle" dropdown-toggle role="button">{{::item.title}} <span class="caret"></span></a>
<ul ng-switch-when="dropdown" class="dropdown-menu">
<li ng-repeat="subitem in item.items | orderBy: 'position'" ng-if="subitem.shouldRender(authentication.user);" ui-sref-active="active">
<a ui-sref="{{subitem.state}}" ng-bind="subitem.title"></a>
</li>
</ul>
<a ng-switch-default ui-sref="{{item.state}}" ng-bind="item.title"></a>
</li>
</ul>
</nav>
Here is what goes in the articles.client.config.js
// Configuring the Articles module
angular.module('articles').run(['Menus',
function(Menus) {
// Add the articles dropdown item
Menus.addMenuItem('topbar', {
title: 'Blog',
state: 'articles',
type: 'dropdown',
roles: ['*'],
position: 1
});
// Add the dropdown list item
Menus.addSubMenuItem('topbar', 'articles', {
title: 'Visit Blog',
state: 'articles.list',
roles: ['user', 'admin']
});
// Add the dropdown create item
Menus.addSubMenuItem('topbar', 'articles', {
title: 'Create Blog Post',
state: 'articles.create',
roles: ['admin']
});
}
]);

Related

Can't left click links in a bootstrap dropdown menu. Have to right click and open in new tab

I have a dropdown menu made with the Bootstrap V3.3.7 dropdown menu control that is populated with several links, but these links only work if I right click and open in new tab. If I left click, nothing happens. No errors on the console and no network activity. Obviously they are valid links since they work if I try to open them in a new tab.
My HTML:
<ul class="dropdown-menu">
<li *ngFor="let item of safeUrlPair(button)">
<a class="dropdown-item" [href]="item.value">{{ item.key }}</a>
</li>
</ul>
Part of the Typescript:
safeUrlPair: () => [{ key: 'Link Text', value: this.object && this.object.id ? this.getSafeLink(`${this.objectLink}${this.object.id}`) : '' }
The getSafeLink method:
getSafeLink(link: string): SafeUrl {
return this.domSanitizer.bypassSecurityTrustUrl(link);
}
I have come up with a workaround that doesn't quite work, but it's progress.
New HTML:
<ul class="dropdown-menu">
<li *ngFor="let item of safeUrlPair(button)">
<a class="dropdown-item" (click)="triggerLink(item.value)">{{ item.key }}</a>
</li>
</ul>
And the triggerLink function:
triggerLink(url: string): void {
if (!url) {
return;
}
window.open(url, '_blank');
}
This allows the left click to work and opens a link in a new tab, but since it is a safeURL, the url isn't passed as a typical link, like http://www.google.com would be.
It ends up being something like: http://localhost:4200/SafeValue%20must%20use%20[property]=binding:%20https://www.google.com%20(see%20http://g.co/ng/security#xss)

AngularJS Loading Issue

I am using angular to pull content and display on some pages of the site. I have bootstrap drop-down menu in the header. Based on the user login in, some drop-down option are hidden. To achieve this, I used ng-if on the header controller. Everything working fine.
But the issue is, sometimes when I open the site I am able to see hidden drop-down options also and {{userRole}} is displayed as {{userRole}}. why is this happening? Thank you.
Screen shot of issue
In the screen shot, user can see two my profile icons.
var itpApp = angular.module("itpApp",['ngRoute','angular.filter','ui.bootstrap','ngSanitize']);
itpApp.controller("headerController", function($scope, $rootScope) {
var gaR = new GlideAjax('ITPortalUtil0');
gaR.addParam('sysparm_name','u_role');
gaR.getXML(function(response) {
$rootScope.userRole = response.responseXML.documentElement.getAttribute("answer");
$rootScope.$apply();
console.log('user role check: '+$rootScope.userRole);
//$rootScope.userRole = $localStorage.user_role;
});
});
<div class="navbar navbar-default1" ng-controller="headerController">
<div class="navbar-collapse collapse" id="shortMenu">
<ul class="nav navbar-nav">
<li class="dropdown">
My Tickets$[SP]<b class="caret"></b>
<ul class="dropdown-menu" id="menu7">
<li ng-if="userRole =='ess'"><a href="#" role="button" data-toggle="modal" data-target="#myModal" >My Profile</a></li>
<li ng-if="userRole =='itil'">My Profile</li>
</ul>
</li>
</ul>
</div>

Recursive compose element in Aurelia

So let's say I've got this view and "Menu" is a collection of menu objects which may also have a collection of menu objects named Children as a property.
Here's the view -
<div class="collapse navbar-collapse navbar-right navbar-main-collapse">
<ul class="nav navbar-nav">
<li repeat.for="m of menu" class.bind="m.type=='child' ? 'dropdown' : ''" as-element="compose" data-type="${m.type}"
view="/client/landing/menubar/${m.type}menu"></li>
</ul>
</div>
And there are two views I'm using as my recursive menu, like so -
(View - no child collection)
<template>
<a href.bind="menu.link" data-info="${menu.type}">${menu.displayText}</a>
</template>
(View - with child collection)
<template>
${menu.displayText} <b class="caret"></b>
<ul class="dropdown-menu">
<li repeat.for="m of menu.children" data-info="${m.type}" class.bind="m.haschildren ? 'dropdown' : ''"
as-element="compose" view="/client/landing/menubar/${m.type}menu"></li>
</ul>
</template>
And the viewmodels for these two views both look like this -
import { customElement, bindable, inject } from "aurelia-framework";
#customElement("parentmenu")
export class ParentMenu {
#bindable menu;
}
I'm getting something. The views do display (although without recursion). The problem is that the repeat.for="m of menu" simply doesn't work below the bind in the first view.
Where have I gone wrong?
There's no need to use compose. Your menu could be a lot simpler, like:
<template bindable="model">
<ul>
<li repeat.for="item of model">
<a href.bind="item.link">${item.displayText}<a/>
<menu if.bind="item.children && item.children.length" model.bind="item.children"></menu>
</ul>
</template>
Usage:
<menu model.bind="menu"></menu>
JS:
menu = [
{
displayText: '1',
href: ''
},
{
displayText: '2',
children: [
{
displayText: '3',
href: ''
},
{
displayText: '4',
href: '',
children: [
{
displayText: '3',
href: ''
}
]
}
]
}
];

change menu class active

I want to change menu class active when click a submenu. But instead what my code does is that set active the default active menu.
$('#menu1').find('li').click(function(){
//removing the previous selected menu state
$('#menu1').find('li').removeClass('active');
//is this element from the second level menu?
if($(this).closest('ul').hasClass('second-level')){
$(this).parents('li').addClass('active');
//this is a parent element
}else{
$(this).addClass('active');
}
});
So for example
<ul id="menu1" class="nav navbar-nav">
<li class="active" > {{ Lang::get('messages.home') }}</li>
<li class='dropdown '>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
{{ Lang::get('messages.vehicles') }}
<b class="caret"></b>
</a>
<ul id = "second-level" class="dropdown-menu">
<li> <a href="form-general.html">{{link_to_action('MaintenanceController#vehicle_maintenance',
Lang::get('messages.vehicle_maintenance'),null)}}</a></li>
</ul>
</li>
when click second level submenu active class is set to home menu (default active meanu) after page refresh. How to set active the menu of submenu?
You can compare the URL in the menu item's link to the current URL on page load:
$(document).ready(function() {
$('#menu1 li').each(function() {
if (location.href.indexOf($('a',this).attr('href'))>=0) {
$(this).addClass('active');
} else {
$(this).removeClass('active');
};
});
});
However, it's probably better to add the class yourself or use server-side code to do so (depending on how your site is generated).

Using Angular to conditionally enable bootstrap submenu

I have a bootstrap 3 menu which I am trying to use Angular JS on.
I have the basic menu working, and the ng-class correctly works, applying it only in the menu has children.
What I am trying to do now is to only have the menu "work" (display the second nested UL) only if the parent LI has child data. So, I have this:
<ul class="nav navbar-nav">
<li ng-class="{'dropdown':(n.children.length)}" ng-repeat="n in navData">
<a data-target="#" ng-attr="{'data-toggle=dropdown':(n.children.length>0)}">{{n.label}}</a>
<ul class="dropdown-menu" role="menu">
<li ng-repeat="p in n.children">{{p.label}}</li>
</ul>
</li>
</ul>
The part I have wrong, or that does not work is the ng-attr on the A tag. The data-toggle=dropdown is what causes the menu to work. Currently, none of the menus work even if they have children.
My model is
var nav = [{
label: 'Pages',
value: 'pages',
children: [{
label: 'Home',
value: 'home'
}, {
label: 'Left Nav',
value: 'left-nav'
}]
}, {
label: 'Components',
value: 'components'
}];
So, "Pages" has children and "Components" does not. The ng-class works as expected.
EDIT: I have added a "toggle" value to the model, set to "dropdown" or "" and then this works:
<ul class="nav navbar-nav">
<li ng-class="{'dropdown':(n.children.length)}" ng-repeat="n in navData">
<a data-target="#" data-toggle="{{n.toggle}}">{{n.label}}</a>
<ul class="dropdown-menu" role="menu">
<li ng-repeat="p in n.children">{{p.label}}</li>
</ul>
</li>
</ul>
I have added a "toggle" value to the model, set to "dropdown" or "" and then this works:
<ul class="nav navbar-nav">
<li ng-class="{'dropdown':(n.children.length)}" ng-repeat="n in navData">
<a data-target="#" data-toggle="{{n.toggle}}">{{n.label}}</a>
<ul class="dropdown-menu" role="menu">
<li ng-repeat="p in n.children">{{p.label}}</li>
</ul>
</li>
</ul>

Categories

Resources