How I spend a parameter title of the post, to display the browser's title?
I use pageTitle parameter on my route, but if put directly: slug as a value, not works.
.state('posts',{
url : '/blog/:slug',
templateUrl : 'content/templates/single.html',
controller : 'SinglePostController',
data: {
pageTitle: 'title'
},
access: {
requiredLogin: false
}
})
The data : {} setting is static.
see similar:
Accessing parameters in custom data
If you want some dynamic feature use resolve : {}
Some links to examples and Q & A about resolve
Angularjs ui-router abstract state with resolve
EXTEND: A simple (really naive but working) example how to use resolve and $rootScope to manage browser title (check it here):
$stateProvider
.state('home', {
url: "/home",
templateUrl: 'tpl.html',
resolve: {
'title': ['$rootScope', function($rootScope){
$rootScope.title = "Other title";
}],
}
})
.state('parent', {
url: "/parent",
templateUrl: 'tpl.html',
resolve: {
'title': ['$rootScope', function($rootScope){
$rootScope.title = "Title from Parent";
}],
}
})
.state('parent.child', {
url: "/child",
templateUrl: 'tpl.html',
controller: 'ChildCtrl',
resolve: {
'titleFromChild': ['$rootScope', function($rootScope){
$rootScope.title = "Title from Child";
}],
}
})
And this could be the html
<!DOCTYPE html>
<html ng-app="MyApp" ng-strict-di>
<head>
<title>{{title}}</title>
Try it here
A challenge here is - what to do on navigation from child to parent, but it could be done by moving that setting into controller and work with $scope.$on('detsroy'...
Here is adjusted plunker
.state('parent.child', {
url: "/child",
templateUrl: 'tpl.html',
controller: 'ChildCtrl',
// no resolve, just controller fills the target
})
.controller('ChildCtrl', ['$rootScope', '$scope', function ($rootScope, $scope) {
var title = $rootScope.title;
$rootScope.title = "Title from Child";
$scope.$on('$destroy', function(){$rootScope.title = title});
}])
Related
I am using AngularUI Router to navigate content on my website. I have some webpages that show the header/footer navigation and some that do not. I want to be able to detect what my current page is and insert the HTML for the header/footer if needed.
Here is my current router
angular.module('app', ['ui.router'])
.config(['$urlRouterProvider', '$stateProvider',
function($urlRouterProvider, $stateProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home', {
url: '/',
templateUrl: 'partials/home.html',
controller: 'homeCtrl'
})
.state('about', {
url: '/about',
templateUrl: 'partials/about.html',
controller: 'aboutCtrl'
})
.state('contact', {
url: '/contact',
templateUrl: 'partials/contact.html',
controller: 'contactCtrl'
})
.state('create', {
url: '/create',
templateUrl: 'partials/create.html',
controller: 'createCtrl'
})
.state('login', {
url: '/login',
templateUrl: 'partials/login.html',
controller: 'loginCtrl'
})
}]);
For the html I have this
<html ng-app="app">
<body>
<!-- *********** HEADER ************* -->
<div ng-include=""></div>
<!-- ********** CONTENT *********** -->
<div ui-view></div>
<!-- **************** FOOTER ****************** -->
<div ng-include="'partials/standard_footer.html'"></div>
</body
</html>
For the webpages create and login I do not want to show the header and footer, but I am not sure how to do that.
I want to do something like this,
<div ng-if="!login && !create" ng-include="'standard_header.html'"></div>
How can I achieve this?
You can expose $state on the $rootScope and that will make it accessible in your webpage.
You can then simply check for state.current.name != 'login'
Like below:
Exposing the current state name with ui router
Edit:
Working Plunker of what i meant: https://plnkr.co/edit/JDpCo3fTePobuX9Qoxjn
You're almost there. Just add a flag in the params of the appropriate states:
.state('create', {
url: '/create',
templateUrl: 'partials/create.html',
controller: 'createCtrl',
params: {
hideHeaderAndFooter: true
}
})
.state('login', {
url: '/login',
templateUrl: 'partials/login.html',
controller: 'loginCtrl',
params: {
hideHeaderAndFooter: true
}
})
And then inject the $stateParams service in your controllers. Every property of the params object will be exposed as a property of the object this service returns:
loginCtrl.$inject = ['$scope', '$stateParams']
function loginCtrl($scope, $stateParams) {
$scope.hideHeaderAndFooter = $stateParams.hideHeaderAndFooter
}
Then you can use ng-if just the way you meant to use it:
<div ng-if="!hideHeaderAndFooter" ng-include="'standard_header.html'"></div>
I am using angular packet template. Here 11 pages loaded and 11 different buttons like the following:
Here is the route code:
state('app.pagelayouts.fixedsidebar1', {
url: "/fixed-sidebar",
templateUrl: "assets/views/page-1.html",
resolve: loadSequence('d3', 'ui.knob', 'countTo', 'dashboardCtrl'),
title: 'Fixed Sidebar',
ncyBreadcrumb: {
label: 'Fixed Sidebar'
},
controller: function ($scope) {
$scope.setLayout();
$scope.app.layout.isSidebarFixed = true;
$scope.$on('$routeChangeSuccess',function(){
$scope.templateUrl = $route.current.templateUrl;
})
}
})
.state('app.pagelayouts.fixedsidebar2', {
url: "/fixed-sidebar",
templateUrl: "assets/views/page-2.html",
resolve: loadSequence('d3', 'ui.knob', 'countTo', 'dashboardCtrl'),
title: 'Fixed Sidebar',
ncyBreadcrumb: {
label: 'Fixed Sidebar'
},
controller: function($scope) {
$scope.setLayout();
$scope.app.layout.isSidebarFixed = true;
}
}).
page-3.html, page-4.html and so on....
Suppose I am in page-1.html, when I refresh it doesn't stay in page-1. Goes to another page. But it should be stay at page-1.html. The templateUrl is changing.
How can i fix it ?
One obvious problem is that you have same url for all the routes.
You should update it with a parameter indicating the template to load, so that when page is refreshed, UI Router knows which state to activate based on the url. For example:
state('app.pagelayouts.fixedsidebar1', {
url: "/fixed-sidebar/1",
templateUrl: "assets/views/page-1.html",
resolve: loadSequence('d3', 'ui.knob', 'countTo', 'dashboardCtrl'),
title: 'Fixed Sidebar',
ncyBreadcrumb: {
label: 'Fixed Sidebar'
},
controller: function($scope) {
$scope.setLayout();
$scope.app.layout.isSidebarFixed = true;
}
});
If all your routes are similar, you can create a single route with a param like:
state('app.pagelayouts.fixedsidebar', {
url: "/fixed-sidebar/:id",
templateUrl: function($stateParams) {
return "assets/views/page-" + $stateParams.id + ".html";
},
resolve: loadSequence('d3', 'ui.knob', 'countTo', 'dashboardCtrl'),
title: 'Fixed Sidebar',
ncyBreadcrumb: {
label: 'Fixed Sidebar'
},
controller: function($scope) {
$scope.setLayout();
$scope.app.layout.isSidebarFixed = true;
}
});
I have 3 type of user: Trainer, sportsmen, fan.
Each 1 do login on same page. But after login i want to show diffrent dashboard depends on user role
Rignt now I try do domething like
.state('trainerDashboard', {
templateUrl: '/App/ControlPanel/views/templates/trainerDashboard.html',
abstract: true,
})
state('login', {
url: '/login',
templateUrl: '/App/ControlPanel/views/dashboard/dashboard.html',
parent: 'trainerDashboard',
controller: 'DashboardCtrl',
controllerAs: 'vm',
data: {
pageTitle: 'Login_Title',
login: true,
defaultState: 'users'
},
resolve: stateResolve
})
but i dont know how to set different parent here
Any Idea ??
Thank you
In your controller what you can define nested states like this
.state('dashboard', {
templateUrl: "/App/ControlPanel/views/templates/dashboard.html"
controller: ** controllerName ** //your controller name
})
.state('dashboard.trainer', {
url: "/trainer",
templateUrl: "/App/ControlPanel/views/templates/trainer.html"
}
.state('dashboard.sportsman', {
url: "/sportsman",
templateUrl: "/App/ControlPanel/views/templates/sportsman.html"
}
.state('dashboard.fan', {
url: "/fan",
templateUrl: "/App/ControlPanel/views/templates/fan.html"
}
And in your controller file you can use $state.go() function provided by Angular UI router to redirect the user to a state on the basis of the user type for example:
if(userType == 'trainer'){
$state.go(dashboard.trainer)
}
else if(userType == 'sportsman'){
$state.go(dashboard.sportsman)
}
else if(userType == 'fan'){
$state.go(dashboard.fan)
}
And in your dashboard.html file you will have to bind a div with ui-view like this
<div ui-view></div>
Hope it helps
Cheers
I have the following config and controllers
.config(function($routeProvider){
$routeProvider
.when('/', {
templateUrl: 'page-home.html',
controller: 'homeController',
controllerAs: 'hctrl'
})
.when('/about', {
templateUrl: 'page-about.html',
controller: 'aboutController',
controllerAs: 'actrl'
})
.when('/contact', {
templateUrl: 'page-contact.html',
controller: 'contactController',
controllerAs: 'cctrl'
});
})
.controller('homeController', function(){
this.pageClass = 'page-home'
})
.controller('aboutController', function(){
this.pageClass = 'page-about'
})
.controller('contactController', function(){
this.pageClass = 'page-contact'
});
My problem comes when I use in in the index.html.
<div class="page {{pageClass}}" ng-view></div>
Since I'm not using $scope, just writing {{pageClass}} won't work. How can I get around this using the controller as syntax?
Edit
I got a couple of good answers. I also discovered an alternate way to do this if you want to name your controllerAs values with different names: hctrl, actor and ctrl (like my code above):
You could do this in the html:
<div class="page {{hctrl.pageClass || actrl.pageClass || cctrl.pageClass}}" ng-view></div>
A good approach towards this problem is by setting the pageClass as a configuration in the routes definition and then create a directive that gets these definitions to be applied as whatever you want them to be (of course within the scope where the directive is applied to).
DEMO
Javascript
Define your route configuration with data key-value object.
.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'page-home.html',
controller: 'homeController',
controllerAs: 'hctrl',
data: {
pageClass: 'page-home'
}
})
.when('/about', {
templateUrl: 'page-about.html',
controller: 'aboutController',
controllerAs: 'actrl',
data: {
pageClass: 'page-about'
}
})
.when('/contact', {
templateUrl: 'page-contact.html',
controller: 'contactController',
controllerAs: 'cctrl',
data: {
pageClass: 'page-contact'
}
});
})
Create a directive that sets these data with the directive's controller.
.directive('routeData', function() {
return {
controller: 'RouteDataController',
controllerAs: 'RouteData',
bindToController: true
}
})
.controller('RouteDataController', function($rootScope, $route) {
var self = this;
$rootScope.$on('$routeChangeSuccess', setCurrentRouteData);
setCurrentRouteData();
function setCurrentRouteData() {
angular.extend(self, $route.current.$$route.data || {});
}
})
In your index.html apply the directive itself and access the directive's controller to get the data values.
<div ng-view route-data class="page {{ RouteData.pageClass }}"></div>
Specify the controller as name
<div class="page {{hctrl.pageClass}}" ng-view></div>
Whatever you wrote in the controllerAs value need to be prepended to the variable, like {{actrl.pageClass}}
I have an MVC application using angularJS. I have a primary navigation and secondary navigation. I am using ngRoute for primary navigation. I made secondary navigation template a directive that I can use in all the other pages. The template used in the directive needs some input parameters.
Routing code:
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/SecondaryNavigation/1', {
templateUrl: 'administration/Page1',
resolve: {
SecNavItems: ["$http", function($http){
var navItems = $http.get('/Navigation/SecondaryNavigation', {params: { pageName: 'Administration'}});
navItems.success(function (data) {
return data;
});
}]
},
controller: 'AdminController'
})}]);
var AdminController = function ($scope, SecNavItems) {
$scope.secList = SecNavItems;
}
AdminController.$inject = ["$scope", "SecNavItems"];
myApp.controller("AdminController", AdminController);
Web method code:
[HttpGet]
public JsonResult SecondaryNavigation(string pageName)
{
Dictionary<string, string> secnavItems = new Dictionary<string, string>();
secnavItems.Add("1", "Item1");
secnavItems.Add("2", "Item2");
var navigationItemsJson = Json(secnavItems, JsonRequestBehavior.AllowGet);
return navigationItemsJson;
}
Page1 code is
<secondary-navigation></secondary-navigation>
My directive is defined as follows:
myApp.directive("secondaryNavigation", function () {
return {
restrict: 'E',
scope: {},
templateUrl: '/navigation/secondaryNavigation'
}
});
Partial view template:
<div style="height:100%; width:25%; background-color:#675c5c; color: white; float:left">
#foreach (KeyValuePair<int, string> navItem in secList)
{
#navItem.Value<br /><br />
}
</div>
<div style="height:100%; width:75%; float:right"></div>
When I run the application I do not see the Item1 and Item2 in the page instead I see {{object}}
Please advise what I am missing in passing the parameters to the template used in the directive.
Thank you.
Figured what went wrong.
I had to create a html template of secondary navigation. I then included the web service call in the admincontroller, set the object value to the webservice result and added it to the routeProvider. I then
set the scope to false in the directive.
Following are the changes I made.
Routing code:
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/SecondaryNavigation/1', {
templateUrl: 'administration/Page1',
controller: 'AdminController'
})}]);
var AdminController = function ($scope, $http) {
var navItems = $http.get('/Navigation/SecondaryNavigation', {params: { pageName: 'Administration'}});
navItems.success(function (data) {
$scope.secList = data;
});
}]
},
}
AdminController.$inject = ["$scope", "$http"];
myApp.controller("AdminController", AdminController);
My directive is defined as follows:
myApp.directive("secondaryNavigation", function () {
return {
restrict: 'E',
scope: false,
templateUrl: '/navigation/secondaryNavigation'
}
});