Загрузка относительного templateUrl

Я пытался найти лучший способ создать модульное, масштабируемое угловое приложение. Мне очень нравится структура таких проектов, как angular-boilerplate, angular-app, где все связанные файлы сгруппированы по функциям для частей и директив.

project
|-- partial
|   |-- partial.js
|   |-- partial.html
|   |-- partial.css
|   |-- partial.spec.js

Однако во всех этих примерах URL-адрес шаблона загружается относительно базового URL-адреса, а не относительно текущего файла:

angular.module('account', [])
.config(function($stateProvider) {
  $stateProvider.state('account', {
    url: '/account',
    templateUrl: 'main/account/account.tpl.html', // this is not very modular
    controller: 'AccountCtrl',
  });
})

Это не очень модульно, и его может быть сложно поддерживать в больших проектах. Мне нужно помнить, что нужно менять путь templateUrl каждый раз, когда я перемещаю любой из этих модулей. Было бы неплохо, если бы был какой-то способ загрузить шаблон относительно текущего файла, например:

templateUrl: './account.tpl.html'

Есть ли способ сделать что-то подобное в angular?


person Danny Nelson    schedule 03.04.2014    source источник
comment
Взгляните на этот stackoverflow. ком/вопросы/21103724/   -  person BKM    schedule 03.04.2014


Ответы (5)


Я думаю, вы в конечном итоге обнаружите, что поддерживать пути относительно файла js будет сложнее, если вообще возможно. Когда придет время отправлять, вы, скорее всего, захотите объединить все ваши файлы javascript в один файл, и в этом случае вы захотите, чтобы шаблоны были связаны с baseUrl. Кроме того, если вы извлекаете шаблоны через ajax, что Angular делает по умолчанию, если вы не упаковываете их предварительно в $templateCache, вы определенно захотите, чтобы они относились к baseUrl, поэтому сервер знает, где их найти после того, как ваш js файл уже отправлен в браузер.

Возможно, причина, по которой вам не нравится иметь их относительно baseUrl в разработке, заключается в том, что вы не используете сервер локально? Если это так, я бы изменил это. Это сильно облегчит вам жизнь, особенно если вы собираетесь работать с маршрутами. Я бы проверил Grunt, у него есть очень простой сервер, который вы можете запустить локально, чтобы имитировать рабочую настройку, называемую Grunt Connect. Вы также можете проверить такой проект, как Yeoman, который предоставляет предварительно упакованную среду разработки интерфейса с использованием Grunt, поэтому вам не нужно не нужно тратить много времени на настройку. Проект Angular Seed также является хорошим примером настройки Grunt для локальной разработки.

person Charlie Martin    schedule 03.04.2014
comment
Да, я думаю, Angular на самом деле не настроен для этого. Мне просто не нравилось иметь относительный baseUrl, потому что в приведенной выше структуре проекта пары шаблон/директива шаблон/частичные всегда находятся в одном и том же каталоге. Думаю, мне нужно использовать что-то вроде RequireJS или Browserify, чтобы получить такую ​​функциональность. - person Danny Nelson; 03.04.2014
comment
Я обычно помещаю путь к своим файлам шаблонов в константу. Что-то вроде... angular.constant('TPL_PATH', '/main/templates/') Я даю каждому модулю собственный путь к шаблону и константу с тем же именем. Таким образом, все мои директивы просто... templateUrl: TPL_PATH + 'name.tpl.html', но TPL_PATH по-прежнему отличается для каждого модуля. - person Charlie Martin; 04.04.2014
comment
Интересно. Это определенно улучшение по сравнению с другим способом. Другой вариант — зарегистрировать более краткое имя шаблона (возможно, такое, которое соответствует имени контроллера/директивы), обернув шаблон ‹script type=text/ng-template id=controllerName.tpl.html›. - person Danny Nelson; 05.04.2014
comment
Проблема, которую я вижу в этом, пытаясь понять это, заключается в том, что когда я переношу свою функцию из приложения в приложение, я должен помнить о переносе не только части области сценариев, но и везде, где хранятся все шаблоны. Вместо перемещения одного каталога я перемещаю два каталога. Или может я не правильно это понимаю. - person Cowman; 17.04.2014
comment
Два каталога становятся одним, когда вы помещаете их в общий родительский каталог. Вы должны думать о своих шаблонах и сценариях как об одном и том же. Вместе они составляют исходный код вашего приложения. Ваше приложение не будет работать без того или другого - person Charlie Martin; 26.06.2015
comment
Я нашел этот пакет gulp очень полезным для изменения templateUrl на простой шаблон ! - person hugsbrugs; 17.05.2016

Лучший способ сделать это сейчас — использовать загрузчик модулей, такой как browserify, webpack или typescript. Есть и множество других. Поскольку требования могут быть сделаны из относительного местоположения файла, а дополнительный бонус в виде возможности импортировать шаблоны с помощью преобразований или загрузчиков, таких как частичное, вам даже не нужно больше использовать URL-адреса шаблонов. Просто вставьте шаблон через require.

Мой старый ответ все еще доступен ниже:

Я написал пост именно на эту тему и рассказал об этом на нашем местном Angular Meetup. Большинство из нас сейчас используют его в производстве.

Это довольно просто, если ваша файловая структура эффективно представлена ​​в ваших модулях. Вот краткий предварительный просмотр решения. Полная ссылка на статью следует.

var module = angular.module('myApp.things', []);

var all = angular.module('myApp.things.all', [
    'myApp.things',
    'things.someThing',
    'things.someOtherThing',
    'things.someOtherOtherThing',
]);

module.paths = {
    root: '/path/to/this/thing/',
    partials: '/path/to/this/thing/partials/',
    sub: '/path/to/this/thing/sub/',
};

module.constant('THINGS_ROOT', module.paths.root);
module.constant('THINGS_PARTIALS', module.paths.partials);
module.constant('THINGS_SUB', module.paths.sub);

module.config(function(stateHelperProvider, THINGS_PARTIALS) {

    stateHelperProvider.setNestedState({
        name: 'things',
        url: '/things',
        templateUrl: THINGS_PARTIALS + 'things.html',
    });
});

И тогда любые подмодули или «относительные» модули выглядят так:

var module = angular.module('things.someThing', ['myApp.things']);
var parent = angular.module('myApp.things');

module.paths = {
    root: parent.paths.sub + '/someThing/',
    sub: parent.paths.sub + '/someThing/sub/',
    partials: parent.paths.sub + '/someThing/module/partials/',
};

module.constant('SOMETHING_ROOT', module.paths.root);
module.constant('SOMETHING_PARTIALS', module.paths.partials);
module.constant('SOMETHING_SUB', module.paths.sub);

module.config(function(stateHelperProvider, SOMETHING_PARTIALS) {

    stateHelperProvider.setNestedState({
        name: 'things.someThing',
        url: "/someThing",
        templateUrl: SOMETHING_PARTIALS + 'someThing.html',
    });
});

Надеюсь это поможет!

Полная статья: Относительные модули AngularJS

Ваше здоровье!

person tannerlinsley    schedule 12.11.2014
comment
Это действительно элегантное решение. Не могу дождаться, чтобы начать использовать его! - person Derek Perkins; 12.11.2014
comment
Это выглядит интересно. Основная проблема, с которой я столкнулся, заключается в том, что это добавляет зависимость к родительскому модулю и, возможно, круговые зависимости. Разве обычно не лучше, чтобы родительские модули зависели от дочерних модулей? Можете ли вы по-прежнему тестировать модуль «things.someThing» изолированно? - person marapet; 25.03.2015
comment
Вариант использования для этого касается не внедрения зависимостей, а большей файловой структуры. В основном это относится к модулям, которые могут находиться внутри других модулей для организаций или для создания платформы для сторонних интеграций и модулей, которые должны быть правильно созданы и расположены в вашей файловой структуре. - person tannerlinsley; 18.04.2015
comment
Поскольку мы используем здесь инъекцию, возможно, стоит иметь еще один централизованный блок (или модуль) только для путей, чтобы у нас было много констант, определенных как Home.Second.Third и т. д. - person windmaomao; 09.06.2015

Я уже какое-то время разбираюсь в этом вопросе. Я использую gulp для упаковки своих шаблонов для производства, но я изо всех сил пытался найти решение, которое меня устраивало для разработки.

Вот где я оказался. Фрагмент ниже позволяет переназначить любой URL по своему усмотрению.

angular.module('rm').config(function($httpProvider) {

  //this map can be defined however you like
  //one option is to loop through script tags and create it automatically
  var templateMap = {
    "relative.tpl.html":"/full/path/to/relative.tpl.html",
    etc...
  };

  //register an http interceptor to transform your template urls
  $httpProvider.interceptors.push(function () {
    return {
      'request': function (config) {
        var url = config.url;
        config.url = templateMap[url] || url;
        return config;
      }
    };
  });
});
person Tom Makin    schedule 23.03.2015

В настоящее время можно делать то, что вы хотите, используя загрузчик модулей systemJs.

import usersTemplate from './users.tpl';

var directive = {
   templateUrl: usersTemplate.name
}

Вы можете посмотреть хороший пример здесь https://github.com/swimlane-contrib/angular1-systemjs-seed

person Andzej Maciusovic    schedule 17.05.2016

Я использовал templateUrl: './templateFile.tpl.html, но что-то обновил, и оно сломалось. Так что я бросил это туда.

Я использовал это в своем объекте Gruntfile.js html2js:

html2js: {
  /**
   * These are the templates from `src/app`.
   */
  app: {
    options: {
      base: '<%= conf.app %>',
      rename: function( templateName ) {
        return templateName.substr( templateName.lastIndexOf('/') );
      }
    },
    src: [ '<%= conf.app %>/**/{,*/}<%= conf.templatePattern %>' ],
    dest: '.tmp/templates/templates-app.js'
  }
}

Я знаю, что это может привести к конфликтам, но для меня это меньшая проблема, чем необходимость редактировать /path/to/modules/widgets/wigdetName/widgetTemplate.tpl.html в каждом файле каждый раз, когда я включаю его в другой проект.

person b.kelley    schedule 24.03.2015