2015-07-07 9 views
6

Jestem nowy w angular.js. Próbuję utworzyć dyrektywę, aby dodać tytuły i znaczniki meta w sekcjidokumentów HTML, ale mam pewne problemy.Jak utworzyć dyrektywę kątową w sekcji <head> dokumentu?

Moja index.html dokument jest następujący:

<!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> 

Moja JavaScript jest:

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>' 
    }; 
}); 

Kiedy otworzyć inspektora, dyrektywa została przeniesiona do <body> i nie został zastąpiony szablon:

enter image description here

Jak mogę utworzyć dyrektywy w nagłówku?

P.S .: Przykład kodu byłby świetny!

+0

Dlaczego potrzebowałbyś dyrektywy, aby dodać metatagi? Po prostu wstaw je od początku? Tytuł można łatwo ustawić z kontrolera, który można przypisać do znacznika html, a głowa będzie miała do niego dostęp. – Chrillewoodz

+1

Niektóre strony będą zawierały niektóre metatagi, a inne nie. Poza tym nie chodzi tylko o tytuł, może to być ustawienie metatagu robots na noindex strony, itd ... – JVerstry

+1

Nie jestem pewien, ale myślę, że specyfikacja HTML nie pozwala na niestandardowe elementy, takie jak ' "jako dziecko z' '. Bez względu na to, szablon nie zastąpi elementu dyrektywy - możesz użyć 'replace: true' (ale jest to przestarzałe), lub możesz po prostu użyć dyrektywy atrybutów zamiast' ' –

Odpowiedz

2

Państwo odpowiedź jest tutaj: Set Page title using UI-Router, realizowane w kodzie może to być:

<!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> 

a wy JS:

app.directive('seoTitle', function() { 
return { 
    restrict: 'a', 
    template: 'works' 
}; 

wystarczy dodać kontroler lub jakąś logikę, aby ustawić tytuł, który chcesz

2

Po pierwsze: patrzyłem w inspektorze i tak, w jakiś sposób tag tytułu pojawia się w ciele. Ale wydaje się, że nie wpływa to na jego funkcję.

Teraz do rozwiązania: Na pierwszy rzut oka wydaje się, że tylko replace: true brakuje w deklaracji dyrektywy seoTitle. Dodanie go rozwiązuje problem i seo-title jest zastąpiony title znacznikiem zgodnie z planem, ale kątowa zawija zawartość w dodatkowym span jako elementu tworzony jest nowy zakres (nawet jeśli zakres seoTag jest zadeklarowana izolowane scope: {}).

wymyśliłem następujące rozwiązanie:

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>', 
    }; 

}); 

Zastosowanie:

<seo-title>My Title</seo-title> 

Jak już wspomniano, z replace: true można zdjąć torebkę seo-title tag.

W celu usunięcia dodatkowo utworzony span element, że dają funkcję compile zwrotami funkcję postLink.

Nie mogę wyjaśnić, dlaczego potrzebuję użyć funkcji transclude w ramach funkcji postLink. Wydaje się, że dość powszechnym problemem jest to, że Angular tworzy w tym przypadku dodatkowy element span. Z niewielką próbą i błędem stwierdziłem, że najprostszym sposobem na pozbycie się span jest dodanie do elementu emtpy() i dodanie tylko innerText.

+0

nie ma pojęcia skąd ten dodatkowy zakres pochodzi, nigdy wcześniej tego nie widziałem. Dostarczone rozwiązanie wydaje się o wiele bardziej złożone niż to potrzebne – charlietfl

4

Twoja dyrektywa nie musi iść w head, aby ustawić tytuł. Po prostu wprowadź dyrektywę $window i ustaw $window.document.title = 'your title'.

UPDATE W ten sposób można aktualizować metatagi.

Do aktualizacji metatagów użyłbym dyrektywę takiego:

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); 

Wraz z usługą ustawić metatagi:

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); 

Więc w tagu head byś to atrybut mm-meta-tags . Następnie w kontrolerze należy wprowadzić usługę metaTags i zadzwonić pod numer addMetaTag, aby zaktualizować tagi.

+0

Jestem świadomy prostszego rozwiązania dla tytułów, ale jak wspomniano w komentarzach do pytania, chodzi nie tylko o tytuł .. – JVerstry

+1

@JVerstry Zaktualizowałem swoją odpowiedź na przykładzie dyrektywy i usługa do ustawiania metatagów. – Martin

0

Możesz wypróbować bibliotekę metang. Poza tytułem obsługuje inne metatagi (opis, autor, og: , twitter:, itp.)

+0

Hej, możesz mi pomóc z metang przez jakąkolwiek próbkę. – Ashu

+0

Tak, oczywiście. Oto przykład https://gist.github.com/timsly/85aadbfb559d85c03a0995f58b28ba56 – timsly

+0

Mogę później dodać jsfiddle lub codepen w razie potrzeby – timsly

Powiązane problemy