I am new to angular.js. I am trying to create a directive to add some title and meta tags in the <head> section of html documents, but I am having some trouble.
My index.html document is as following:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<base href="/">
<seo-title></seo-title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.1/angular.min.js"></script>
<script src="https://code.angularjs.org/1.4.1/angular-route.min.js"></script>
<script src="/incl/js/myApp.js"></script>
</head>
<body >
<div ng-view></div>
</body>
</html>
My javascript is:
var app = angular.module ('myApp', ['ngRoute']);
app.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$routeProvider
.when('/', { templateUrl: 'routes/home.html'})
.when('/pageA', { templateUrl: 'routes/pageA.html'})
.when('/pageB', { templateUrl: 'routes/pageB.html'})
.otherwise({ redirectTo: '/' });
$locationProvider.html5Mode({
enabled: true
});
}]);
app.directive('seoTitle', function() {
return {
restrict: 'E',
template: '<title>{{seo.title}}</title>'
};
});
When I open the inspector, the directive has been moved to the <body> and has not been replaced with the template:
How can I create directives in the header?
P.S.: A code example would be great!
Your directive does not need to go in the head to set the title. Just have your directive inject $window and set $window.document.title = 'your title'.
UPDATE This is how you can update meta tags.
For updating meta tags I would use a Directive like this:
mmMetaTags.$inject = ['metaTags'];
function mmMetaTags(metaTags) {
return {
restrict: 'A',
link: function(scope, element) {
metaTags.metaTags.forEach(function(tag) {
addMetaTag(tag.name, tag.content)
});
metaTags.subscribe(addMetaTag);
function addMetaTag(name, content) {
var tag = element[0].querySelector('meta[name="' + name + '"]');
if (tag) {
tag.setAttribute('content', content);
} else {
element.append('<meta name="' + name + '" content="' + content + '">');
}
}
}
}
}
directive('mmMetaTags', mmMetaTags);
Along with a service to set the metaTags:
function MetaTags() {
// private
this._tags = [];
// private
this._subscriber;
var self = this;
Object.defineProperty(this, 'metaTags', { get: function() {
return self._tags;
}});
}
MetaTags.prototype.addMetaTag = function(name, content) {
this._tags.push({ name: name, content: content });
this._updateSubscriber(name, content);
}
MetaTags.prototype.subscribe = function(callback) {
if (!this.subscriber) {
this._subscriber = callback;
} else {
throw new Error('Subscriber already attached. Only one subscriber may be added as there can only be one instance of <head>');
}
}
// private
MetaTags.prototype._updateSubscriber = function(name, content) {
this.subscriber(name, content);
}
service('metaTags', MetaTags);
So in your head tag you would include the attribute mm-meta-tags. Then in your controller you would inject the metaTags service and call addMetaTag to update the tags.
You answer is here: Set Page title using UI-Router, implemented in your code it could be:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<base href="/">
<title seo-title>doesn't work</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.1/angular.min.js"></script>
<script src="https://code.angularjs.org/1.4.1/angular-route.min.js"></script>
<script src="/incl/js/myApp.js"></script>
</head>
<body >
<div ng-view></div>
</body>
</html>
and you js:
app.directive('seoTitle', function() {
return {
restrict: 'a',
template: 'works'
};
you just need to add a controller or some logic to set the title you want
First things first: I was looking in the inspector and yes, somehow the title tag appears within the body. But it seems not to affect its function.
Now to the solution: At first glance it seems that only
replace: true is missing in the declaration of the seoTitle directive.
Adding it solves the problem and the seo-title is replaced with title tag as planned, but Angular wraps the content in an additional span element as a new scope is created (even if the scope for seoTag is declared isolated scope: {}).
I came up with following solution:
app.directive('seoTitle', function() {
function compile(elem, attrs, transclude) {
return function ($scope) {
transclude($scope, function (clone) {
elem.empty();
elem.append(clone[0].innerText);
});
};
}
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {},
compile: compile,
template: '<title ng-transclude></title>',
};
});
Usage:
<seo-title>My Title</seo-title>
As already mentioned, with replace: true you can remove the wrapping seo-title tag.
In order to remove the additionally created span element,
I provide the compile function with returns the postLink function.
I can't really explain, why I need to use the transclude function within the postLink function.
It seems to be a quite common problem, that Angular creates an additional span element in this case.
With a little bit try and error I found that the easiest way to get rid of the span, is to emtpy() the element and append only the innerText.
You can try metang library. Beside title it supports other meta tags(description, author, og:, twitter:, etc)
来源:https://stackoverflow.com/questions/31277637/how-to-create-an-angular-directive-in-the-head-section-of-a-document