ngClass not updating the class - javascript

I am using angularJS with bootstrap to design a navigation on my application. I have defined a main controller and inside the main controller I call different page views using the ng-view attribute and then these individual views have their own controllers.
I am using the ng-class attribute to add the active class to my links, however, it is not working. The expression evaluates to true or false but the ng-class does not updates the class="active" on the elements.
On my home page I have the following code -
<section ng-controller="dashBoardCtrl" class="container">
<section class="row">
<h1>DME DashBoard | <small>WFM HeadCount</small> </h1>
</section>
<section class="row">
<ul class="nav nav-tabs">
<li role="presentation" ng-class="{active: {{path=='/'}}}"><a ng-href="#/">Home</a></li>
<li role="presentation" ng-class="{active: {{path=='/login'}}}"><a ng-href="#/login">Login</a></li>
</ul>
</section>
<section ng-view></section>
</section>
This is how the routes are configured on the app -
dmeDash.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: '/views/home.html',
controller: 'homePageCtrl'
})
.when('/login', {
templateUrl: '/views/login.html',
controller: 'loginCtrl'
})
.otherwise({
redirectTo: '/'
});
}]);
The dashBoardCtrl have the following code -
dmeDashControllers.controller('dashBoardCtrl', ['$scope','$location', function($scope, $location) {
$scope.path = $location.$$path;
$scope.$watch('path',function(n,o) {
})
}]);
Home Page Controller has the following code -
dmeDashControllers.controller('homePageCtrl', ['$scope','$location', function($scope, $location) {
$scope.$parent.path = $location.$$path;
}]);
The log in page controller has the following code -
dmeDashControllers.controller('loginCtrl', ['$scope','$location', function($scope, $location) {
$scope.$parent.path = $location.$$path;
}]);
When I click from Home page to Login page the active class is not removed from home page link and not applied to the login page as well, however, when I view the code in firebug the expressions evaluates to true or false when the page changes.
When I refresh on individual pages the ng-class works correctly but not when using the hyperlinks, please suggest.

The syntax is wrong on the template. It should be:
<li role="presentation" ng-class="{'active': path==='/'}"><a ng-href="#/">Home</a></li>
And as style guide try using the === instead of the simple == because of type coercion. Or test agains truthy or falsy

Related

Angular Routing - Load data into parent page before first route

I am using angular routing for a admin panel project. Following is my angular js code.
app.js
(function() {
var app = angular.module("app", [
"ngRoute",
"app.dashboard",
"app.calendar",
"app.event"
]);
var dashboard = angular.module("app.dashboard");
dashboard
.config(function($routeProvider) {
$routeProvider.
when('/dashboard', {
templateUrl: '/views/dashboard/dashboard.html',
controller: 'DashBoardIndexController as ctrl'
}).
when('/dashboard/detail', {
templateUrl: "/views/dashboard/detailgraph.html",
controller: "DashBoardDetailController as ctrl"
})
});
......
......
//Controllers related to dashboard module
var calendar = angular.module("app.calendar");
calendar
.config(function($routeProvider) {
$routeProvider.
when('/calendar', {
templateUrl: '/views/calendar/calendar.html',
controller: 'CalendarIndexController as ctrl'
}).
when('/calendar/markevent', {
templateUrl: "/views/calendar/markevent.html",
controller: "CalendarEventController as ctrl"
})
});
......
......
//Controllers related to calendar module
}());
For better code management, I am dividing various module of application and including them in main app module.
After login, the first route loaded will be of dashboard (/dashboard). But before route provider initialized and dashboard loaded, I need to fetch the user's rights level and accordingly create the side navigation menus in parent page. Below is my parent page:
home.html
<body ng-app="app">
<header>
<nav id="mynav" class="bold z-depth-1" role="navigation">
<div class="nav-wrapper container">
<a id="logo-container" href="#" class="brand-logo text-darken-1">Logo</a>
<div class="container">
<a href="#" data-activates="slide-out" class="button-collapse top-nav full hide-on-large-only black-text"><i
class="mdi-navigation-menu"></i></a>
</div>
</div>
</nav>
<ul id="slide-out" class="side-nav fixed center-align">
<!-- This side menu items should be created based on user's rights --!>
</ul>
</header>
<main class="grey lighten-4">
<div id="main-container" class="container z-depth-1 ">
<div ng-view=""></div>
</div>
</main>
As you can see, before ng-view is loaded with first route (/dashboard), I need to make server call to fetch the user's rights. I am relatively new to angular and I think we can do this by resolve promise. But here two modules are different (app and app.dashboard).
What could be the correct way to solve this problem?

ngHide directive only works with ngRoute module after page refresh

When I login on my app, I want the login and signup button to disappear from the nav so I am using ng-hide directive if the login was successful and a token was received from the server, which I store in the cookies.
Nav is part of the index.html file.
Because I am using angular routing, when login is successful, index.html is not loaded again instead I render the home page through ng-view directive.
The problem is I have to refresh the page for ng-hide to work. I am assuming it is because ng-hide is part of index.html page, which does not get reloaded.
Hoping there is a bette solution than refreshing the page every time someone logs in.
Here is some of my relevant code.
HTML
<!-- Navigation -->
<nav class="navbar navbar-custom navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-main-collapse">
<i class="fa fa-bars"></i>
</button>
<a class="navbar-brand page-scroll" href="#/">
<i class="fa fa-play-circle"></i> <span class="light">Webnar</span>
</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse navbar-right navbar-main-collapse">
<ul class="nav navbar-nav">
<!-- Hidden li included to remove active class from about link when scrolled up past about section -->
<li class="hidden">
</li>
<li>
<a class="page-scroll" href="#about">Webinars</a>
</li>
<li ng-hide="token">
<a class="page-scroll" href="#/login">Login</a>
</li>
<li ng-show="token">
<a class="page-scroll " href="#/create">Add a webinar</a>
</li>
<li ng-hide="token">
<a class="page-scroll btn btn-default " href="#/signup">Sign Up</a>
</li>
<li ng-show="token" >
<a class="page-scroll btn btn-default" ng-click="logOut()">Logout</a>
</li>
</ul>
</div>
<!-- /.navbar-collapse -->
</div>
<!-- /.container -->
</nav>
App.js
var webinarApp = angular.module('webinarApp', ['ngCookies', 'ngRoute']);
webinarApp.config(function($routeProvider){
$routeProvider
.when('/', {
templateUrl: './home.html',
controller: 'mainController'
})
.when('/signup', {
templateUrl: './signup.html',
controller: 'mainController'
})
.when('/login', {
templateUrl: './login.html',
controller: 'mainController'
})
.when('/create', {
templateUrl: './create.html',
controller: 'mainController'
})
});
webinarApp.controller('mainController', ['$scope', '$http', '$cookies', '$location', function($scope, $http, $cookies, $location){
$scope.welcomeMessage = '';
$scope.users = [];
$scope.searchQuery = "";
$scope.orderByField = 'name';
$scope.newUser = {};
$scope.logInUser = {};
$scope.webinars = [];
$scope.newWebinar = {};
$scope.isDisabled = false;
// ============== Users ================
$scope.getUsers = function(){
$http.get('/api/users').then(function(response){
$scope.users = response.data;
});
};
$scope.getUsers();
$scope.createUser = function(){
$http.post('/api/users', $scope.newUser).then(function(response){
console.log(response.data)
$scope.users.push(response.data);
$scope.newUser = {};
$location.path('/login');
});
};
$scope.obtainToken = function(){
$http.post("/api/users/authentication_token", $scope.logInUser).then(function(reponse){
$scope.token = reponse.data.token;
console.log($scope.token);
$cookies.put('token', $scope.token);
$location.path('/')
});
};
It's because you put the navbar on the index page. It's not a template that is loaded by the route module. So it's not related to any route and controller that are bind with it. Controller declared in routes only applies for template that are loaded by the route module.
To bind a controller whatever the route is use ng-controller directive. Put it on your <nav> element
Note if you use the "as controller" syntax you must do in controller :
this.isDisabled
instead of
$scope.isDisabled
Documentation : https://docs.angularjs.org/#!/api/ng/directive/ngController
If you need to update datas to that controller with the rest of the application. Use $rootScope. If you use 'ctrl as' syntax, the easier is to do :
this.$rootScope=$rootScope;
If you don't like this use $watch to watch for changes and rebind the currentValue to the controller :
$rootScope.watch('myParameter', function(new){
this.myParameter = new;
});
AND DON'T FORGET TO INITIALIZE THE VARIABLE IN $ROOTSCOPE. Or the variable will end up in a child scope that won't be visible for your navbar's controller.
You should declare $scope.token with your other variable declarations. It does not exist in the scope when you are initially setting your ng-hide.
$scope.isDisabled = false;
$scope.token;
Have you tried using $scope.$apply() ???
$scope.$apply(function() {
$scope.token = <whatever value>;
})
Ok i think one way to do this would be to add a controller for nav say navbarController.
<nav ng-controller="navbarController">...</nav>
Inject $rootScope into both maincontroller and navbarController.
then in mainController whenever you need to change value of token, do this
$rootScope.$emit('tokenValueChange', <value>);
then in navbarController add,
$rootScope.$on('tokenValueChange', function(newValue) {
$scope.token = newValue;
})
I am not sure if this is a perfect method but this should work.
I had a similar problem as OP (viditsaxena), and solved it the same way he did. Like him, I had ng-hide in my nav which was located in index.html. My ng-hides worked correctly on initial page load, but when I tried to navigate to a different view, my ng-hide's would not work until I refreshed the page.
My solution: The same way #viditsaxena describes in his comments under the accepted answer (use $rootScope instead of $scope), but I thought I'd put my actual code here to show you how I made it work in my app.js file:
I went from this (ng-hide required refresh to load after I navigated away from the original view):
app.controller('routeController', ['$scope', '$location', function($scope, $location) {
$scope.showPortfolioHeader = $location.path() === '/jcRealty';
}]);
To this (now my ng-hides don't require a refresh after I navigate away from my first view):
app.controller('routeController', ['$rootScope', '$location', function($rootScope, $location) {
$rootScope.showPortfolioHeader = $location.path() === '/jcRealty';
}]);
The accepted answer got me part of the way there, but I had a hard time deciphering some of the grammar in his response. My own testing confirmed some of what he said. My controller above (routeController) is related to the view located at the /jcRealty path. If I put my ng-hides in my jcRealty view, they work properly (no refresh needed) using $scope. But since my ng-hide's are on index.html, outside of that controller's path, $rootScope was needed to not require a page reload.

Template not loading in Angular route

Issue is quite simple. I have been trying for hours now but just couldn't get the template to load via angularJS client side routing. Not using any server side routing.
So, used various combinations of paths. If I use "/home" in button href it straight away gives error that it couldn't find "/home". But with "#/home", I don't get that error but it still wouldn't load the template.
Any help would be greatly appreciated.
Created a new plunker: http://plnkr.co/edit/F7KoWbBuwsXOQLRPF0CN?p=preview
Template directory:
Project ---
|
|
CSS
|
|
JS
|
|
templates---
|
|
home.html
JS:
var myApp = angular.module("myApp",['ngRoute']);
myApp.controller('appController',function($scope,$http){
//mytext = 0; instantiating variables without using var gives referencing error due to "use strict";
$scope.angular = angular;
$scope.mytext = "Harsh";
$scope.formSuccess = false;
$http({method:"GET", url:"JS/carousel-data.json"}).
success(function(data) {
$scope.carouselData = angular.fromJson(data);
}).
error(function(data) {
console.log("Error loading images");
});
myApp.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/home', {
templateUrl: 'templates/home.html',
controller: 'appController'
})
.when('/edit', {
templateUrl: 'templates/home.html',
controller: 'appController'
});
});
HTML:
<body ng-controller="appController">
<header id="pageHeader" class="col-md-12 col-sm-12 col-xs-12 header">
<nav class="col-md-5 col-sm-6 col-xs-10 menu">
<ul class="nav nav-pills" id="menuLinks">
<li class="dropdown visible-xs">
Sapient <span class="caret"></span>
<ul class="dropdown-menu" role="menu">
<li>Home</li>
<li>Edit</li>
</ul>
</li>
<li role="presentation" class="hidden-xs" >Home</li>
<li role="presentation" class="hidden-xs" >Edit</li>
</ul>
</nav>
</header>
<div ng-view></div>
</body>
It's rather unclear how you've set up things? Is the HTML your index or is that your home.html?
Secondly you already declare the controllers of your pages to be appController, no need to define that with the ng-controller directive anymore.
Apart from that you're loading the same template on each href, could it be that you're just seeing the same page like declared?
$routeProvider
.when('/home', {
templateUrl: 'templates/home.html', <---
controller: 'appController' <---
})
.when('/edit', {
templateUrl: 'templates/home.html', <---
controller: '**appController'<--
});
It should be noteworthy that there is a more extensive module for routing. You can find it at ui-router.

AngularJS show login/logout button conditionally in navbar on app page

Main.jsp
<html>
<body ng-app="myApp">
<div class="navbar">
View Orders
<a href="/logout" ng-show="$scope.isUserLoggedIn"> Logout </label>
<a href="/login" ng-show="!$scope.isUserLoggedIn"> Login </label>
</div>
<div ng-view></div>
</body>
</html>
Controllers
var myApp = angular.module('myApp', ['ngRoute']);
...
// route for the default home page
.when('/', {
templateUrl : function($node, tattrs) {
return "resources/html/home.html";
},
controller : 'mainController'
})
// route for the order page
.when('/order', {
templateUrl : function($node, tattrs) {
return "resources/html/order.html";
},
controller : 'orderController'
})
....
myApp.controller('mainController', function($scope, $http) {
....
$scope.isUserLoggedIn = true; //or false
.....
Question:
The $scope.isUserLoggedIn is having no effect on Login/Logout hrefs. The scope is probably not accessible on the main app page (i.e in the navbar in the ng-app page).
I want to show hide the Login/Logout button conditionally. Any ideas?
You are missing assigning controller to div
No need to use $scope there, just use
<div class="navbar" ng-controller="mainController">
View Orders
<a href="/logout" ng-show="isUserLoggedIn"> Logout </label>
<a href="/login" ng-show="!isUserLoggedIn"> Login </label>
</div>

angularjs: ng-click on <a> not working, works on <button>

Here is the Javascript
function gotoUrl($scope, $location, $http, $window) {
$scope.setRoute = function (route) {
$location.path(route);
};
My code is
<ul class="nav navbar-nav navbar">
<li><a href="#" data-ng-click="setRoute('summary')"><span
class="icon-bar-chart"></span> Summary</a></li>
<li><a href="#
" data-ng-click="setRoute('transactions')"><span
class="icon-reorder"></span>
Transactions</a></li>
<li><a href="#" data-ng-click="setRoute('budgets')"><span
class="icon-calendar"></span>
Budgets</a></li>
</ul>
The routes are configured as
app.config(function ($routeProvider) {
$routeProvider
.when('/summary', {templateUrl: '../static/partials/summary.html', controller: 'SummaryController'})
.when('/transactions', { templateUrl: '../static/partials/listTransaction.html', controller: 'TransactionsManagerController'})
.when('/profile', {templateUrl: '../static/partials/profile.html', controller: 'ProfileController'})
.when('/new', {templateUrl: '../static/partials/addTransaction.html', controller: 'TransactionAddController'})
.when('/budgets', {templateUrl: '../static/partials/budgets.html'})
.otherwise({redirectTo: '/summary'});
});
When I click on Transactions, it takes me to Summary
When I change the code from <a> to <button>, it works, what is that I am doing wrong here?
http://docs.angularjs.org/api/ng.directive:a
Modifies the default behavior of the html A tag so that the default
action is prevented when the href attribute is empty.
Try setting href="" instead of href="#". If you are using hashbang mode routing, the latter results in a full-page reload, which is what seems to be happening in your case as well. Any link with href="#" that you click will cause your app to fully reload the page and load the default route -- in your case Summary.
You can get rid of gotoUrl function and modify DOM to
<span></span>Transactions
AngularJS will take care of the rest.
change this code segment
<li><a href="#
" data-ng-click="setRoute('transactions')"><span
class="icon-reorder"></span>
Transactions</a></li>
to
<li><a href="/transactions"><span
class="icon-reorder"></span>
Transactions</a></li>

Categories

Resources