angular-ui-router: add css class if state matched - angularjs

simple wiki
I'd like to show an edit button in the navbar is state == 'page'
v0.2.10
.state('page',{
url: "/wiki/{ns:[0-9a-zA-Z\-/_]+}/{wp:[0-9a-zA-Z\-/_]+}",
templateUrl: "views/wiki/view.html",
controller: "PageController"
})
I tried
<li ng-show="$state.$current.name == 'page'"><button type="button" class="btn btn-default navbar-btn">Edit</button></li>
and
<a ng-class="{hidden: $state.$current.name == 'page'}" class="btn navbar-btn btn-primary" ui-sref="edit">Edit</a>
even
$state.includes('page')
and
$state.is('page')

I do this all the time in projects. The trick is to add a method on scope to check states.
$scope.is = function(name){
return $state.is(name);
}
$scope.includes = function(name){
return $state.includes(name);
}
Html:
<li ng-show="is('page')">
<a ng-class="{hidden: is('page')}">...</a>
I generally put those on root scope, but they are extremely useful. Another thing to look into is using the ui-sref-active directives. They are very good when you are creating links to states, and also want to auto-magically add a class when that state is active.

I think the best way to do this is to use ui-sref-active directive. The usage is pretty straight forward:
<a ui-sref-active="active" ui-sref="login">Login</a>
So when you are on login page it will automatically add class active to your a tag.

Another way you can accomplish this with they way you've written it.
app.run(function($rootScope, $state) {
$rootScope.$state = $state;
});
This will make the state available in all views so you could do something like
$state.current.name == 'page'

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

Not getting breadcrumb name in view

<td><i class="dataentry-breadcrumb" /></td>
<!-- {{breadcrumb.length}} {{breadcrumb[0].nodeName}} -->
<td ng-repeat="breadCrumbObj in breadcrumb">
<i class="dataentry-breadcrumbArrow" />
<a class="dataentry-breadcrumbElement" href='#'
title="{{breadCrumbObj.nodeName}}"
ng-click=updateBreadCrumb(breadCrumbObj.level)>{{breadCrumbObj.nodeName}}</a>
</td>
In the above code, nodeName in anchor tag is not getting display in UI. But it is present in the array.I tried to print it and commented. It was showing nodeName. But not in anchor tag. Please anyone help me...
I will show how I did it, as it seemed more logical and more apstracted so you can have better control of the views you are displaying.
First of all, you place it in the basic html file where it is displayed. Something like this:
<div ncy-breadcrumb></div>
Now this allows you to create a independent element for a breadcrumb, so now we have basically a custom directive for it, and within breadcrumb.html you model it with something like this, again mostly html.
<div class="breadcrumb">
<span ng-repeat="step in steps | limitTo:(steps.length-1)">
<a class="btn btn-tab" href="{{step.ncyBreadcrumbLink}}">{{step.ncyBreadcrumbLabel}}</a>
<span class="btn btn-tab btn-tab-divider">></span>
</span>
<span ng-repeat="step in steps | limitTo:-1">
<span class="btn btn-tab btn-current">{{step.ncyBreadcrumbLabel}}</span>
</span>
</div>
So now that you have some layout in the breadcrumb, you call it from the state controller where you control the views of your app. You first set it up as dependency.
'$breadcrumbProvider', function($breadcrumbProvider, ..) {
configure it within the function
// configure breadcrump
$breadcrumbProvider.setOptions({
templateUrl: 'scripts/nav/breadcrump.html'
});
and than all there is left to do, name how you call it depending on where you are in the app. Like this:
.state('root.vacancy', {
url: '/vacancies/:id',
shouldHighlight: 'home',
views: {
'main-content#root': {
templateUrl: 'scripts/vacancies/vacancy.html',
controller: 'VacancyController',
resolve: {
vacancy: function(vacancyService, $stateParams) {
return vacancyService.getVacancy($stateParams.id);
}
}
}
},
ncyBreadcrumb: {
label: "{{newProfile.vacancyTitle}}",
parent: 'root.home'
}
})
You set the state for routing for each state you have in the app. This way a solid amount of modular architecture is incorporated, and your breadcrumb is superbly independent :)
Hope it helps.

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.

Angular App issue where buttons have to be clicked twice before state change

I am using ui-router on an angular app and experiencing a problem where certain buttons using ui-sref have to be clicked twice before it changes state. Just hoping someone else has had this same issue and found a solution.
here is the button html:
<button id="continue-btn1" type="button" class="btn btn-reset btn-continue" ui-sref="appGatewayEditor.suppPay" data-ng-disabled="suppQuestions.$invalid">continue <i class="fa fa-angle-double-right"></i>
</button>
The router is using nested views like this:
.state('appGatewayEditor.suppPay', {
url: "/supplemental-payment",
templateUrl: 'components/appGateway/appGatewayEditor/supplemental/suppPay.html',
controller: 'supplementalPayCtrl as suppPayCtrl'
})
Any suggestions would be appreciated!!

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