I am new to Angular. I have a directive that displays the navigation:
(function(){
angular
.module('instaguideApp')
.directive('navigation', navigation);
function navigation(authenticationData){
return {
restrict: 'EA',
templateUrl: '/common/directives/navigation/navigation.template.html',
scope: false,
link: function(scope, elem, attr) {
scope.data = {
isLoggedIn: authenticationData.isLoggedIn
};
}
};
}
})()
navigation.template.html is:
<div class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">InstaGuide
<button type="button" data-toggle="collapse" data-target="#navbar-main" class="navbar-toggle"><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button>
</div>
<div id="navbar-main" class="navbar-collapse collapse">
<ul ng-switch="{{data.isLoggedIn}}" class="nav navbar-nav">
<li>About</li>
<li ng-switch-default>
Login
</li>
<li ng-switch-when="true">>
Logout
</li>
<li>Debugging Value: {{data.isLoggedIn}}</li>
</ul>
</div>
</div>
</div>
I have a service which stores the login state of the user:
(function(){
angular
.module('instaguideApp')
.service('authenticationData', authenticationData);
function authenticationData(){
var auth = {
isLoggedIn: false
};
return auth;
}
})();
Once I successfully log in, i set "isLoggedIn" of authenticationData to true. When this happens I want to show Logout in the navigation rather than Login. You can see I am using ng-switch in an attempt to achieve this.
When I login, the template receives that I have logged in because I can see that "Debugging Value: false" changes to "Debugging Value: true".
However, Login and Register still appear in the menu, as if ng-switch has not registered that it's value has changed. Any idea how to achieve this?
Try removing the parentheses in the ng-switch value:
<ul ng-switch="data.isLoggedIn" class="nav navbar-nav">
ng-switch is expecting angular expression as its value. So there is no need to wrap the value into double parentheses.
Related
I have two controllers headerController, aboutController.
headerController -> To maintain the navigation and redirection
aboutController -> works when about-us page loads.
My issue is I have to update the headerController variable value when aboutController loads. i.e When about us page loads, the navigation about-us should active, similar to all the pages.
This is my code:
app.service('shareService', function () {
var data;
return {
getProperty: function () {
return data;
},
setProperty: function (value) {
data = value;
}
};
});
app.controller('headerController', function ($scope, shareService) {
$scope.navigation = [
{url: '#!/home', name: 'Home'},
{url: '#!/about-us', name: 'About Us'},
{url: '#!/services', name: 'Services'}
];
var data = shareService.getProperty();
console.log(data);
$scope.selectedIndex = 0;
$scope.itemClicked = function ($index) {
console.log($index);
$scope.selectedIndex = $index;
};
});
app.controller('aboutController', function ($scope, shareService) {
console.log('test');
$scope.selectedIndex = 1;
shareService.setProperty({navigation: $scope.selectedIndex});
});
header.html:
<header ng-controller="headerController">
<div class="header">
<div class="first-half col-md-6">
<div class="row">
<div class="logo">
<img src="assets/img/logo.png" alt=""/>
</div>
</div>
</div>
<div class="second-half col-md-6">
<div class="row">
<div class="social-share">
<ul id="social-share-header">
<li><i class="fa fa-facebook" aria-hidden="true"></i></li>
<li><i class="fa fa-twitter" aria-hidden="true"></i></li>
<li><i class="fa fa-google-plus" aria-hidden="true"></i></li>
</ul>
</div>
</div>
</div>
<nav>
<ul ng-repeat="nav in navigation">
<li class="main-nav" ng-class="{ 'active': $index == selectedIndex }"
ng-click="itemClicked($index)">
{{nav.name}}
</li>
</ul>
</nav>
</div>
</header>
index.html
This is how my template works.
<body ng-app="myApp">
<section class="first-section">
<div ng-include="'views/header.html'"></div>
</section>
<section class="second-section">
<div ng-view></div>
</section>
<section class="last-section">
<div ng-include="'views/footer.html'"></div>
</section>
</body>
Update 1: Added index.html file.
Update 2: Issue explanation: If I run directly to the about us page, then still the home navigation is on active. But it should be About us
What is you are looking for is event based communication between your controllers. This can be easily done using. $rootScope.$on, $rootScope.$emit and $rootScope.$broadcast. Since explaining all three of them in this answer will be overkill. Kindly go through this article
I'm playing around with AngularJS and trying to build a very simple app for learning purposes, but i've ran into a problem.
I'm using Kinvey BAAS. So, this is what I'm trying to do:
I have a login.controller.js, which looks like this (skipping the module registration and the config parts...):
`
.controller('LoginController', [
'$scope',
'$location',
'users',
function ($scope, $rootScope, $location, users) {
$scope.login = function login() {
users.login($scope.user)
.then(function (loggedInUser) {
$location.path('/home');
console.log(loggedInUser);
}, function (error) {
console.log(error);
});
}
}
])
The idea is simple. Use a service to log the user in. Then, redirect him to the homepage (/home).
The authentication service looks like this (users.js):
`
.factory('users', [
'$http',
'$q',
'$cookies',
'$location',
'BASE_URL',
'APP_KEY',
'APP_SECRET',
function ($http, $q, $cookies, $location, BASE_URL, APP_KEY, APP_SECRET) {
var user = undefined;
function login(user) {
var deferred = $q.defer();
// Get the user information.
$http.post(BASE_URL + 'user/' + APP_KEY + '/login', {
username: user.username,
password: user.password
})
.then(function (response) {
_preserveUserData(response.data);
deferred.resolve(response);
}, function (error) {
deferred.reject(error);
});
return deferred.promise;
}
function _preserveUserData(data) {
var authToken = data._kmd.authtoken;
$cookies.put('authToken', authToken);
user = data;
}
function isLogged() {
if !! (user || $cookies.get('authToken'));
}
function getLoggedUser() {
var deferred = $q.defer();
if (user) {
deferred.resolve(user);
} else if ($cookies.get('authToken')) {
var authToken = $cookies.get('authToken');
$http.defaults.headers.common.Authorization = 'Kinvey ' + authToken;
$http.get(BASE_URL + 'user/' + APP_KEY + '/_me')
.then(function (response) {
user = response.data;
deferred.resolve(response);
}, function (error) {
deferred.reject(error);
});
} else {
deferred.reject('No logged user.');
}
return deferred.promise;
}
return {
login: login,
isLogged: isLogged,
getLoggedUser: getLoggedUser
};
}
]);
I also have a main controller (main.controller.js). The MainController wraps the whole content with a div (), for binding to the scope some global stuff...like the currently logged user.
`
.controller('MainController', [
'APP_TITLE',
'$scope',
'users',
function (APP_TITLE, $scope, users) {
// A place to store some more-global stuff.
$scope.appTitle = APP_TITLE;
$scope.user = undefined;
if (users.isLogged()) {
users.getLoggedUser()
.then(function (loggedUser) {
$scope.user = loggedUser.data;
}, function (error) {
console.log(error);
});
}
}
])
Now, this is the index.html (where the Main controller and the ng-view are):
<body>
<div ng-controller="MainController" ng-cloak>
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#!/">{{appTitle}}</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>Home</li>
<li>Favorites</li>
<li>Users</li>
</ul>
<ul class="nav navbar-nav navbar-right" ng-if="user">
<li class="dropdown">
{{user.username}}<span class="caret"></span>
<ul class="dropdown-menu">
<li>Links</li>
<li>Edit Profile</li>
<li role="separator" class="divider"></li>
<li>Logout</li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<!--[if lt IE 7]>
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please upgrade your browser to improve your experience.</p>
<![endif]-->
<div ng-view>
</div>
</div>
And this is the home.html (where the username should be displayed):
<div class="container">
<h2>Hello, <span ng-if="user">{{user.username}}</span></h2>
</div>
The thing is that, when the user is logged, I save a cookie and redirect the logged user...but the MainController doesn't register the logged in user (it never enters the if (users.isLogged()) part). I have to refresh to see the username of the user.
Any guidance on how to solve this problem will be handy. Also code quality and overall code-improvement suggestions will be also highly appreciated.
Thanks in advance!
Borislav.
users should be a service, not a factory... a service will create a single shared instance, a factory is a new instance for each controller.
I'm trying to show and hide a div using ng-show. It's a navbar that I want to show only in some views.
I have a controller which "controls" that div. And in other controller I want to edit this ng-show value in order to hide or show the div (navbar).
I tried different things as using a $rootScope, a timeout, an $apply, a factory... but nothing works.
So I'm asking here if anyone could help me.
(Sorry for my English)
This is my html and js codes (last edit code)
<div id="main">
<!-- AquĆ inyectamos las vistas -->
<div ng-controller="appCtrl" ng-show="isLogged" class="navbar navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button>
<a class="navbar-brand" href="#/">Aula Virtual</a> </div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav" style="text-align: right">
<li class="active">Home</li>
<li>Users</li>
<li>Operaciones</li>
<li>About</li>
<li>Contact</li>
</ul>
</div>
</div>
<div class="connect">
<div class="container">
<p>
Aula Virtual para profesorado y alumnos de la universidad
</p>
</div>
</div>
</div>
<div ui-view></div>
</div>
I tried a (ng-show="isLogged==false") too.
The controller of the div:
.controller('appCtrl', function($scope, $rootScope) {
console.log($scope.isLogged); //---> this shows undefined
});
The controller where I want to edit the isLogged value:
cities2.controller('userCtrl',['rootScope', '$scope', '$state','$http','md5', function($rootScope, $scope, $state, $http, md5) {
$rootScope.$apply(function(){
$rootScope.isLogged = true;
});
Thanks for the help!
It's good practice to use services to share data between controllers.
cities2.controller('appCtrl', ['$scope', 'LoggedStatus', function($scope,LoggedStatus) {
$scope.LoggedStatus = LoggedStatus;
}]);
cities2.controller('userCtrl', ['$scope', 'LoggedStatus', function($scope,LoggedStatus) {
$scope.LoggedStatus = LoggedStatus;
}]);
cities2.service('LoggedStatus', function() {
return {
isLogged: false
}
});
Changing the value of $scope.LoggedStatus.isLogged in either controller will change the value in both.
In your appCtrl controller, do $scope.isLogged=0. If you change this value to 1, the block will be visible else it will be hidden.
app.controller('appCtrl', function($scope) {
$scope.isLogged=0;
})
Refer to the plunker below:
https://plnkr.co/edit/d3q3QwA9k5f6ewXbqZ3M?p=preview
Well, finally I found the solution. I put this if can help someone:
I put a .run in the appCtrl where I initialize the ng-show:
.run(function ($rootScope) {
$rootScope.isLogged = false;
});
and now, when I put a true value in the other controller it works, and the navbar appears.
cities2.controller('userCtrl',['$rootScope', '$scope', '$state','$http','md5','$sessionStorage', function($rootScope, $scope, $state, $http, md5, $sessionStorage) {
$rootScope.isLogged=true;
}]);
I have a menu bar defined in the "HomeController" with a login button.
My login form is a ui-bootstrap modal whose controller is "LoginController".
After successfully log in, user is directed to another state. But I also want the "Login" button to hide and show the current user's email.
I think I should use either localstorage or cookies to store the current user information. the localstorage data never expires so I think cookies is better?
So what should I do in my "LoginController" and "MainController"?
Can I use the $emit and $on?
I'm new to angular. Any suggestions would be appreciated.
.state('home', {
url: '/home',
templateUrl: 'template/partial-home.html',
controller:'mainController'
})
.state('login', {
url: '/login',
parent:'home',
onEnter:['$stateParams','$state','$modal','$resource',function($stateParams,$state, $modal, $resource){
$modal.open({
animation: true,
size:'',
templateUrl: 'login/login.html',
controller:'loginController'
}).result.then(function(){
console.log('promise resolved success');
$state.go('admin-dashboard',{});
},function(){
console.log('promise rejected fail');
}).finally(function(){
console.log('promise finally');
//$state.go('home',{});
});
}]
})
.controller('loginController',function($scope,$http,$timeout,AuthToken,$window){
$scope.badCreds = false;
$scope.cancel = function() {
$scope.$dismiss();
};
$scope.login = function() {
console.log($scope.credential);
$http.post('/authenticate',$scope.credential).then(function success(response){
console.log(response.data.token);
AuthToken.setToken(response.data.token);
$scope.currentuser = response.data.user;
$scope.alreadyLoggedIn = true;
console.log('success', 'Hey there!', 'Welcome ' + $scope.currentuser.email + '!');
$scope.$close();
},function error(response){
$scope.message='Problem logging in! Sorry!';
});
};
$scope.logout = function(){
AuthToken.clearToken();
$scope.currentuser = null;
//showAlert('info','Goodbye!','Have a great day!');
};
<body ng-controller="mainController">
<header>
<div class="nav navbar-default navbar-fixed-top" role="navigation">
<div class = "container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Westlake Pioneers</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a ui-sref="home" ui-sref-active="active"><i class="fa fa-home"></i>Home</a></li>
<li><a ui-sref="team" ui-sref-active="active"><i class="fa fa-shield"></i>Our Team</a></li>
<li><a ui-sref="blogs" ui-sref-active="active"><i class="fa fa-book"></i>Blogs</a></li>
<li><a ui-sref="projects" ui-sref-active="active"><i class="fa fa-wrench"></i>Projects</a></li>
<li><a ui-sref="contact" ui-sref-active="active"><i class="fa fa-comment"></i> Contact</a></li>
<li><a ng-hide="$rootScope.currentuser" ui-sref="login" ui-sref-active="active"><i class="fa fa-sign-in"></i></i>Login</a></li>
<li>{{currentuser.email}}</li>
</ul>
</div>
</div>
</div>
</header>
<div id="main">
<div class="page {{pageClass}}" ui-view>
</div>
</div>
To pass a parameter into a view when using ui-router do the following:
Add "params" field in your 'home' route definition with an object that will hold the user name ($stateProvider API):
.state('home', {
url: '/home',
templateUrl: 'template/partial-home.html',
controller:'mainController',
params : { userName: null }
})
When closing modal, pass the user name of logged in user back to source (add $uibModalInstance as dependency to login controller, what's $scope.$close()?):
$uibModalInstance.close(response.data.user);
Accept the username in your modal declaration:
.result.then(function (loggedInUserName)
Call $state.go and pass the username to the view:
$state.go('admin-dashboard',{userName:loggedInUserName});
Finally inject $stateParams to the controller that handles 'admin-dashboard' view and access it using $stateParams.userName
Alternatively, if you would like to make username available to the whole application, you can just store it in the $rootScope(dirty) or make an angular service (better).
Good luck!
I have the following HTML to make an accordion:
{{isExpandAllOpen}} // Present in the scope of the calling page
<li class="row" ng-repeat="test in AllTests">
<div vh-accordion-group panel-class="panel-info">
<div vh-accordion-header> </div>
<div vh-accordion-body> </div>
</div>
</li>
In vhAccordionHeader.js we have the following code:
home.directive("vhAccordionHeader", ['version', function(version) {
return {
require: '^vhAccordionGroup',
replace: true,
restrict: 'EA',
transclude: 'element',
templateUrl: "JS/HomeModule/Directives/vhAccordion/vhAccordionHeader.html?v=" + version
};
}]);
home.directive("vhAccordionAssignId", function() {
return {
require: '^vhAccordionGroup',
link: function(scope, element, attrs, vhAccordionGroupController) {
scope.isOpen = true;
}
};
});
in AccordionHeader.html
<div class="panel-heading">
<h4 class="panel-title">
<a ng-click="isOpen = !isOpen" data-toggle="collapse" onclick=" return false; " vh-accordion-assign-id>
<i class="pull-left glyphicon" ng-class="{'glyphicon-chevron-up': isOpen, 'glyphicon-chevron-down': !isOpen}" style="margin: -2px 10px 0 0"></i><span ng-transclude></span>
</a>
</h4>
the isOpen variable controls the expand/collapse all functionality.
Since I want to implement a expand/collapse all functionality, using the isExpandAllOpen to be equal to IsOpen, when expanding all button is used.
I cannot find a way to assign isExpandAllOpen to isOpen as it is a diferent directive.
TIA
As you don't specify isolated scope for your vhAccordionAssignId directive you an get access to isExpandAllOpen via scope inheritance. Simply read scope.isExpandAllOpen. Mind that scope inheritance will work for reading only.
Now you want to be notified when it got changed? Put a watcher in your link function
scope.$watch('isExpandAllOpen', function(newVal){
scope.isOpen = newVal;
//do additional stuff if required
});