Skip to content

Instantly share code, notes, and snippets.

@hilios
Last active September 8, 2024 22:39
Show Gist options
  • Save hilios/34e0b9f968a4c688fc3d to your computer and use it in GitHub Desktop.
Save hilios/34e0b9f968a4c688fc3d to your computer and use it in GitHub Desktop.
ngPageTitle - AngularJS page title service

$pageTitle

Allows to control the page title from the AngularJS route system, controllers or any other component through an injectable service.

ngPageTitle - Page title service (run tests)

To get started add the module to your app and configure the page title provider:

angular.module('app', ['ngPageTitle'])
.config(function($pageTitleProvider) {
  // Use the current doc title
  $pageTitleProvider.setDefaultTitle();
  // Set a custom default title
  $pageTitleProvider.setDefaultTitle('My App');
});

Then setup the $pageTitle property along your routes:

$routeProvider.when('path/to', {
  // ...
  pageTitle: 'Route title'
});

The document title will automatically update every time the route changes with success.

It's also possible to change the routes within any component that supports injection through the $pageTitle service, with the set method:

function MyAppCtrl($pageTitle) {
  $pageTitle.set('Controller title');
}

ngPageTitleI18n - Page title service with internationalization support (run tests)

The iternationalization support is provided by the ng-i18next, and all titles will be parsed through the plugin before been set to the document, read the i18next documentation to understand all supported features.

To get started add the module to your app and configure the page title provider:

angular.module('app', ['ngPageTitleI18n'])
.config(function($pageTitleProvider) {
  // Use the current doc title
  $pageTitleProvider.setDefaultTitle();
  // Set a custom default title
  $pageTitleProvider.setDefaultTitle('default.title');
});

Then setup the $pageTitle property along your routes:

$routeProvider.when('path/to', {
  // ...
  pageTitle: 'path.title'
});

The document title will automatically update every time the route changes with success.

It's also possible to change the routes within any component that supports injection through the $pageTitle service, with the set/update method:

function MyAppCtrl($pageTitle) {
  $pageTitle.set('path.title');
}

The $pageTitle must be a valid i18next string to allow correct localization, as the following JSON:

{
  "path": {
    "title": "My path title",
    "variableTitle": "__varName__ path title"
  }
}

There's also the possibility to interpolate variables through the service, we can set the value of varName giving set an variables object as the second parameter.

function MyAppCtrl($pageTitle) {
  $pageTitle.set('path.variableTitle', {varName: 'Variable'});
  // => Variable path title
}

Or just update the current title, if already been set within the route. This is specially usefull when you have to resolve a promise before set the title. Notice that for the update method only the variables object is required.

$routeProvider.when('path/to', {
 // ...
 pageTitle: 'path.title',
 resolve: {
   data: function($http, $pageTitle) {
      // Updates the page title after promise resolved
      return $http.get('/content/1.json')
        .success(function(data) {
          $pageTitle.update({varName: data.title});
        });
   }
 }
});

The route will be update only when the route is changed with success, so we won't show non replaced title.

/**
* $pageTitle
* ==========
*
* Allows to control the page title from the AngularJS route system, controllers
* or any other component through an injectable service.
*
* ### ngPageTitle - Page title service
*
* To get started add the module to your app and configure the page title
* provider:
*
* ```js
* angular.module('app', ['ngPageTitle'])
* .config(function($pageTitleProvider) {
* // Use the current doc title
* $pageTitleProvider.setDefaultTitle();
* // Set a custom default title
* $pageTitleProvider.setDefaultTitle('My App');
* });
* ```
*
* Then setup the `$pageTitle` property along your routes:
*
* ```js
* $routeProvider.when('path/to', {
* // ...
* pageTitle: 'Route title'
* });
* ```
*
* The document title will automatically update every time the route changes
* with success.
*
* It's also possible to change the routes within any component that supports
* injection through the `$pageTitle` service, with the `set` method:
*
* ```js
* function MyAppCtrl($pageTitle) {
* $pageTitle.set('Controller title');
* }
* ```
*/
angular.module('ngPageTitle', ['ngRoute'])
.provider('$pageTitle', function() {
var defaultTitle;
this.setDefault = function(value) {
defaultTitle = value;
};
/**
* @name $pageTitle
* @requires $rootScope
* @requires $window
*
* @description
* The `$pageTitle` service factory.
*
* ### Methods:
* - $pageTitle.get()
* - $pageTitle.set(value)
*/
function PageTitleService($rootScope, $window) {
var _currentTitle;
/**
* Returns the current document title.
* @return {string}
*/
function _get() {
return $window.document.title;
}
/**
* Sets the document title.
* @param {String} title - The title.
*/
function _set(value) {
_currentTitle = value || defaultTitle;
$window.document.title = _currentTitle;
}
// Set up the default title to the document, if none provide use the current
// document title as the default title.
if (defaultTitle) {
$window.document.title = defaultTitle;
} else {
defaultTitle = $window.document.title;
}
// Bind to angular route system.
$rootScope.$on('$routeChangeSuccess', function(event, route) {
var _pageTitle;
if (route && angular.isDefined(route.$$route)) {
_pageTitle = route.$$route.pageTitle || null;
}
_set(_pageTitle);
});
return {
get: _get,
set: _set
}
}
this.$get = ['$rootScope', '$window', PageTitleService];
});
/**
* $pageTitle
* ==========
*
* Allows to control and localize the page title from the AngularJS route
* system, controllers or any other component through an injectable service.
*
* ### ngPageTitleI18n - Page title service with internationalization support
*
* The iternationalization support is provided by the
* [ng-i18next](https://github.com/archer96/ng-i18next), and all titles will be
* parsed through the plugin before been set to the document, read the
* [i18next documentation](http://i18next.com/pages/doc_features.html) to
* understand all supported features.
*
* To get started add the module to your app and configure the page title
* provider:
*
* ```js
* angular.module('app', ['ngPageTitleI18n'])
* .config(function($pageTitleProvider) {
* // Use the current doc title
* $pageTitleProvider.setDefaultTitle();
* // Set a custom default title
* $pageTitleProvider.setDefaultTitle('default.title');
* });
* ```
*
* Then setup the `$pageTitle` property along your routes:
*
* ```js
* $routeProvider.when('path/to', {
* // ...
* pageTitle: 'path.title'
* });
* ```
*
* The document title will automatically update every time the route changes
* with success.
*
* It's also possible to change the routes within any component that supports
* injection through the `$pageTitle` service, with the `set`/`update` method:
*
* ```js
* function MyAppCtrl($pageTitle) {
* $pageTitle.set('path.title');
* }
* ```
*
* The `$pageTitle` must be a valid i18next string to allow correct localization,
* as the following JSON:
*
* ```json
* {
* "path": {
* "title": "My path title",
* "variableTitle": "__varName__ path title"
* }
* }
* ```
*
* There's also the possibility to interpolate variables through the service,
* we can set the value of `varName` giving `set` an variables object as the
* second parameter.
*
* ```js
* function MyAppCtrl($pageTitle) {
* $pageTitle.set('path.variableTitle', {varName: 'Variable'});
* // => Variable path title
* }
* ```
*
* Or just `update` the current title, if already been set within the route.
* This is specially usefull when you have to resolve a promise before set the
* title.
* Notice that for the `update` method only the variables object is required.
*
* ```js
* $routeProvider.when('path/to', {
* // ...
* pageTitle: 'path.title',
* resolve: {
* data: function($http, $pageTitle) {
* // Updates the page title after promise resolved
* return $http.get('/content/1.json')
* .success(function(data) {
* $pageTitle.update({varName: data.title});
* });
* }
* }
* });
* ```
*
* The route will be update only when the route is changed with success, so we
* won't show non replaced title.
*/
angular.module('ngPageTitleI18n', ['ngRoute', 'jm.i18next'])
.provider('$pageTitle', function() {
var defaultTitle;
/**
* Sets the default title value, if none given it will use the document title
* as the default, it must be called uppon config to allow the bindinds to the
* route system.
* @param {String} [value] - The default title value.
*/
this.setDefault = function(value) {
defaultTitle = value;
};
/**
* @name $pageTitle
* @requires $rootScope
* @requires $window
* @requires $i18next
*
* @description
* The `$pageTitle` with i18n support service factory.
*
* ### Methods:
* - $pageTitle.get()
* - $pageTitle.set(value, variables)
* - $pageTitle.update(variables)
*/
function PageTitleI18nFactory($rootScope, $window, $i18next) {
var _currentTitle,
_currentVariables = {};
/**
* Returns the current document title.
* @return {string}
*/
function _get() {
return $window.document.title;
}
/**
* Sets the document title, replacing the variable if has any.
* @param {String} title - The i18n key.
* @param {Object} [variables] - The variables object.
*/
function _set(value, variables) {
_currentTitle = value || defaultTitle;
_update(variables || _currentVariables);
}
/**
* Interpolates new set of variables in the current page title.
* @param {Object} variables - The variables object.
*/
function _update(variables) {
_currentVariables = variables || {};
$window.document.title = $i18next(_currentTitle, _currentVariables);
}
// Set up the default title to the document, if none provide use the current
// document title as the default title.
if (defaultTitle) {
_set(defaultTitle);
} else {
defaultTitle = $window.document.title;
}
// Bind to angular route system.
$rootScope.$on('$routeChangeSuccess', function(event, route) {
var _pageTitle;
if (route && angular.isDefined(route.$$route)) {
_pageTitle = route.$$route.pageTitle || null;
}
_set(_pageTitle);
});
return {
get: _get,
set: _set,
update: _update
}
}
this.$get = ['$rootScope', '$window', '$i18next', PageTitleI18nFactory];
});
describe('ngPageTitleI18n', function() {
var DEFAULT_TITLE = 'Foo Bar',
$window, provider, $pageTitle;
beforeEach(module('ngPageTitleI18n'));
beforeEach(function() {
angular.module('testPageTitleMdl', ['ngRoute', 'ngPageTitleI18n'])
.config(function($routeProvider, $i18nextProvider, $pageTitleProvider) {
$i18nextProvider.options = {
resStore: {
'dev': {
'translation': {
'title': {
'default': DEFAULT_TITLE,
'route': 'Custom route title',
'variable': '__varName__ title'
}
}
}
}
};
provider = $pageTitleProvider;
$pageTitleProvider.setDefault('title.default');
$routeProvider
.when('/test/default/title', {})
.when('/test/custom/title', {
pageTitle: 'title.route'
})
.when('/test/promise/title', {
pageTitle: 'title.variable',
resolve: {
data: function($q, $pageTitle) {
var deferred = $q.defer();
deferred.resolve('Variable');
return deferred.promise.then(function(data) {
$pageTitle.update({varName: data});
});
}
}
});
});
// Load the test module.
module('testPageTitleMdl');
});
beforeEach(inject(function(_$window_, _$pageTitle_) {
$window = _$window_;
$pageTitle = _$pageTitle_;
}));
describe('$pageTitleProvider', function() {
it('should be defined', function() {
expect(provider).toBeDefined();
});
describe('#setDefault(value)', function() {
it('should be defined', function() {
expect(provider.setDefault).toBeDefined();
expect(typeof provider.setDefault).toBe('function');
});
});
});
describe('$pageTitle', function() {
it('should be defined', function() {
expect($pageTitle).toBeDefined();
});
it('should set the default title to the document', function() {
expect($window.document.title).toBe(DEFAULT_TITLE);
});
describe('#get()', function() {
it('should be defined', function() {
expect($pageTitle.get).toBeDefined();
expect(typeof $pageTitle.get).toBe('function');
});
it('should return the current document title', function() {
expect($pageTitle.get()).toBe($window.document.title);
});
});
describe('#set(value, variables)', function() {
it('should be defined', function() {
expect($pageTitle.set).toBeDefined();
expect(typeof $pageTitle.set).toBe('function');
});
it('should set the document title', function() {
$pageTitle.set('Test');
expect($pageTitle.get()).toBe('Test');
});
it('should replace variables', function() {
$pageTitle.set('__myVar__', {myVar: 'Test'});
expect($pageTitle.get()).toBe('Test');
});
});
describe('#update(variables)', function() {
it('should be defined', function() {
expect($pageTitle.update).toBeDefined();
expect(typeof $pageTitle.update).toBe('function');
});
});
describe('on $routeChangeSuccess event', function() {
var navigateTo;
beforeEach(inject(function($location, $route, $rootScope) {
navigateTo = function(path) {
$location.path(path);
$route.reload();
$rootScope.$apply();
}
}));
it('should change the page title according to route config', function() {
navigateTo('/test/custom/title');
expect($pageTitle.get()).toBe('Custom route title');
});
it('should use the default if no page title is defined on route', function() {
navigateTo('/test/default/title');
expect($pageTitle.get()).toBe(DEFAULT_TITLE);
});
it('should change page title after resolving variables', function() {
navigateTo('/test/promise/title');
expect($pageTitle.get()).toBe('Variable title');
});
});
});
});
describe('ngPageTitle', function() {
var DEFAULT_TITLE = 'Foo Bar',
$window, provider, $pageTitle;
beforeEach(module('ngPageTitle'));
beforeEach(function() {
angular.module('testPageTitleMdl', ['ngRoute', 'ngPageTitle'])
.config(function($routeProvider, $pageTitleProvider) {
provider = $pageTitleProvider;
$pageTitleProvider.setDefault(DEFAULT_TITLE);
$routeProvider
.when('/test/default/title', {})
.when('/test/custom/title', {
pageTitle: 'Custom route title'
});
});
// Load the test module.
module('testPageTitleMdl');
});
beforeEach(inject(function(_$window_, _$pageTitle_) {
$window = _$window_;
$pageTitle = _$pageTitle_;
}));
describe('$pageTitleProvider', function() {
it('should be defined', function() {
expect(provider).toBeDefined();
});
describe('#setDefault(value)', function() {
it('should be defined', function() {
expect(provider.setDefault).toBeDefined();
expect(typeof provider.setDefault).toBe('function');
});
});
});
describe('$pageTitle', function() {
it('should be defined', function() {
expect($pageTitle).toBeDefined();
});
it('should set the default title to the document', function() {
expect($window.document.title).toBe(DEFAULT_TITLE);
});
describe('#get()', function() {
it('should be defined', function() {
expect($pageTitle.get).toBeDefined();
expect(typeof $pageTitle.get).toBe('function');
});
it('should return the current document title', function() {
console.log($window.document.title)
expect($pageTitle.get()).toBe($window.document.title);
});
});
describe('#set(value)', function() {
it('should be defined', function() {
expect($pageTitle.set).toBeDefined();
expect(typeof $pageTitle.set).toBe('function');
});
it('should set the document title', function() {
$pageTitle.set('Test');
expect($pageTitle.get()).toBe('Test');
});
});
describe('on $routeChangeSuccess event', function() {
var navigateTo;
beforeEach(inject(function($location, $route, $rootScope) {
navigateTo = function(path) {
$location.path(path);
$route.reload();
$rootScope.$apply();
}
}));
it('should change the page title according to route config', function() {
navigateTo('/test/custom/title');
expect($pageTitle.get()).toBe('Custom route title');
});
it('should use the default if no page title is defined on route', function() {
navigateTo('/test/default/title');
expect($pageTitle.get()).toBe(DEFAULT_TITLE);
});
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment