Angular.js, router-ui and Bootstrap: Activate State of Clicked Button - angularjs

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.

Related

angular Js url navigation after getting rid of #

After reading this I was able to fix the # problem in my URL. It works fine without the URL.
In index.html
<base href="/app-name/">
My URL :
http://localhost:7001/app-name
Before applying base URL I had
http://localhost:7001/app-name/#/home
1) When I type this in browser how does the URL change to http://localhost:7001/app-name/home?
I was able to change and navigate to diff levels of application when using #. But, after applying base in index.html I am unable to perform this and the browser throws a 404. Any suggestions on how to get this working?
Here is my navigation page
<div class='navbar-header'>
<a class='navbar-brand' href="home"><img alt='img' src="appName/images/logo.PNG" type="image/png" height="30"></a>
<div class="navbar-header">
<a class="navbar-brand" href="home"><b>App - Name</b></a>
</div>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li> <span class="glyphicon glyphicon-home"></span> Home</li>
<li> <span class="glyphicon glyphicon-list-alt"></span> YYYYYYYYY </li>
<li> <span class="glyphicon glyphicon-hand-up"></span> XXXXXXXX</li>
</ul>
</div>
Router looks like this.
'use strict';
appName.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/home', {
templateUrl : 'appName/models/scheduler/home.html',
controller : 'mainController'
})
.when('/logs', {
templateUrl : 'appName/models/logs/logs.html',
controller : 'logsController'
})
.when('/info', {
templateUrl : 'appName/models/quick_info/info.html',
controller : 'yyyyController'
})
.otherwise({redirectTo:'/home'});
// $locationProvider.html5Mode(true);
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
Thanks for taking time to look into this.

Getting multiple select when reloading the page using angular.js

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.

Using UI Router in order to implement a navbar/header that changes according to whether the user is logged in or not

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.

AngularJS multilanguage routing

I have an AngularJS webapp. I´m changing the application so the URLs can be multilanguage (for SEO indexing purposes).
I´m setting up my app.js, like this:
$routeProvider.when('/:language', {templateUrl: 'partials/home.html', controller: 'HomeCtrl'});
$routeProvider.when('/:language/about', {templateUrl: 'partials/about.html', controller: 'AboutCtrl'});
Then, in a service I get the language parameter with $routeParams and call my translation code with angular-translate to serve the page in the corresponding language.
Everything is working so far.
But, moreover, in the menu bar, I have a select combo box to choose the language. So, when user change the language, the url language parameter should change.
How should I do this?
Here's an example. Like I said in your other question, I'd use ui-router for this.
http://plnkr.co/edit/bCNgS07BblMHz55VBRSQ?p=preview
The language dropdown will preserve the currently selected state. So if you go to home -> paragraph, then change language, you will remain on the paragraph route but the language parameter will change.
app.js:
routerApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/en');
$stateProvider
.state('lang', {
url: '/:language',
templateUrl: 'partial-lang.html',
abstract: true,
controller: function($state, $scope) {
$scope.changeLanguage = function(language) {
$state.go($state.current.name, {language: language});
}
}
})
.state('lang.home', {
url: '',
templateUrl: 'partial-home.html'
})
.state('lang.home.list', {
url: '/list',
templateUrl: 'partial-home-list.html',
controller: function($scope) {
$scope.dogs = ['Bernese', 'Husky', 'Goldendoodle'];
}
})
.state('lang.home.paragraph', {
url: '/paragraph',
template: 'I could sure use a drink right now.'
})
.state('lang.about', {
url: '/about',
templateUrl: 'partial-about.html'
});
});
partial-lang.html:
<nav class="navbar navbar-inverse" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" href="#">AngularUI Router</a>
</div>
<ul class="nav navbar-nav">
<li><a ui-sref=".home">Home</a></li>
<li><a ui-sref=".about">About</a></li>
<li class="dropdown">
<a href class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Language: {{$state.params.language | uppercase}} <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href ng-click="changeLanguage('en')">English</a></li>
<li><a href ng-click="changeLanguage('fr')">Français</a></li>
<li><a href ng-click="changeLanguage('ru')">Русский</a></li>
</ul>
</li>
</ul>
</nav>
<div class="container">
<div ui-view></div>
</div>
index.html
<body ng-app="routerApp">
<div ui-view></div>
<pre>
<p>state = {{$state | json}}</p>
</pre>
</body>
The rest of the files are self-explanatory
You bind your combo box to a variable, then you can use $watch to know when it changes, and finally you can user $route to update language.
$watch info
$route info
Update:
Something like this:
$scope.$watch('language', function (newValue, oldValue) {
if (newValue !== oldValue) {
$route.updateParams({language: newValue});
}
});
UPDATE VERSION 1.0.7
$scope.$watch('language', function (newValue, oldValue) {
if (newValue !== oldValue) {
var path = $location.path();
path = path.replace('/'+oldValue+'/', '/'+newValue+'/');
console.log(path);
$location.path(path);
$route.reload();
}
});

Angular UI Router: How do I get parent view to be "active" when navigating to nested view?

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.

Resources