TemplateUrl в директивах AngularJS

Когда шаблон в директиве становится большим - его трудно поддерживать. Мы можем заменить переменную шаблона на templateUrl, которая позволяет указывать какой шаблон загружать.

Для этого создадим директиву в файле index.html:

<!DOCTYPE html>
<html lang="en" ng-app='app'>
<head>
    <meta charset="UTF-8">
    <title></title>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.9/angular.min.js"></script>
  <script>
      var app = angular.module('app', []);
 
      app.directive('fooBar', function () {
          return {
              restrict: 'E',
              link: function (scope, element, attrs) {
                  console.log('directive')
              }
          };
      });
    </script>
</head>
<body>
<foo-bar></foo-bar>
</body>
</html>

Эта директива возвращает объект, с полями restrict, template и link функцией. При обновлении страницы видим, что наш console.log отрабатывается.

Давайте добавим какой-то шаблон, например:

var app = angular.module('app', []);
 
app.directive('fooBar', function () {
    return {
        restrict: 'E',
        template: "<div>element</div><div>element</div><div>element</div>",
        link: function (scope, element, attrs) {
            console.log('directive')
        }
    };
});

Если кода в шаблоне немного, как в нашем примере, одна строка, то использование шаблона нам подходит, так как его достаточно легко поддерживать. Но как только наш шаблон разрастается, при этом директива, к примеру, занимает более 50-ти строк в html файле, поддерживать такой код становится очень непросто. Вот тогда то нам и понадобится такая вещь, как TemplateUrl, которая указывает ссылку на шаблон.

Давайте перепишем наш код с помощью TemplateUrl, где в качестве ссылки укажем - bookmarks.html:

var app = angular.module('app', []);
 
app.directive('fooBar', function () {
    return {
        restrict: 'E',
        templateUrl: "bookmarks.html",
        link: function (scope, element, attrs) {
            console.log('directive')
        }
    };
});

Открыв браузер, видим, что ничего не работает и выдается ошибка - браузер не может загрузить файл bookmarks.html. Проверяем путь, по которому браузер пытается загрузить файл - все верно. Мы видим ошибку, который нам говорит, что кроссдоменный запрос не поддерживается при использование локального file:/.. . Но у нас открыта локальная html страница в браузере, поэтому нормально, что путь указан через file:/.., ведь мы не используем сервер. Конечно, если бы у нас был сервер, и мы бы обращались к нему через http протокол - подобная ошибка не возникла бы. Что же мы можем сделать, чтобы устранить данную ошибку?
Мы не будем создавать отдельный файл, вместо этого в html добавляем еще один script и в type указываем ng-template, а также id:

<!DOCTYPE html>
<html lang="en" ng-app='app'>
<head>
    <meta charset="UTF-8">
    <title></title>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.9/angular.min.js"></script>
  <script>
      var app = angular.module('app', []);
 
      app.directive('fooBar', function () {
          return {
              restrict: 'E',
              templateUrl: "bookmarks.html",
              link: function (scope, element, attrs) {
                  console.log('directive')
              }
          };
      });
    </script>
</head>
<body>
<foo-bar></foo-bar>
<script type="text/ng-template" id="bookmarks.html"></script>
</body>
</html>

Данный скрипт загружает наш шаблон ангулара на страницу. Это тоже самое, как если бы мы получали наш шаблон, используя http протокол, как это должно было бы быть по умолчанию. Наш id совпадает с templateUrl, который мы ранее передали.
Напишем внутри скрипта произвольный html код, например:

Напишем внутри скрипта произвольный html код, например:

<script type="text/ng-template" id="bookmarks.html">
    <div>Hello from TemlateUrl</div>
</script>

Открываем браузер - ошибок нет, также содержание нашего шаблона Hello from TemlateUrl вывелось в директиве. Если посмотреть в инструменты разработчика в браузере - видно, что именно наш скрипт загрузил шаблон.

Немного усложним:

<script type="text/ng-template" id="bookmarks.html">
    <div ng-repeat='bookmark in bookmarks'>
        {{bookmark.name}}
    </div>
</script>

Для того, чтобы все корректно работало - создаем массив в директиве, с объектами внутри. В link-функции присвоим scope.bookmarks наш массив bookmarks:

var app = angular.module('app', []);
 
app.directive('fooBar', function () {
    var bookmarks = [
        {
            id: 1,
            name: 'EmberJS'
        },
        {
            id: 2,
            name: 'AngularJS'
        }
    ];
    return {
        restrict: 'E',
        templateUrl: "bookmarks.html",
        link: function (scope, element, attrs) {
            console.log('directive');
            scope.bookmarks = bookmarks;
        }
    };
});

Обновим браузер - в шаблоне вывелись все объекты массива.

Итак, данный метод позволяет перенести часть кода в html файл и его достотачно лего поддерживать. Даже если будет написано больше кода, так как мы используем html файл, в котором хорошо видна разметка, в частности, закрываемость тегов - код поддерживать, повторюсь, проще.

<script type="text/ng-template" id="bookmarks.html">
    <div ng-repeat='bookmark in bookmarks'>
        {{bookmark.name}}
    </div>
 
    <div ng-repeat='bookmark in bookmarks'>
        {{bookmark.name}}
    </div>
 
    <div ng-repeat='bookmark in bookmarks'>
        {{bookmark.name}}
    </div>
</script>

Практически во всех случаях, когда template разрастается, используют templateUrl, с указанием пути. Если же вы хотите, чтобы templateUrl работал не через скрипт, то есть несколько вариантов. Самый простой - поднять веб-сервер. Если же вы не знаете как это сделать, или по тем или иным причинам не желаете это делать, тогда можно использовать WebStorm. Там можно открыть html файл с помощью внутреннего сервера вебшторма. Тогда, при открытии html файла - программа открывает его не через file:/.., а через localhost, с указание используемого порта. Например, путь будет иметь следующий вид - localhost:4342/index.html . Также можно поднять веб-сервер с помощью Node.js.