Created
September 16, 2019 12:39
-
-
Save codfish/7dc25bb87b81869a8e875c3e78c79bce to your computer and use it in GitHub Desktop.
AngularJS v1 Meta Service
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// *********************************************************************************** | |
// meta-service.js | |
'use strict'; | |
/** | |
* Meta Service | |
* | |
* The Meta Service allows you to abstract a lot of business logic | |
* that goes into setting meta & link tags for your templates. | |
* Easily set page title, description, canonical, og, twitter, etc. tags. | |
* | |
* NOTE: Pre-populated definitions exist for the developers convenience, | |
* i.e. rss, stylesheet, favicon, etc. This allows the developer to | |
* only provide the dynamic aspects of the tag, like `href`, without | |
* needing to manually set a `type` for example. | |
* | |
* Instead of: | |
* MetaService.set([{rel: 'alternate', type: "application/rss+xml", title: 'Site RSS', href: 'http://feeds.feedburner.com/sitename/blog'}]); | |
* | |
* you can just do: | |
* MetaService.set([{ | |
* definition: 'rss', href: 'http://feeds.feedburner.com/sitename/blog' | |
* }]); | |
* | |
* EXAMPLE: | |
* | |
* # in your js controller, etc. | |
* MetaService.set([ | |
* {title: title}, | |
* {name: 'description', content: description.toString()}, | |
* {'http-equiv': 'Content-Type', content: 'text/html; charset=utf-8'}, | |
* {definition: 'rss', href: 'http://feeds.feedburner.com/sitename/blog'}, | |
* {definition: 'favicon', href: '/alternate-favicon.png'}, | |
* {rel: 'stylesheet', href: '/css/hello.css'} | |
* ]); | |
* | |
* @ngInject | |
*/ | |
function MetaService($rootScope, $window) { | |
var MetaService = {}, | |
dictionary = {}, // default values for known meta & link tags | |
page = {}, // local store for current page values (title, etc) | |
links = [], // local store for current link tags (canonical, etc) | |
metas = []; // local store for current meta tags (description, etc) | |
// initialize an empty objects on the root scope | |
$rootScope.page = {}; | |
$rootScope.metas = []; | |
$rootScope.links = []; | |
// put defaults here so users don't need to. | |
// Values will get extended later | |
dictionary = { | |
stylesheet: { | |
rel: 'stylesheet', | |
type: 'text/css', | |
media: 'all' | |
}, | |
favicon: { | |
rel: 'shortcut icon', | |
type: 'image/x-icon' | |
}, | |
rss: { | |
rel: 'alternate', | |
type: 'application/rss+xml', | |
title: 'RSS' | |
} | |
}; | |
/** | |
* Set's any & all provided meta/link/page values | |
* | |
* @param {array} tags array of objects containing meta/link/page tag info | |
* @return {void} | |
*/ | |
MetaService.set = function(tags) { | |
var _this = this; | |
if ($window.Object.keys(tags).length === 0) { | |
return; | |
} | |
angular.forEach(tags, function(tag, key) { | |
var definition = {}, | |
pos = null, | |
nameAttr = null, | |
contentAttr = null, | |
linkTag = (tag.rel && tag.href) ? true : false; | |
// handle any unique and special tags | |
if ($window.Object.keys(tag).length === 1 && tag.title) { | |
_this.title = tag.title; | |
return; | |
} | |
if ($window.Object.keys(tag).length === 1 && tag.canonical) { | |
_this.canonical = tag.canonical; | |
return; | |
} | |
// check if there's a known tag definition you can extend | |
if (definition = dictionary[tag.definition || tag[nameAttr]]) { | |
tag = angular.extend(definition, tag); | |
} | |
// figure out proper attributes for the tag | |
// meta tags can have either 'name', 'http-equiv' or | |
// 'property' as their "name" attribute | |
metaName = tag['http-equiv'] ? 'http-equiv' : (tag.property ? 'property' : 'name'); | |
nameAttr = tag.rel ? 'rel' : metaName; | |
contentAttr = tag.href ? 'href' : 'content'; | |
linkTag = (tag.rel && tag.href) ? true : false; | |
// add tag to page | |
if (linkTag) { | |
// do nothing if same tag exists already | |
pos = links.map(function(obj) { | |
if (obj[nameAttr] === tag[nameAttr]) { | |
return obj[contentAttr]; | |
} | |
}).indexOf(tag[contentAttr]); | |
if (pos !== -1) { return; } // tag exists already | |
links.push(tag); | |
$rootScope.links.push(tag); | |
} else { | |
// do nothing if same tag exists already | |
pos = metas.map(function(obj) { | |
if (obj[nameAttr] === tag[nameAttr]) { | |
return obj[contentAttr]; | |
} | |
}).indexOf(tag[contentAttr]); | |
if (pos !== -1) { return; } // tag exists already | |
metas.push(tag); | |
$rootScope.metas.push(tag); | |
} | |
}); | |
}; | |
/** | |
* Getter and Setter for page title | |
*/ | |
Object.defineProperty(MetaService, 'title', { | |
get: function() { | |
return page.title; | |
}, | |
set: function(title) { | |
page.title = title; | |
$rootScope.page.title = title; | |
} | |
}); | |
/** | |
* Getter and Setter for canonical link | |
*/ | |
Object.defineProperty(MetaService, 'canonical', { | |
get: function() { | |
var pos = links.map(function(link) { | |
return link['rel']; | |
}).indexOf('canonical'); | |
return links[pos]['href']; | |
}, | |
set: function(canonical) { | |
var tag = { | |
'rel': 'canonical', | |
'href': canonical | |
}; | |
links.push(tag); | |
$rootScope.links.push(tag); | |
} | |
}); | |
return MetaService; | |
}; | |
angular | |
.module('app.meta', []) | |
.service('MetaService', MetaService); | |
// *********************************************************************************** | |
// app-controller.js | |
'use strict'; | |
/** | |
* Application Controller | |
* | |
* @ngInject | |
*/ | |
function AppCtrl($rootScope, $log, $state, MetaService, configuration) { | |
$rootScope.$on('$stateChangeSuccess', function(event, state, params, from, fromParams) { | |
// set canonical based on the new state url & param values | |
MetaService.canonical = configuration.DOMAIN_HOST + $state.href(state, params); | |
}); | |
} | |
angular | |
.module('app') | |
.controller('AppCtrl', AppCtrl); | |
// *********************************************************************************** | |
// Example updates from random controller | |
// Update meta tags | |
MetaService.set([ | |
{title: 'Title goes here'}, | |
{name: 'description', content: 'Description goes here'}, | |
{'http-equiv': 'refresh', content: '15'}, | |
{'http-equiv': 'Content-Type', content: 'text/html; charset=utf-8'}, | |
{definition: 'rss', title: 'Site Name - RSS', href: 'http://feeds.feedburner.com/sitename/blog'}, | |
{definition: 'favicon', href: '/alternate-favicon.png'}, | |
{rel: 'stylesheet', href: '/css/hello.css'} | |
]); | |
// *********************************************************************************** | |
// index.html | |
<!doctype html> | |
<head> | |
<title data-ng-bind-template="{{ page.title }} - Site Name">Site Name</title> | |
<meta ng-attr-name="{{ meta.name }}" ng-attr-property="{{ meta.property }}" ng-attr-http-equiv="{{ meta['http-equiv'] }}" ng-attr-content="{{ meta.content }}" ng-attr-charset="{{ meta.charset }}" ng-attr-data-ng-repeat="meta in metas"> | |
<link ng-attr-rel="{{ link.rel }}" ng-attr-href="{{ link.href }}" ng-attr-type="{{ link.type }}" ng-attr-media="{{ link.media }}" ng-attr-data-ng-repeat="link in links"> | |
</head> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment