How to set active class on the current state using angular-route? - angularjs

my route file
app.config(["$routeProvider",function($route)
{
$route.when("/",{
templateUrl : "partials/index.html",
controller : "AppCtrl"
}).when("/contact",{
templateUrl:"partials/contact.html",
controller:"ContactCtrl"
}).
when("/about-us",{
templateUrl:"partials/about.html",
controller:"AboutCtrl"
}).
when("/gallery",{
templateUrl:"partials/gallery.html",
controller:"GalleryCtrl"
}).
otherwise({
redirectTo:"/"
});
}]);
in my header.html partials i'm using HeaderCtrl controller
app.controller("HeaderCtrl",["$scope","$location",function($scope,$location)
{
$scope.location=$location.path().replace("/","");
}]);
my header.html
<ul ng-controller="HeaderCtrl">
<li ng-class="{active:location===''}">home</li>
<li ng-class="{active:location==='about-us'}">about us</li>
<li ng-class="{active:location==='gallery'}">gallery</li>
<li ng-class="{active:location==='contact'}">contact</li>
</ul>
when the page reloads (actual refresh) then it works ie the class active is applied on the respective li but when i change the routes (by clicking on the menu items) it doesn't work

The solution to your problem is to bind an event that updates $scope.location when the URL successfully changes. You don't have to bind a click event to each <li> element. What if the route is invalid or fails? You don't want to show the user that element is the active route when it's really not.
If you read the documentation on the $location service, you'll see an events section. The one we're interested in is $locationChangeSuccess. To wire it up in your controller, do this:
$scope.$on('$locationChangeSuccess', function () {
$scope.location = $location.path().replace('/', '');
});

you add some object like active to router and set condition on your html with ngClass
like this :
app.config(["$routeProvider",function($route)
{
$route.when("/",{
templateUrl : "partials/index.html",
controller : "AppCtrl",
active:'home',
}).when("/contact",{
templateUrl:"partials/contact.html",
controller:"ContactCtrl",
active:'contact',
}).
when("/about-us",{
templateUrl:"partials/about.html",
controller:"AboutCtrl",
active:'about',
}).
when("/gallery",{
templateUrl:"partials/gallery.html",
controller:"GalleryCtrl"
active:'GalleryCtrl',
}).
otherwise({
redirectTo:"/"
});
}])
//remember that add $route inside the scope
.controller("HeaderCtrl",["$scope","$location",function($scope,$route)
{
$scope.$route = $route;
}]);
.active{
color:#a33;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<ul ng-controller="HeaderCtrl">
<li data-ng-class="{'active':$route.current.active === 'home'}">home</li>
<li data-ng-class="{'active':$route.current.active === 'about'}">about us</li>
<li data-ng-class="{'active':$route.current.active === 'gallery'}">gallery</li>
<li data-ng-class="{'active':$route.current.active === 'contact'}">contact</li>
</ul>

Related

Each time I load new link, it is redirected to my home link in angular js

I am not able to figure out why this behaviour occur. Each time I try to load new location by clicking anchors, it redirect to root location. I am builing my app in subdirectory http://localhost/myapp/. Kindly see the code below.
Here is HTML Code:
<ul class="nav navbar-nav navbar-right">
<li>Home</li>
<li>Insert Leave</li>
<li>Current Year</li>
</li>
</ul>
Here is script:
var app = angular.module('leaveApp',['ngRoute']);
app.config(['$routeProvider',function($routeProvider){
$routeProvider
.when('/',{
templateUrl : 'templates/temp.php',
controller : 'homeCtrl'
})
.when('/insertLeaveDetails',{
templateUrl : 'templates/temp.php',
controller : 'insertLeaveDetailsCtrl'
})
.when('/currentYearDetails',{
templateUrl : 'templates/temp.php',
controller : 'currentYearDetailsCtrl'
})
.otherwise({
redirectTo: '/'
});
}]);
app.controller('homeCtrl',['$scope',function($scope){
console.log('home ctrl');
$scope.msg = 'This is home ctrl';
}]);
app.controller('insertLeaveDetailsCtrl',['$scope',function($scope){
console.log('insert ctrl');
$scope.msg = 'This is leave ctrl';
}]);
app.controller('currentYearDetailsCtrl',['$scope',function($scope){
console.log('current deatail ctrl');
$scope.msg = 'This is current year ctrl';
}]);
The default value for $locationProvider.hashPrefix is "!". This means that, unless you change the provider value, your links should look like
<ul class="nav navbar-nav navbar-right">
<li>Home</li>
<li>Insert Leave</li>
<li>Current Year</li>
</ul>

template not displaying binded data after routed, on first click - AngularJS

Trying to route to different view template from the index page. Initially, the list on main index page gets loaded and the main.html gets loaded in ng-view, displaying it's text contents. The data from 'MainCtrl' is broadcasted properly and works fine. Now, the confusion is, when the item from the list is clicked, it gets routed to content template(content.html), but the content does not display the binded value on the first click on the list. But, after second click, it starts showing the binded values that is broadcasted from MainCtrl.
<body ng-app="myApp">
<div ng-controller="MainCtrl">
<ul ng-repeat="value in msg" ng-click="setSelectedValue(value)">
<li>
<a href='#/content'>{{ value }}</a>
</li>
</ul>
</div>
<div ng-view=""></div>
main.html:
<p>Select from the list.</p>
content.html:
//loads the selected item from the list on index page
<h3>Selected: {{ message }}</h3>
angular
.module('myApp', ['ngRoute'])
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
.when('/content', {
controller: 'ContentCtrl',
templateUrl: 'views/content.html'
})
.otherwise({
redirectTo: '/'
});
})
.factory('myService', function($http, $rootScope){
var sharedService ={};
sharedService.message = '';
sharedService.prepforBroadcast = function(value){
this.message = value;
this.broadcastItem();
};
sharedService.broadcastItem = function(){
$rootScope.$broadcast ('handleBroadcast');
};
return {
sharedService: sharedService
};
})
.controller('MainCtrl', function ($scope, myService) {
$scope.msg = data; //this will be json data
$scope.selectedValue;
$scope.setSelectedValue = function(value){
$scope.selectedValue = value;
myService.sharedService.prepforBroadcast(value);
}
})
.controller('ContentCtrl', function ($scope, myService) {
$scope.$on('handleBroadcast', function(){
$scope.message = myService.sharedService.message;
})
});
Not sure what exactly is the reason for not binding the data on the very first click even though when the template loads instantly. Any help or thought would be greatly appreciated. Scratching my head for a while.
<ul ng-repeat="value in msg" ng-click="setSelectedValue(value)">
check with out ng-click="setSelectedValue(value)" part. seems like ur click is going to handle by setSelectedValue(value) function
The ng-repeat and ng-click should be on li.
<ul>
<li ng-repeat="value in msg" ng-click="setSelectedValue(value)">
<a href='#/content'>{{ value }}</a>
</li>
</ul>

Active link/tab in AngularUI Router

I'm using AngularUI Router and I'm trying to have nested/children links.
All works fine but how do I have selected/active link in Contact tab?
Basically, I need to be able to have selected/active contact one link when the Contact page is loaded. Currently it does not read for some reason the controlleroneCtrl unless I click on the link contact one.
angular
.module ('myApp', ['ui.router'
])
.config (['$urlRouterProvider', '$stateProvider', function ($urlRouterProvider, $stateProvider) {
$urlRouterProvider.otherwise ('/summary');
$stateProvider.
state ('summary', {
url: '/summary',
templateUrl: 'summary.html',
controller: 'summaryCtrl'
}).
state ('about', {
url: '/about',
templateUrl: 'about.html',
controller: 'aboutCtrl'
}).
state ('contact', {
url: '/contact',
templateUrl: 'contact.html',
controller: 'contactoneCtrl'
})
// Sub page
.state('contact.one',{
url: '/contact.contactone',
templateUrl: 'one.html',
controller: 'contactoneCtrl'
})
// Sub page
.state('contact.two',{
url: '/contact.contacttwo',
templateUrl: 'two.html',
controller: 'contacttwoCtrl'
});
}]);
Plunker: http://plnkr.co/edit/DWjp5M6kJt2MyBrasfaQ?p=preview
There's a much quicker way to do this. Just use the ui-sref-active="active" attribute instead of ui-sref.
An example:
<ul>
<li ui-sref-active="active">
<a ui-sref="state">State 1</a>
<li>
<ul>
When the state is active the list item gets the class active. If you want a different class for active states or more than one class, just add it as follows
<ul>
<li ui-sref-active="active so-active super-active">
<a ui-sref="state">State 1</a>
<li>
<ul>
I use the pattern of exposing state on the root scope and using state.current.name in templates. I justify this global exposure because it's an app-level concern. If your navigation directive has isolate scope you'll need to pass it in, but that's no biggie.
In practice it's been very good for us I think.
Looks like this:
javascript
app = angular.module ('myApp', ['ui.router']);
app.controller('MainController', function($scope, $state){
$scope.state = $state;
});
html:
<nav>
<ul>
<li ng-repeat="tab in tabs" ng-class="{active: state.current.name === tab.id}>{{tab.name}}</li>
</ul>
</nav>
here is the updated plunk - http://plnkr.co/edit/UjjNm4JJIsjb4ydWZRDi?p=preview
Changes
added a new controller contactCtrl
setup $state.go('contact.contactone'); inside the contactCtrl
updated app.js so that /contact points to contactCtrl
I'm using ng-class like this:
ng-class="{active: state.current.name.split('.')[1] === 'homepage'}"
My "state" name is structured like:
app
app.homepage
app.profile
app.profile.user
.etc
For example, in my homepage, it's button became like this:
<li ng-class="{active: state.current.name.split('.')[1] === 'homepage'}"><a ui-sref="app.homepage">Home</a></li>
So just define scope of $state like #Simple As Could Be said at root of the app controllers, and you can use ng-class to whatever your app's state and how deep your app's state nested.
See my plunk http://embed.plnkr.co/bRfl1S9KXQuvL0Bvt9jD/preview.
Also try updating the version of ui-router to 0.2.12.
Only client tab as really been implemented.

AngularJS $location.path() changed after upgrading to 1.1.15

I have a NavigationController that has a selectedItem for the current selected item in a navigation list. It uses $location.path() to try and set it to a default value. It's in hashbang mode. Here is a simplified version:
App.controller("NavigationController", ['$scope', '$location', function($scope, $location) {
$scope.currentSelection = $location.path() || "/dashboard";
$scope.select = function( name ) {
$scope.currentSelection = name;
}
}]);
And the html:
<body ng-app="App">
<div class="container-fluid absoluteFill">
<div class="row-fluid fill" ng-controller="NavigationController">
<div class="span2 nav-bubble fill">
<ul class="nav nav-list">
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
</div>
<div ng-view></div>
</div>
</div>
</body>
And the config:
angular.module("App", ["ngResource"])
.config(function($routeProvider) {
$routeProvider.
when( '/', { redirectTo: '/dashboard' }).
when( '/dashboard', {
controller: 'DashboardController',
templateUrl: '/gpa/app/views/dashboard.html'
}).
otherwise({redirectTo: '/'});
})
The problem is that when I navigate to /home/index (without a hash bang) $location.path() returns "/index" where it used to return null prior to 1.1.15. However, if I go to "/home/index#/dashboard it returns "/dashboard" as expected. I tried redirecting when someone goes to "/" to "/dashboard", but NavigationController is called prior to being redirected so it continues to get "/index".
So how can I at least tell when the hashbang is not included? $location.hash() always seems to return "". I don't want to hard code "/index" in my code to know when nothing is on the URL.
I think you want to use the $route service and hook into the $routeChangeSuccess event.
App.controller("NavigationController", function($scope, $location) {
$scope.$on("$routeChangeSuccess", function (scope, next, current) {
$scope.currentSelection = $location.path() || "/dashboard";
});
$scope.select = function( name ) {
$scope.currentSelection = name;
}
});

nest ng-view inside a form

given the controller
function ctl($scope, $http) {
$scope.postForm = function() {
console.log("submitting form")
}
}
and the view
<form name="pform" ng-show="!error.Show">
<div ng-view></div>
<button type='button' value='Save' ng-click="postForm()" />
</form>
The controller method postForm doesn't get called, however, if i move the form tag into the view the method is called. Is there a reason that this doesn't work as I expect it to? Is there another way to accomplish the goal of sharing the form controls across different views?
Update
my module and routeProvider are configured like this:
angular.module("profilemodule", [])
.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when("/info", { templateUrl: '/partials/profile/info.html', controller: ProfileController })
.when("/user", { templateUrl: '/partials/profile/user.html', controller: ProfileController })
.when("/introduction", { templateUrl: '/partials/profile/editor.html', controller: ProfileController })
.otherwise({ redirectTo: '/info' });
}]).run(function ($rootScope, $location) {
$rootScope.location = $location;
})
and the page includes some nav elements which are set based on the location service like so:
<div class="row">
<div class="offset2 span10">
<ul class="nav nav-pills">
<li ng-class="{active: location.$$path.substring(0, '/info'.length) == '/info'}"><a href="#/info" >Information</a></li>
<li ng-class="{active: location.$$path.substring(0, '/user'.length) == '/user'}"><a href="#/user" >User</a></li>
<li ng-class="{active: location.$$path.substring(0, '/intro'.length) == '/intro'}"><a href="#/intro" >Introduction</a></li>
</ul>
</div>
</div>
<form name="pform" method="POST" ng-show="!error.Show">
<div ng-view></div>
<button type='button' value='Save' ng-click="postForm()" />
</form>
the ng-class statements works perfectly, is it because I've set the location property of $scope in the module's run method?
thanks,
jason
ng-view with routing creates a new scope with the controller, and you can't reach a child scope. Your submit action lies in the parent scope and the form data lies in the child scope (created by ng-view).
If you want to use common form controls, you can use ng-include, this directive gets template it and renders that in the current scope.
Move your form controls to a new template, then include them in all of your forms.
API reference:
http://docs.angularjs.org/api/ng.directive:ngInclude

Resources