I have one issue.I am using Angular.js ui-router for displaying the nested views.In my case i have one parent menu and it has some sub menus. Let me to explain my code below.
dashboard.html:
<li ui-sref-active="active" ><a ui-sref="dashboard">Home</a></li>
<li ui-sref-active="active">
<a ui-sref=".res.userrole">Resource Management</a>
</li>
Here Resource Management is my parent menu and its sub menus are given below.
res.html:
<tabset>
<tab ui-sref="dashboard.res.userrole" ui-sref-active="active">
<tab-heading>Add User Role</tab-heading>
</tab>
<!--<tab ui-sref="dashboard.res.course" ui-sref-active="active">
<tab-heading>Add Course</tab-heading>
</tab>-->
<tab ui-sref="dashboard.res.class" ui-sref-active="active">
<tab-heading>Add Class</tab-heading>
</tab>
<tab ui-sref="dashboard.res.section" ui-sref-active="active">
<tab-heading>Add Section</tab-heading>
</tab>
<tab ui-sref="dashboard.res.session" ui-sref-active="active">
<tab-heading>Add Session</tab-heading>
</tab>
<tab ui-sref="dashboard.res.unit" ui-sref-active="active">
<tab-heading>Add Unit</tab-heading>
</tab>
</tabset>
<div ui-view></div>
Loginroute.js:
.state('dashboard.res', {
url: '/res',
templateUrl: 'dashboardview/res.html',
controller: 'resController'
})
.state('dashboard.res.userrole', {
url: '/userrole',
templateUrl: 'dashboardview/userrole.html',
controller: 'resourceuserroleController'
})
.state('dashboard.res.class', {
url: '/class',
templateUrl: 'dashboardview/class.html',
controller: 'resourceclassController'
})
.state('dashboard.res.section', {
url: '/section',
templateUrl: 'dashboardview/section.html',
controller: 'resourcesectionController'
})
.state('dashboard.res.session', {
url: '/session',
templateUrl: 'dashboardview/session.html',
controller: 'resourceSessionController'
})
.state('dashboard.res.unit', {
url: '/unit',
templateUrl: 'dashboardview/unit.html',
controller: 'resourceunitController'
})
Here my problem is when i am reloading any page of the above sub menu the first sub menu('i.e-Add User Role') is getting active class along with the refreshing sub menu page.So at a time i am getting two sub menu are active.Here i need if user is reloading any sub menu page that sub menu title will remain active.Please help me to resolve this issue.
Here is a idea using $state.includes().
e.g:
if state is /home/:id, Home tab will be activated.
if state is /home/sub/:id, Home and Home sub tabs will be activated
code example:
<ul class="nav navbar-nav">
<li ng-class="{active: $state.includes('home')}" class="active"><a ui-sref="home" href="/">Home</a></li>
<li ng-class="{active: $state.includes('home.sub')}" ><a ui-sref="home.sub" href="/">Home sub</a></li>
<li ng-class="{active: $state.includes('reports')}" ><a ui-sref="reports" href="/admin/reports">Reports</a></li>
<li ng-class="{active: $state.includes('users')}" ><a ui-sref="users" href="/admin/users">Users</a></li>
<li ng-class="{active: $state.includes('groups')}" ><a ui-sref="groups" href="/admin/groups">Groups</a></li>
Hope this may help to your case.
Related
I have one issue while using Angular.js ui-router.I added active class for highlight the menu but its not working.I am explaining my code below.
<ul class="nav navbar-nav">
<li ui-sref-active="active" ><a ui-sref=".profile">College Profile</a></li>
<li ng-class="{active: $state.includes('dashboard.deptmanagement')}"><a ui-sref="dashboard.deptmanagement.stream" >Department Management</a></li>
<li ui-sref-active="active">
<li ui-sref-active="active"><a ui-sref="dashboard.user.usermanagement">User Management</a></li>
<li ui-sref-active="active"><a ui-sref="dashboard.plan.contime">Plan Management</a></li>
</ul>
My problem is in Department Management menu from the above code.As this menu has some sub menus if i am adding here ui-sref-active="active" the issue is coming when the sub menu are selecting this menu can not get any active class.The sub menu of this parent menu is given below.
deptmanagement.html:
<div>
<tabset>
<tab ui-sref=".stream" ui-sref-active="active">
<tab-heading>Add Stream</tab-heading>
</tab>
<tab ui-sref=".dept" ui-sref-active="active">
<tab-heading>Add Department</tab-heading>
</tab>
<tab ui-sref=".course" ui-sref-active="active">
<tab-heading>Add Course</tab-heading>
</tab>
<tab ui-sref=".sub" ui-sref-active="active">
<tab-heading>Add Subject</tab-heading>
</tab>
</tabset>
<div ui-view></div>
</div>
loginroute.js
var Admin=angular.module('Channabasavashwara',['ui.router', '720kb.datepicker','ngMessages','ngCapsLock','ui.bootstrap']);
Admin.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('/', {
url: '/',
templateUrl: 'dashboardview/login.html',
controller: 'loginController'
})
.state('dashboard', {
url: '/dashboard',
templateUrl: 'dashboardview/dashboard.html',
controller: 'dashboardController'
})
.state('dashboard.profile', {
url: '/profile',
templateUrl: 'dashboardview/profile.html',
controller: 'profileController'
})
.state('dashboard.deptmanagement', {
url: '/deptmanagement',
templateUrl: 'dashboardview/deptmanagement.html',
controller: 'deptmanagementController'
})
.state('dashboard.deptmanagement.stream', {
url: '/stream',
templateUrl: 'dashboardview/stream.html',
controller: 'streamController'
})
.state('dashboard.deptmanagement.course', {
url: '/course',
templateUrl: 'dashboardview/course.html',
controller: 'resourcecourseController'
})
.state('dashboard.deptmanagement.sub', {
url: '/subject',
templateUrl: 'dashboardview/subject.html',
controller: 'deptsubjectController'
})
.state('dashboard.deptmanagement.dept', {
url: '/dept',
templateUrl: 'dashboardview/dept.html',
controller: 'deptController'
})
})
Here my requirement is when any of above sub-menu will select the main menu remain highlight.Please help me to resolve this issue.
To use ng-class="{'active':$state.includes('route1')}" for navigation $state needs to be available to the view, ie defined on the $scope in the controller.
$scope.$state = $state;
You can define $rootScope.$state = $state; so that it is available on $rootScope throughout your app although this may be considered poor practice.
If your controller is mainCtrl then:
Admin.controller('mainCtrl', ['$scope', '$state', function($scope, $state) {
$scope.$state = $state;
}]);
Or if you want to define $state on $rootScope you can use .run()
Admin.run(function($rootScope, $state) {
$rootScope.$state = $state;
})
Because the submenu is a tabset you can compare the current state name for each tab to set the active tab
<div>
<tabset>
<tab ui-sref="dashboard.deptmanagement.stream" active="$state.current.name == 'dashboard.deptmanagement.stream'">
<tab-heading>Add Stream</tab-heading>
</tab>
<tab ui-sref="dashboard.deptmanagement.dept" active="$state.current.name == 'dashboard.deptmanagement.dept'">
<tab-heading>Add Department</tab-heading>
</tab>
<tab ui-sref="dashboard.deptmanagement.course" active="$state.current.name == 'dashboard.deptmanagement.course'">
<tab-heading>Add Course</tab-heading>
</tab>
<tab ui-sref="dashboard.deptmanagement.sub" active="$state.current.name == 'dashboard.deptmanagement.sub'">
<tab-heading>Add Subject</tab-heading>
</tab>
</tabset>
<div ui-view></div>
</div>
I have a navbar template that is meant to adapt and change according to whether or not the user is logged in.
I have a root state inherited by all the other states and an authenticated state inherited by all states that assume the user is logged in.
My root state:
.state('root', {
abstract: true,
template: '<ui-view />'
data: {
requiresLogin: false
},
views: {
'header#': {
//Issue: navbarCtrl is not defined here...
templateUrl: 'app/navbar/views/navbar.view.html'
},
'footer#': {
templateUrl: 'app/footer/views/footer.html'
}
}
})
and my authenticated state:
.state('authenticated', {
abstract: true,
parent: 'root',
views: {
'header#': {
controller: 'NavbarCtrl',
templateUrl: 'app/navbar/views/navbar.view.html'
}
},
data: {
requiresLogin: true
},
resolve: {
currentUserAccount: ['domainService', function (domainService) {
return domainService.currentUserAccount();
}]
}
})
Now the issue is that I need my navbarCtrl in the root state but this controller would not work there if the user is not logged in since the controller relies on data obtained when the user logs in:
.controller('NavbarCtrl', ['$scope', '$interval', 'messageService', 'currentUserAccount', function ($scope, $interval, messageService, currentUserAccount) {
$scope.currentUserAccount = currentUserAccount.data;
...
Here is also my navbar template:
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="navmenu" collapse="isCollapsed">
<!--if user is not connected-->
<ul ng-if="!authenticated" class="nav navbar-nav navbar-right">
<li>Fonctionnalités</li>
<li>À propos</li>
<li>Contact</li>
<li><a class="btnNav btn btn-primary" role="button" ui-sref="signup.form" href="#">S'inscrire</a></li>
</ul>
<!--if user is connected-->
<ul ng-if="authenticated" class="nav navbar-nav navbar-right">
<li ng-if="messageCount"><a ui-sref="message" href="#"><span style="font-size:16px;" class="glyphicon icon-email NewMail" aria-hidden="true"></span> {{messageCount}}</a></li>
<li class="visible-xs"><a ui-sref="dashboard.useraccount.summary" href="#">Mon compte</a></li>
<li class="visible-xs" ng-controller="SignoutCtrl"><a ng-click="signout()" href="#">Se déconnecter</a></li>
<li class="hidden-xs">
<section class="btn-group" dropdown>
<button type="button" class="btn btn-link" id="dropdown" dropdown-toggle>
<img ng-if="currentUserAccount.userAccountType==='PARENTS_TYPE'" src="assets/media/img/parents.svg" width="46" height="46" class="img-circle">
<img ng-if="currentUserAccount.userAccountType==='CHILDCARE_WORKER_TYPE'" src="assets/media/img/professionel.svg" width="46" height="46" class="img-circle">
{{currentUserAccount.firstName}}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdown">
<li><a ui-sref="dashboard.useraccount.summary" href="#"><span class="glyphicon icon-settings" aria-hidden="true"></span> Mon compte</a></li>
<li ng-controller="SignoutCtrl">
<a ng-click="signout()" href="#"><span class="glyphicon icon-lock" aria-hidden="true"></span> {{'SIGNOUT' | translate}}</a>
</li>
</ul>
</section>
</li>
</ul>
</div>
So I am not sure how to proceed with my navbar issue. I was thinking of checking whether $rootScope.authenticated is defined within NavbarCtrl but it does not seem right.
Your header controller should be in ancestor root abstract state and the dynamic functionality which you wants to handle (i.e. if the user is not logged in since the controller relies on data obtained when the user logs in) should be handled in it .You can handle the 2 header templates.(i.e. with login and without login) through ng-show/ng-hide in the header controller through scope variable states. In other words, header controller should be written in a way that without authentication it should return the without login header and with authentication it should written the after login header.
I am trying to do something here but it does not work, I have the following view:
<header ui-view="header">
</header>
and here is my app.js file:
.state('root', {
url: '',
views: {
'header': {
templateUrl: '/js/app/partials/layout/header.html',
controller: 'HeaderController'
},
'slider': {
templateUrl: '/js/app/partials/slider.html'
},
'container#': {
templateUrl: '/js/app/partials/home.html',
controller: 'HomeController'
},
'sidebar': {
templateUrl: '/js/app/partials/layout/sidebar.html',
controller: 'SideBarController'
},
'footer':{
templateUrl: '/js/app/partials/layout/footer.html'
}
}
})
Now this particular view:
'slider': {
templateUrl: '/js/app/partials/slider.html'
},
is not in my index.html file but rather within my /partial/layout/header.html file. Now the header template is being loaded into the header view, but the slider view does not show.
This is my header.html partial with my slider view inside:
<div class="container-fluid">
<div class="col-md-12">
<a href="#" class="pull-left">
<img src="images/logo.png" alt="Your Happy Family" class="img-responsive">
</a>
<!-- Begin Top Navigation -->
<div class="menu_block">
<nav class="horizontal-nav full-width horizontalNav-notprocessed">
<ul class="sf-menu">
<li class="home"><a ui-sref="root.home">home</a></li>
<li class="tickets">
tickets
<ul>
<li class="bus">Bus</li>
<li class="airline">Local Airline</li>
<li class="events">Events</li>
</ul>
<div class="clear"></div>
</li>
<li class="partners"><a ui-sref="root.partners">partners</a></li>
<li class="contact"><a ui-sref="root.contact">contact us</a></li>
</ul>
</nav>
<div class="clear"></div>
</div>
<!-- End Top Navigation -->
<div class="clear"></div>
<!-- Slider View -->
<div ui-view="slider">
</div>
<div class="clear"></div>
</div>
</div>
I am doing this for a reason, I need my slider view to appear within the header section.
What you usually need is relative pathing for multiple nested views. If you scroll down to the bottom of the docs (https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views) they explain what the syntax of relative pathing does.
This might be what you're looking for but I always get a little tripped up without actually testing the pathing and without a plunker...
'slider#root': {
templateUrl: '/js/app/partials/slider.html'
},
I have this nav.html:
<ul class="nav nav-pills pull-right">
<li ng-class="{ active: $state.includes('home') }"><a ui-sref="home">Home</a></li>
<li ng-class="{ active: $state.includes('about') }"><a ui-sref="about">About</a></li>
<li ng-class="{ active: $state.includes('contact') }"><a ui-sref="contact">Contact</a></li>
</ul>
<h3 class="text-muted">my page title</h3>
</div
This Controller:
.module('app', [
'ui.router'
])
.config(['$urlRouterProvider','$stateProvider', function($urlRouterProvider,$stateProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('about', {
url: '/about',
templateUrl: 'templates/about.html',
controller: 'aboutCtrl'
})
// and so forth
Now when I click a button in the navigation, the ui-router correctly displays tha page and changes the url in the browser adress bar. However Bootstrap does not make the button activated, aka selected or color it grey etc. How to achieve this the angular way?
You must make sure that $state service is defined/injected in your current scope. You may have a navCtrl that handles the rendering logic of your navbar html. Remember to inject that controller in your nav.html:
<ul ng-controller = "navCtrl" class="nav nav-pills pull-right">
Next, write a boolean function inside your navCtrl to check the current state, using $state.includes:
.controller('navCtrl',['$scope','$state','$location',function($scope,$state,$location){
$scope.isState = function(states){
return $state.includes(states);
};
}])
and lastly use this function in your html:
<li ng-class="{active: isState('home') }">
<a ui-sref="home">Home</a>
</li>
Here is the working plnkr.
I'm working on a project that has implemented the UI router and it's using ui-sref-active="active" to add the active class to the navigation menu item when that item is the current route. However, when you navigate to a nested view within that view, the parent menu item is no longer active. See the following Plunker:
http://plnkr.co/edit/2CoEdS?p=preview
By default (or if you click on it) Route 1 is "active". When you click on "Show List," you will see that Route 1 is no longer active.
Edit:
The only difference between this example and my actual project is that the navigation menu in my actual project has its own controller and so does not use the same scope as the controller for "route1".
EDIT For updated ui-router 0.2.13:
ui-sref-active="active" now sets the 'active' class when the current state is the ui-sref's state or any child
ui-sref-active-eq="active" behaves as the previous iterations of ui-sref-active, and only sets the class for the exact state
Original Answer:
See open ui-router issues:
https://github.com/angular-ui/ui-router/issues/704 and 818
A general workaround people are suggesting is:
ng-class="{active:$state.includes('route1')}"
Of course, $state must be added to $scope. See updated plunk: http://plnkr.co/edit/KHLDJP?p=preview
You are having a wrong understanding of ui-sref-active="active"
<li ui-sref-active="active"><a ui-sref="route1">Route 1</a></li>
This will show special css highlighting only when you are in state route1 (reference https://github.com/angular-ui/ui-router/wiki/Quick-Reference#wiki-ui-sref-active). This is the case when you click on route 1. But when you click on "Show list" you are no longer in route1.
Rather you are in state "route1.list" . You can verify this by writing the following code. This is strictly for understanding how state works.
js
inside controller
$rootScope.currentState = $state.$current.name //using rootScope so that you can access the variable anywhere inside html
inside html
{{currentState}}
If you look closely at documentation of ui-sref-active, it not only looks at stateName but also stateParams, hence when you go to substate it no longer changes css. From the sourcecode it becomes clearer.
function update() {
if ($state.$current.self === state && matchesParams()) {
$element.addClass(activeClass);
} else {
$element.removeClass(activeClass);
}// route1===route1.list will not be true.
to solve the problem, remember scope variables are inherited in nested views.
inside controller of route.
$scope.route1Active = true;
in html
<li ng-class={active:route1Active}><a ui-sref="route1">Route 1</a></li>
Angular UI router now supports this natively. See commit https://github.com/angular-ui/ui-router/commit/bf163ad6ce176ce28792696c8302d7cdf5c05a01
My solution was to set:
<li ng-class="{ 'active': state.current.name.indexOf('route1') != -1 }">
The state was already previously added to the controller's scope:
$scope.state = $state;
You do not need to do any thing in the controllers. Here is my example code:
<ul class="nav nav-pills nav-stacked" role="tablist">
<li ui-sref-active="active"><a ui-sref="Booking.Step1" href="#/Booking/Step1">Step1</a></li>
<li ui-sref-active="active"><a ui-sref="Booking.Step2" href="#/Booking/Step2" >Step2</a></li>
<li ui-sref-active="active"><a ui-sref="Booking.Step3" href="#/Booking/Step3">Step3</a></li>
<li ui-sref-active="active"><a ui-sref="Booking.Step4" href="#/Booking/Step4">Step4</a></li>
<li ui-sref-active="active"><a ui-sref="Booking.Step5" href="#/Booking/Step5">Step5</a></li>
</ul>
In route configuration:
$stateProvider.state('Booking', {
abstract: true,
url: '/Booking',
templateUrl: "TourApp/Templates/Booking/SideMenu.html",
controller: "SideMenuController"
});
$stateProvider.state('Booking.Step1', {
url: "/Step1",
views: {
'content': {
templateUrl: "TourApp/Templates/Booking/Step1.html",
controller: "Step1Controller"
}
}
});
$stateProvider.state('Booking.Step2', {
url: "/Step2",
views: {
'content': {
templateUrl: "TourApp/Templates/Booking/Step2.html",
controller: "Step2Controller"
}
}
});
Now they have updated and the new way to do that is
<a ui-sref-active="{'active': 'main.app.manage.**'}" ui-sref="main.app.manage.people.list"></a>
Below is the state file
angular.module('manage.people', ['people.invite'])
.config(['$stateProvider', function($stateProvider) {
$stateProvider
.state('main.app.manage.people', {
url: '/people',
abstract: true,
cache: false,
views: {
'tabContent': {
template: '<div ui-view="peopleContent"></div>',
controller: 'peopleController'
}
}
})
.state('main.app.manage.people.list', {
url: '/list',
views: {
'peopleContent': {
templateUrl: '/internal/main/app/manage/people/views/people.html',
controller: 'peopleListController'
}
}
});
We already have a solution without any "hack" HERE
That's the way to do:
HTML >
<li ui-sref-active="active" >
<a href="#" class="submenu" ui-sref="bands">
<i class="fa fa-location-arrow" aria-hidden="true"></i>
Bands
<span class="fa fa-chevron-down"></span>
</a>
<ul class="nav child_menu">
<li ui-sref-active="active">
<a ui-sref="bands.nirvana">
Nirvana
</a>
</li>
<li ui-sref-active="active">
<a ui-sref="bands.iron">
Iron
</a>
</li>
<li ui-sref-active="active">
<a ui-sref="bands.metalica">
Metalica
</a>
</li>
</ul>
Our router config will be like this >
$stateProvider.state('bands', {
abstract: true,
url: '/bands',
templateUrl: "myapp/categories/template.bands.html", //<ui-view></ui-view>
controller: "SomeController as vm"
}).state('bands.nirvana', {
url: '/nirvana',
templateUrl: "myapp/categories/band.nirvana.html",
controller: "SomeController as vm"
}).state('bands.iron', {
url: '/iron',
templateUrl: "myapp/categories/band.iron.html",
controller: "SomeController as vm"
}).state('bands.meatlica', {
url: '/metalica',
templateUrl: "myapp/categories/band.metalica.html",
controller: "SomeController as vm"
})
I have come here 2 years later the question was asked but angular-ui-router has much proficient approach in solving this issue. It worked for nested states too.
<ul>
<li ui-sref-active="active" class="item">
<a ui-sref="home">Home</a>
</li>
<!-- ... -->
</ul>
When app navigates to home state, this is how resulting HTML will appear :
<ul>
<li ui-sref-active="active" class="item active">
<a ui-sref="home">Home</a>
</li>
<!-- ... -->
</ul>
ui-sref-active quick reference :
A directive working alongside ui-sref to add classes to an element
when the related ui-sref directive's state is active, and removing
them when it is inactive. The primary use-case is to simplify the
special appearance of navigation menus relying on ui-sref, by having
the "active" state's menu button appear different, distinguishing it
from the inactive menu items.
Complete documentation.
I hope this is what you have been looking for.Place the parent url in the list class ,now whenever you navigate to child class parent class will be active
Step 1: Add a Controller for your nav bar orin your existing controller where nav bar is included add the following
app.controller('navCtrl', ['$scope', '$location', function($scope, $location) {
$scope.isActive = function(destination) {
return destination === $location.path();
}
}]);
Step2: In your nav bar
<li ng-class="{active: isActive('/home')}"><a ui-sref="app.home">Browse Journal</a></li>
Thats it.