What approach do you recommend to navigate pages from nav menu using angularjs?
Pages will have footer and header html using ng-include to have common templates. I found ng-view to navigate between pages.
In this example, there's a module named navList and a controller and a method navClass inside it. Using a special service in angular.js, $location which parses the URL in the browser and makes the URL available in the application. Finally, just match the URL hash with the parameter passed.
var navList = angular.module('navList', []);
navList.controller('navCtrl', ['$scope', '$location', function ($scope, $location) {
$scope.navClass = function (page) {
var currentRoute = $location.path().substring(1) || 'home';
return page === currentRoute ? 'active' : '';
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="well sidebar-nav" ng-app="navList">
<ul class="nav nav-list" ng-controller="navCtrl">
<li ng-class="navClass('home')"><a href='#/home'>Home</a></li>
<li ng-class="navClass('about')"><a href='#/about'>About Us</a></li>
<li ng-class="navClass('contact')"><a href='#/contact'>Contact Us</a></li>
</ul>
</div>
JsFiddle Link
Angular router is what you need:
https://github.com/angular-ui/ui-router/blob/master/README.md
Related
in my login controller i redirected to index page
location.href="index.html"
in index.html i used this code
<body data-ng-app="userApp" ng-controller="mainCtrl">
<div class="dropdown-menu dropdown-menu-right topDropdownMenu">
<a class="dropdown-item" href="#/dashboard/{{$root.tab.id}}">Dashboard</a>
<a class="dropdown-item" href="#/voters/{{$root.tab.id}}">Voters</a>
</div>
and this is my mainCtrl controller
services.getElectionParties().success(function(data,status){
$scope.tabs = data;
});
i tried redirecting to "#/dashboard". but i need to pass tab.id as url parameter on login by default
any help will be appreciated
simple . use same location.href in mainCtrl to redirect by default
services.getElectionParties().success(function(data,status){
$scope.tabs = data;
$scope.tab = data[0].id;
location.href = "#/dashboard/"+$scope.tab.id;
});
by these changes you will be redirected to your dashboard once your mainCtrl is loaded by default
I have simple Scala Play Framework and Angular application. I tried to render JSON data on play's "xxx.scala.html" template but don't know what is the problem it is not rendering as expeted.
#main("Welcome to Play") {
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"> </script>
<script>
app.controller('NamesCtrl', function($scope) {
// get names using AngularJS AJAX API
$http.get('/getNames').success(function(data){
$scope.names = data;
});
});
</script>
<div ng-app="app" ng-contoller="NamesCtrl">
<ul>
<li ng-repeat=" name in names">{{name}}</li>
</ul>
</div>
}
My route entry
GET /getNames controllers.HomeController.getNames
Scala Controller:
def getNames = Action {
val names = List("Bob","Mike","John")
Ok(Json.toJson(names)).as(JSON)
}
When I am calling my page using url
http://localhost:9000/getNames
I was getting response on page as below,
["Bob","Mike","John"]
Please can you explain what am I doing wrong here?
Thanks !!
There are some problems in the code. The correct one is this:
#main("Welcome to Play") {
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.19/angular.min.js"></script>
<div ng-app="myApp" ng-controller="NamesCtrl">
<ul>
<li ng-repeat="name in names">{{name}}</li>
</ul>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('NamesCtrl', function($scope, $http) {
$http.get('/getNames').success(function(data){
console.log(data);
$scope.names = data;
});
});
</script>
}
What has changed:
AngularJS 1.3.19 instead of 1.2.10
AngularJS module - which is referenced in the div
injected the $http service in the controller
your ng was wrong - it should be ng-controller instead of ng-contoller (a typo I guess)
The result is what you would expect:
how to write a service or factory for bootstrap tabs using angularJs.
I placed in one controller but need a common function(repeated code) for different controllers.
<ul class="nav nav-tabs">
<li data-ng-class="{active:tab===0}">
<a href ng-click="changeTab(0)"> <i class="fa fa-list"></i></a>
</li>
<li data-ng-class="{active:tab===1}">
<a href ng-click="changeTab(1)"><i class="fa fa-user"></i></a>
</li>
</ul>
<div data-ng-class="{activeTab:tab===0}" ng-show="isActiveTab(0)">
tab1
</div>
<div data-ng-class="{activeTab:tab===1}" ng-show="isActiveTab(1)">
tab2
</div>
controller
$scope.tab = 0;
$scope.changeTab = function(newTab){
$scope.tab = newTab;
};
$scope.isActiveTab = function(tab){
return $scope.tab === tab;
};
Managing tabs is a view concern. Rather than implementing a factory, I recommend creating two directives: tabContainer and tab. The tab directive registers itself with the parent tabContainer using the require attribute to access the parent directive's controller API.
Demo
Usage
<tab-container selected="tab2">
<tab name="tab1">tab1</tab>
<tab name="tab2">tab2</tab>
</tab-container>
Parent Directive
The parent directive publishes the following controller API that the child tab directives will access:
tabContainer controller
// registers this tab with the parent tabContainer
this.register = function(element) {
$scope.tabs.push(element);
}
// returns the selected tab object whose
// name property indicates which tab is active
this.getSelected = function() {
return $scope.selectedTab;
}
Child Directive
The tab directive is able to access the parent controller by requiring the parent directive in its directive definition, and accessing the parent directive's controller as the 4th argument to the tab directive's link function:
tab directive definition
scope: true,
require: '^tabContainer',
link: function(scope, element, attr, tabContainer) {
// set the tab so that it is visible in the tab directive's scope.
scope.tab = { name: attr.name, element:element};
scope.selectedTab = tabContainer.getSelected();
tabContainer.register(scope.tab);
}
The scope is set to true so that each tab will create its own child scope and not interfere with the scope of other tabs.
Template Files
For example purposes, the directive templates are embedded in the HTML:
<script type="text/ng-template" id="tabContainer.html">
<ul class="nav nav-tabs">
<li ng-repeat="tab in tabs" data-ng-class="{active:selectedTab.name===tab.name}">
<a href ng-click="changeTab(tab)"> <i class="fa fa-list">{{tab.name}}</i></a>
</li>
</ul>
<ng-transclude></ng-transclude>
</script>
<script type="text/ng-template" id="tab.html">
<div data-ng-class="{activeTab:selectedTab.name===tab.name}" ng-show="selectedTab.name === tab.name">
<ng-transclude></ng-transclude>
</div>
</script>
It is recommended to move these to dedicated HTML files.
Changing the Active Tab
The user is able to change the active tab by clicking the tab link. This is achieved by publishing a $scope function in the parent controller:
$scope.changeTab = function(tab) {
$scope.selectedTab.name = tab.name;
}
Creating a Tabs Module
The beauty of AngularJS and its pluggable modular architecture is that you can extend the AngularJS directive ecosystem, and have the directives work together seamlessly. For example, you could encapsulate the above tabs directive into a tabs module, and even use the ngRepeat directive to bind the tabs.
Demo
Controller
var app = angular.module('app',['tabs']);
app.controller('ctrl', function($scope) {
$scope.tabData = [
{ name: 'tab1', body: 'You selected tab1!'},
{ name: 'tab2', body: 'You selected tab2!'},
{ name: 'tab3', body: 'You selected tab3!'},
{ name: 'tab4', body: 'You selected tab4!'},
];
});
View
<div class="container" ng-controller="ctrl">
<tab-container selected="tab1">
<tab ng-repeat="tab in tabData" name="{{tab.name}}">{{ tab.body }} </tab>
</tab-container>
</div>
Hi I write it with out using any service or factory
see the example
<ul ng-init="tab = 1">
<li ng-class="{active:tab===1}">
<a href ng-click="tab = 1">Tab1</a>
</li>
<li ng-class="{active:tab===2}">
<a href ng-click="tab = 2">Tab2</a>
</li>
<li ng-class="{active:tab===3}">
<a href ng-click="tab = 3">Tab3</a>
</li>
<br><br>
<p ng-show="tab === 1"> Tab1 content </p>
<p ng-show="tab === 2"> Tab2 content</p>
<p ng-show="tab === 3"> Tab3 content</p>
</ul>
Dynamically change it through controller see the working example here
The structure for controllers/services in Angular are explained well here:
https://github.com/johnpapa/angular-styleguide
In app.js, we declare an angular application, give it a name, and any dependencies (ng-route / ng-grid). $http calls should be made using a factory or a service, and the controller should call the service to fetch or post data. From the angular documentation, "services are substitutable objects that are wired together using dependency injection (DI). You can use services to organize and share code across your app."
https://docs.angularjs.org/guide/services
app.js:
var app = angular.module('appname', []);
app.factory('httpResponseErrorInterceptor'...
app.config(['$httpProvider',...
Controller:
angular.module('appname').controller("NameCtrl", ["$scope", "$log", "$window", "$http", "$timeout", "SomeService",
function ($scope, $log, $window, $http, $timeout, TabService) {
//your controller code
$scope.tab = 0;
$scope.changeTab = function(newTab){
$scope.tab = newTab;
};
$scope.isActiveTab = function(tab){
return $scope.tab === tab;
};
}
]);
Service:
angular.module('appname').service("TabService", function () {
//Your code for shared functionality regarding tab service
var currentTab = {};
return {
currentTab : currentTab
}
});
AngularJS noob here.
I want my application to be able to respond to a url hash. By respond I mean simple stuff like set a variable value.
In this example, if the url is http:example.com/#parents-to-be, I want the app to perform the standard behaviour which is scroll to #parents-to-be, and also set $scope.tab3 = 1;
From doing some research, it seems like this can be achieved with a combination of $location.hash() and $anchorScroll(). However, I haven't been successful thus far. Can someone please help?
html:
<div ng-app="bug">
<div ng-controller="TabsController">
<a href ng-click="activateTab(1)">tab 1</a>
<a href ng-click="activateTab(2)">tab 2</a>
<a href ng-click="activateTab(3)">tab 3</a>
<div id="parents-to-be"> <!-- this is the target div -->
<div ng-show="tab1 === 1">content of tab 1</div>
<div ng-show="tab2 === 1">content of tab 2</div>
<div ng-show="tab3 === 1">content of tab 3</div>
</div>
</div> <!-- /angular tabs controller scope -->
</div> <!-- /angular app scope -->
app.js:
(function() {
var app = angular.module('bug', []);
app.controller('TabsController', function($scope, $location, $anchorScroll) {
// init tabs
$scope.initTabs = function() {
$scope.tab1 = 0;
$scope.tab2 = 0;
$scope.tab3 = 0;
};
// activate tabs
$scope.activateTab = function(tab_index) {
$scope.initTabs();
$scope['tab' + tab_index] = 1;
};
// this is the part of the app where I try to get the hash value and edit the value of tab3
$scope.hash_value = $location.hash();
if ($scope.hash_value === "parents-to-be") {
$scope.activateTab(3);
$anchorScroll();
}
});
})();
Thank you!
Use the $on event handler to capture the hash value after the $locationChangeSuccess event:
$rootScope.$on('$locationChangeSuccess', function()
{
console.log(arguments[1].replace(/[^#]+(#.+)/, "$1") );
}
)
angular.element(document).injector().get('$rootScope').$on('$locationChangeSuccess', function(){console.log(arguments[1].replace(/[^#]+(#.+)/, "$1"))})
References
feat($location): add support for History API state handling
hashchange Event Reference
In my AngularJS application, I'm using a router with an ng-view directive.
Besides it I would like to add a generic header (same for all the views). So I did the following:
<!-- index.html -->
<body ng-app="myApp">
...
<div ng-controller="TopmenuCtrl" class="header">
<div ng-include="template.url"></div>
...
</div>
<div ng-view></div>
</body>
The view is dynamic depending on the session token:
<!-- views/topmenu.html -->
<ul class="nav nav-pills pull-right">
<li class="active"><a ng-href="#">Home</a></li>
<li><a ng-href="#">About</a></li>
<li><a ng-href="#">Contact</a></li>
<li ng-show="token"><a ng-href="#" ng-click="doLogout()">Logout</a></li>
</ul>
And the topmenu controller with the logout method:
// controllers/topmenu.js
$scope.template = {url: 'views/topmenu.html'};
$scope.doLogout = function() {
localStorageService.clearAll();
$window.sessionStorage.token = '';
$location.path('/login');
};
The problem is: When I click on "logout" in the app, the topmenu controller is called and destroy the session but the main one from the router is called too and display an error because the session was destroyed!
The only (not satisfactory) solution I found to prevent this is to add this code in each controllers of the app:
if ($window.sessionStorage.token = '') {
return;
}
Is there a way to execute the header controller but not the main ng-view controller?
I finally found my answer: https://stackoverflow.com/a/11672909/900416.
Now my logout link looks like: <a href ng-click="doLogout()">Logout</a>.