Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use separate templates with my angular directive bower package?

So I have a large set of directives I created that I want to use on many projects, so I turned it into a bower package and included it in one of my projects. Unfortunately the directives won't work, because the templateUrl path is incorrect.

The templateUrls are based on the templates being in the same directory as the js for the directives. So "./tabbedtextareas.html" What are some of my simpler options for solving this problem?

The ones I've thought of so far are:

  • copy and paste the html into the JS files
    • editing the templates will be a pain afterwards
  • use grunt to compile the templates with the JS, perhaps even creating a hook to commit, merge to master and push.
    • This is a very simple plugin and I prefer to keep things as simple as possible.
  • put my templates in a directory, then in each project have my server handle requests to that folder.
    • anyone requiring my directives as a dependency in bower would need to do know this specific thing. Ie. the package would not installable simply by bower install.

Is there maybe like a bower install script you can add or something? Any help is appreciated.

like image 351
Sophie McCarrell Avatar asked May 06 '14 21:05

Sophie McCarrell


2 Answers

I've been on the hunt for guidance/advice on this very problem, and have considered a number of different options. I thought I'd share what I've settled on currently.

N.B. the project that this is approach is being used on is still in its early stages, so the approach described is by no means set in stone. I wouldn't be surprised if I had to adapt/change it in the future.

Background context is the same, we've got multiple self-contained directives living on GitHub that are used via bower. Each components template has to be inline with the directive, as templateUrl paths won't work.

I'm essentially doing option 2 from above, using gulp, and leveraging the angular template cache using the gulp-angular-templatecache plugin.

Solution

gulpfile.js

Does 2 things, parse component name and write template contents to template cache (via gulp plugin) and concatenate component code and mark-up into single file (into dist/<component-name>.js.

var gulp = require('gulp'),
    templates = require('gulp-angular-templatecache'),
    concat = require('gulp-concat'),
    clean = require('gulp-clean'),
    pkg = require('./package.json');

var template = 'myTemplate.tpl.html'

gulp.task('templates', function () {
  return gulp.src(template)
    .pipe(templates('templates.tmp', {
      root: '/templates/',
      module: pkg.name
    }))
    .pipe(gulp.dest('.'));
});

gulp.task('concat', ['templates'], function () {
  return gulp.src([pkg.main, 'templates.tmp'])
    .pipe(concat(pkg.name + '.js'))
    .pipe(gulp.dest('./dist/'));
});

gulp.task('clean', ['concat'], function () {
  gulp.src('./*.tmp', {read: false})
    .pipe(clean());
});

gulp.task('watch', function () {
  gulp.watch(['*.js', '*.html'], ['build']);
});

gulp.task('build', ['templates', 'concat', 'clean']);
gulp.task('default', ['build', 'watch']);

Output

The template gets set in the template cache, and the directive retrieves it via $templateCache.get(key) when setting the template attribute. This gives the single file output needed to use this component via bower, whilst allowing you to maintain the mark up in a separate file in source.

angular.module('myModule', []).directive('myDirective', function ($templateCache) {

  return {
    template: $templateCache.get('/template/myTemplate.tpl.html');
    link: function (scope, elm, attr) {

    }
  };
});

angular.module("myModule").run(["$templateCache", function($templateCache) {$templateCache.put("/template/myTemplate.tpl.html","<div>This is the template for your component</div>");}]);

Thoughts

  1. There's an additional overhead of having a build step when working on a component. Given the requirement, I don't think there's a way to completely avoid such a step. If it's not done during component build, then it'd have to be done at implementation time. Given those 2 options, I think it's better to do it in the component when the scope is narrow and clear.

  2. I'm not convinced my gulp tasks are entirely optimal. There's a certain amount of synchronicity, which runs contrary to "the gulp way". Could probably figure out how to improve it with some time/effort.

like image 110
Jaz Lalli Avatar answered Dec 27 '22 08:12

Jaz Lalli


I used grunt-angular-templates "Grunt build task to concatenate & register your AngularJS templates in the $templateCache"

// within my Gruntfile.js
grunt.initConfig({
  ngtemplates: {
    'angular-my-directives': {
      src:      'views/**/*.html',
      dest:     'template.js'
    }
  }
  // ...
});

generates something like: ./template.js

angular.module('angular-my-directives').run(['$templateCache', function($templateCache) {

  $templateCache.put('views/directives/my-download.html',
    "<form name=\"myDownloadForm\" ng-submit=\"submit()\" novalidate>\n" +
    "</form>"
  );

}]);

Now in my directive I can simply use templateUrl: 'views/directives/my-download.html' and it will use the $templateCache.

Finally I used grunt-contrib-concat to combine my files for easy loading.

like image 26
electblake Avatar answered Dec 27 '22 10:12

electblake