ui-router active class for parent menu when submenu selected - angularjs

I am a newbie to ui-router , i would like to get a menu like below (its not a collapse thing, please see the plnkr )
menu1
a) submenu1
b) submenu2
c) submenu3
menu2
menu3
I managed to get the menus and submenus using the ui-router but not sure about the proper way to use the ui-router and used ui-sref-active="active" active the menu , the problem am facing is when I click on the submenu i would like to get the active to parent also.. ie if I click submenu1 , submenu2 or submneu3 i want to active its parent menu1.
here is the plunker : http://plnkr.co/edit/1kpmUiacrb3Aoo4E19O1?p=preview

There is an updated plunker, which does use the $state.includes method as defined here
Angular UI Router: How do I get parent view to be "active" when navigating to nested view?
the changes are: menu gets controller which puts $state into $scope:
"menu#dashboard": { templateUrl: "menu.html",
controller : function ($scope, $state){ $scope.$state = $state },
},
instead of this:
<li ui-sref-active="active"><a ui-sref=".menu1.submenu1">Menu 1</a></li>
<li ui-sref-active="active"><a ui-sref=".menu2">Menu 2</a></li>
<li ui-sref-active="active"><a ui-sref=".menu3">Menu 3</a></li>
we have to use defintion with ng-class:
<li ng-class="{active:$state.includes('dashboard.menu1')}"><a ui-sref=".menu1.submenu1">Menu 1</a></li>
<li ng-class="{active:$state.includes('dashboard.menu2')}"><a ui-sref=".menu2">Menu 2</a></li>
<li ng-class="{active:$state.includes('dashboard.menu3')}"><a ui-sref=".menu3">Menu 3</a></li>
BUT: this feature would be in a next ui-router release as we can see here:
feat(uiSrefActive): Also activate for child states.
cite
To limit activation to target state use new ui-sref-active-eq directive
Breaking Change: Since ui-sref-active now activates even when child states are active you may need to swap out your ui-sref-active with ui-sref-active-eq, thought typically we think devs want the auto inheritance.

Related

Angularjs, Redirect views from controller

I'm new to angularJS. I'm using angularjs to implement a website. The website has two pages. The first page list all items and if user click on it, it will redirect to detail information page.
I have my routes configure as below:
var app = angular.module('myApp', ["ngRoute"]);
app.config(function($routeProvider) {
$routeProvider
.when("/list", {
templateUrl : "list.html",
controller : "listCtrl"
})
.when("/detail/:id"){
templateUrl : "detail.html"
}
});
In the list.html. I use ng-repeat to display a list of items and a listener on to listen mouse click.
<ul class="list-group">
<li class="list-group-item" ng-repeat="i in items">{{i.name}}
<a href="#" ng-click="goToEdit($index)">
<span class="glyphicon glyphicon-pencil"></span>
</a>
</li>
</ul>
I want to redirect view to detail information in the ng-click function.
I tried $location.path() but it not working.
$scope.goToEdit = function(index){
console.log($location.path());
$location.path("/detail/" + index);
console.log($location.path());
}
This way won't work.
Even though the second log on console show location.path() has been changed to " /detail/id".
If I add $scope.$apply() after $location.path(); Then I will get a action already in progress error.
Do you have any solution???
Thanks
It might have something to do with use href="#" which is not good when using hash based routing
You could just set the href yourself and don't really need the controller function or ng-click
<a ng-href="#/detail/{{$index}}" >
Note that you should really give each item a unique identifier as $index could change due to using filters in ng-repeat or removing data from array
Also you don't have a controller identified for your second route

Angular-ui-router: ui-sref-active with child active

I am using angular-ui-router and nested states in my application, and I also have a navigation bar. The nav bar is hand written, and uses ui-sref-active to highlight the current state. It is a two-level navigation bar.
Now, when I am in, say Candidate / Settings I would like both Candidate (in level 1) and Setting (in level 2) to be highlighted. However, using ui-sref-active, if I am in state Candidate.Settings then only that state is highlighted, not Candidate.
Candidate have sub-state - > bookmark, applicants
Setting have sub-state - > profile, password
I want to make active candidate and bookmark at a time while candidate should redirected to bookmark state on loading time.
I am able to make parent and child state active, but the problem is i want to load child state on clicking on candidate, and candidate and bookmark both should be active.
<ul class="ul-list">
<li ui-sref-active="current"><a ui-sref="advertiser.candidate" data-ng-click="showPage('candidatePage')">Candidates</a></li>
<li ui-sref-active="current"><a ui-sref="advertiser.settings" data-ng-click="showPage('settingsPage')">Settings</a></li>
<li class="hide block bg-green"><a class="nav-link">Help</a></li>
<li class="hide block bg-green"><a class="nav-link">Contact Us</a></li>
</ul>
<ul>
<li><a ui-sref-active="current" ui-sref=".bookmarks" data-ng-click="loadCandiatePage('bookmarks')">Bookmarks <span class="sr-only"></span></a></li>
<li><a ui-sref-active="current" ui-sref=".applicants" data-ng-click="loadCandiatePage('applicants')"> Applicants</a></li>
<li><a ui-sref-active="current" ui-sref=".hired" data-ng-click="loadCandiatePage('hired')">Hired</a></li>
</ul>
Thanks in advance!!!
You can use ng-class to set the desired class name by evaluating the $state.
To use $state if your view you need to make it available on the scope in the controller:
controller('mainCtrl', ['$scope', '$state', function($scope, $state) {
$scope.$state = $state;
}]);
Or if you want it to be available app wide without setting it in each controller you can define it on $rootScope with .run:
.run(function($rootScope, $state) {
$rootScope.$state = $state;
})
In your view you can still use ui-sref-active and also use ng-class to evaluate the current state. For example (substitute your application logic):
<li>
<a ui-sref-active="current"
ng-class="{'current': $state.current.name == 'advertiser.candidate'}"
ui-sref=".bookmarks"
data-ng-click="loadCandiatePage('bookmarks')">
Bookmarks <span class="sr-only"></span>
</a>
</li>
.state('advertiser.candidate', {
url: '/candidate',
abstract: true,
defaultChild: 'advertiser.candidate.bookmarks',
templateUrl: 'modules/users/views/advertiser/menuTabs/candidate/advertiser.candidate.html'
})
.state('advertiser.candidate.bookmarks', {
url: '/bookmarks',
templateUrl: 'modules/users/views/advertiser/menuTabs/candidate/advertiser.candidate.bookmarks.html'
})
and click on candidate page i set $state.go('advertiser.candidate.bookmarks'), then it worked for me.
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>
That's it.

How to refer DOM elements ID using "a href" inside views - Angular JS

I have tried to find some solution on google about this but couldn't get an exact answer.
I am trying to change tabs inside a view using below code:
<ul class="nav nav-tabs">
<li class="{active: selectedTab === 'details'}"><a href ng-click="selectTab('details')">Details</a></li>
<li class="{active: selectedTab === 'size'}"><a href ng-click="selectTab('size')">Size</a></li>
<li class="{active: selectedTab === 'shipping'}"><a href ng-click="selectTab('shipping')">Shipping</a></li>
</ul>
But whenever I am clicking on "Size" tab, the view redirects to some page. I mean URL changes
from http://localhost:8080/abcd/index.html#/ TO http://localhost:8080/Final_Albatross/index.html#/size
Without view implementation, the click refers to id "size" and tab changes.
Definitely angular is treating this click as a new view call. Please help me out!!
My JS file:
mainAngular.controller('ProductDetailController', function($scope, $routeParams) {
$scope.prod_Id = $routeParams.prodId;
$scope.selectTab = function(tabName) {
alert(tabName);
$scope.selectedTab = tabName;
alert($scope.selectedTab);
}
});
Although I have achieved it using "target="_self" but I want to do it in angular way.
Using anchor links in Angular require target="_self".
https://docs.angularjs.org/guide/$location
<ul>
<li>Link</li>
<li>Anchor</li>
</ul>
Forget about the jQuery, DOM way to handle that kind of problems. Use the angular way.
In AngularJS, the single point of truth is the model. The view (i.e. the HTML) is only a representation of that model, that changes automatically when the model changes.
So, you want a selected tab. Add that to the model:
$scope.selectedTab = 'details';
You want to be able to change which tab is selected. That is as simple as
$scope.selectTab = function(tabName) {
$scope.selectedTab = tabName;
}
And you want the view to be reflect the model values:
<ul class="nav nav-tabs">
<li class="{active: selectedTab === 'details'}"><a href ng-click="selectTab('details'}">Details</a></li>
<li class="{active: selectedTab === 'size'}"><a href ng-click="selectTab('size'}">Size</a></li>
</ul>

Navigate from parent state to children state

I have the below states, they appear in a menu which has a submenu.
What I would like to do is, when I click on the first state ('app.web'), to have in the menu both buttons 'active' (I use ui-sref-active="active" on main and sub menu <li>) and when I click on the second state, to have again both buttons 'active'.
At the moment, the below setup is
not working if I click the main menu, but
is working when I click the sub menu button.
main menu link state:
.state('app.web', {
url: '/:webID/dashboard',
views: {
'container#': {
templateUrl: '...',
}
}
sub menu link state:
.state('app.web.dashboard', {
url: '^/:webID/dashboard',
views: {
'container#': {
templateUrl: '...',
controller: '...',
}
}
}
I understand you want to have both links to be marked with "active" ... parent and child ... even if only parent is selected. But this is not possible...
As we can read here:
ui-sref-active
Description
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.
...
Will activate when the ui-sref's target state or any child state is active...
As shown in the doc (cited above): "Will activate when the ui-sref's target state or any child state is active".
Other words, having selected Parent - will never trigger that feature.
Here is a working plunker showing how these links will be decorated:
<a ui-sref-active="active" ui-sref="app">
<a ui-sref-active="active" ui-sref="app.web({webID:123})">
<a ui-sref-active="active" ui-sref="app.web.dashboard({webID:123})">
EXTEND: why is this plunker not working?
// working
<a ui-sref-active="current" ui-sref="home">
<a ui-sref-active="current" ui-sref="home.child1">
<a ui-sref-active="current" ui-sref="home.child2">
// NOT WORKING
<a ui-sref-active="current" href="#/home">
<a ui-sref-active="current" href="#/home/child1">
<a ui-sref-active="current" href="#/home/child2">
The point is - ui-sref-active is dependent on ui-sref. The above doc link says:
ui-sref-active can live on the same element as ui-sref or on a parent element. The first ui-sref-active found at the same level or above the ui-sref will be used.
The point is - we need ui-sref. Without that directive, the ui-sref-active simply won't work.
Some more details could be found in this answer

AngularJS UI Router - Nested state with individual views

I have a menu on my website, where the items have an active state. The default state is areas, then I can navigate through my website changing states.
<li ui-sref-active="active">
<a ui-sref="areas">
<span>Areas</span>
</a>
</li>
.state('areas', {
url: '/areas',
templateUrl : 'templates/areas.html',
controller : 'AreaCtrl'
})
In my areas.html template, I have a list, with items which can be clicked...:
<li ng-repeat="area in areas" ui-sref="areas.city({areaId: area.area_id, areaName: area.name})">
Now when one of these is clicked, I need to keep the active state on my menu. So the only way of doing this is via nested states...
.state('areas.city', {
url: "/:areaId/:areaName",
templateUrl: 'dist/templates/cities.html',
controller: 'CityCtrl'
})
However the problem is, my cities.html needs to be a totally new view (in place of where areas.html is), which isn't nested within areas (so I don't have a <ui-view> within areas.html).
I can, just not nest the view, so the state is .state('city', but then I lose the active state on the menu.
Any clue how I get around this?
You can activate the state in the main menu as like below
<li ng-class="{active: $state.includes('area') || $state.includes('areas.city')}">
<a ui-sref="areas">
<span>Areas</span>
</a>
</li>
Also, please apply the $state into $rootScope. So that you can access $state in any views.
myApp.run(function($rootScope, $state) {
$rootScope.$state = $state;
});

Resources