Here's the situation. I have a directive, that depends on a templateUrl.
The directive looks something like this:
angular.module('foo')
.directive('bar', function(){
return {
restrict: 'E',
replace: true,
templateUrl: '/foo/bar.html',
controller: 'fooController',
require: '^ngModel',
scope: {
onSuccess: '&'
}
};
});
This directive is part of one of my applications, and it's important that it stays part of the application. However, I'd also like to use the same directive in other projects, and currently I'm using bower to pull down the repository into my other projects. However, this directive will break because the templateUrl will be incorrect. Bower clones down my entire project, and the actual path of the template, at best, will need to be this in my other project:
/lib/public/foo/bar.html
How do other people manage this?
I've never liked using template strings for templating due to issues with maintainability. I prototype html very quickly so I opt for a grunt task that reads my files and processes them into a single $templateCache js file.
Solution
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', // where my view files are
dest: 'src/templates.js' // single file of $templateCache
}
}
// ...
});
generates something like: ./src/templates.js which preserves my folder structure:
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.
Checkout "Grunt concat + uglify with sourcemaps" (or leave a better link in comments) to learn about how to concat + uglify (aka min) js files into a single "dist" file.
If working on your own custom bower package..
Be sure to commit the concatenated (aka built) files to the package repo so your package consumers can simply include my-concat-package.js or my-concat-package.min.js
Angular directives have templateUrl and template properties. template receives a HTML string. It's not a perfect solution, because you need to put HTML into your JS. But it is a common pattern for library creators to put the HTML string directly on template property, so they can wrap their module into a single file.
You may want make that templateUrl-to-template a build step of you lib.
Take a look on Angular Bootstrap Bower Repo.
One solution to this, and my personally preferred solution to this, is to put the template into $templateCache in a Module.run function. That way you never have to worry about the url referring to the wrong thing--you can give it any arbitrary identifying url you want--and it will never require an http request to fetch that template, to boot.
In your-directive project:
Create all template with xyz.tpl.html file name, and put into your-directive dir with all js code. All templateUrl looks like
templateUrl: '/template/my.tpl.html'
In app project:
Create a gulp/grunt task in your project for copy all *.tpl.html file into /template/ dir from bower_components (default).
e.g.:
// copy template files
gulp.task('copy-tpl', function() {
return gulp.src([
config.dirs.src.bower_components + '/**/*.tpl.html'
])
.pipe(flatten())
.pipe(gulp.dest(config.dirs.build.tpl));
});
Important!
The /template dir is a convention (as js, css, etc).
You can do this with gulp using gulp-angular-templatecache.
You directive would look like so:
angular.module('foo').directive('bar', function($templateCache){
return {
restrict: 'E',
replace: true,
template: '$templateCache.get('bar.html')',
controller: 'fooController',
require: '^ngModel',
scope: {
onSuccess: '&'
}
};
});
And your gulpfile.js would look like this:
var gulp = require('gulp'),
addTemplates = require('gulp-angular-templatecache');
gulp.task('default', function() {
gulp.src('templatesDir/**/*.html')
.pipe(addTemplates('templateFile.js', {module: 'foo' }))
.pipe(gulp.dest('dist'));
});
This produces the file 'templateFile.js' in your dist folder which then can be packaged with your directive file in your bower.json.
I already gave an answer using grunt to build your html files into $templateCache file, but I've since switched to gulp, so anyone looking to follow same process but using gulp, checkout gulp-angular-templatecache
Related
I am minifying an angular project through gulp.This project contains index.html,css,libraries,app.js(Angular module containing routing layer+controllers) and views.
I could easily minify+concat all js files,libraries and css files into one bundle file.HTML files were also easily minified but the problem is i have routing in my app.js which render templateUrl like
.state('dashboard.home', {
url: '/home',
templateUrl: 'app/views/dashboard/home.html'
})
Now,beacause of this routing i cannot minify+concat all html files into one.because each route renders one view with its file name while there will be only one file named bundle.html.
Here,I need a guideline about how to handle this situation.
Thanks Regards
I use the gulp-ng-template for this:
gulpfile.js:
var ngTemplate = require('gulp-ng-template');
....
gulp.task('templates', function () {
return gulp.src(['view1.html', 'view2.html'])
.pipe(ngTemplate({filePath: 'js/tpl.js'}))
.pipe(gulp.dest('test'));
});
ngTemplate combines your views and puts them into the single file js/tpl.js that will look like this:
angular.module('ngTemplates').run(['$templateCache', function($templateCache) {
$templateCache.put('view1.html', '<div class="test">A</div>\n');
$templateCache.put('view2.html', '<div class="test">\n <span>B</span>\n</div>\n');
}]);
Now all you need is to include this file into your index.html. Your views will be available to the angular compiler at their original paths. You don't need to include your original html views into project any more.
You can add this file js/tpl.js to your index.html manually or by using ng-html-replace.
Instead of concatenating all templates into one html file you should use $templateCache angular provider and convert all of your html templates into JavaScript code. By using templateCache you can put all of your teplates into one file and it will work perfectly with routing mechanism. Try this gulp module Gulp ng templates
I am just starting out with AngularJS. I decided to go with ng-BoilerPlate as a structure.
I am currently stuck on creating a small custom directive.
What I did was the following :
I created an html file for the directive under src/app/login/sso/facebook-button.html.
This contains just regular code you need for a directive.
<a href="#" class="btn btn-lg btn-block omb_btn-facebook">
<i class="fa fa-facebook visible-xs"></i>
<span class="hidden-xs">Facebook</span>
</a>
In this same directory I also created the javascript file needed for this directive "ssoDirective.js".
app.directive('facebookButton', function() {
return {
restrict : 'E',
templateUrl : 'facebook-button.html'
};
});
Finally I just used the template in a login.tpl.html file (which works no problem without this template).
<facebook-button><facebook-button>
Now when I grunt this code (just the normal grunt config of ng-boilerPlate) I get the following error in Chrome :
GET http://localhost:63342/app/login/sso/facebook-button.html 404 (Not Found)angular.js:8632
Error: [$compile:tpload] Failed to load template: /app/login/sso/facebook-button.html
I understand why this error is arrising. When I look into the build directory the facebook-button.html file just isn't there anywhere. Using grep I can also not find the contents of this file anywhere in this directory.
So grunt clearly skips this file while building.
So the question is. How do you create a very simple directive like this in ng-boilerPlate. Where do you place the .html for a directive so it gets included in the grunt build of ng-boilerPlate, and what templateUrl you specify so it gets found.
The templates in ngbp will be merged into one file during the build process (actually two separate files, templates-app.js for the app-modules and templates-common.js for common reusables). This process done by html2js task configured in Gruntfile.js.
In build.config.js you can specify which files where to merge. By default all files match src/common/**/*.tpl.html pattern goes to templates-common.js and files match src/app/**/*.tpl.html merged into templates-app.js. You can also add your own rules but don't forget to configure Gruntfile.js as well!
If you really want to use explicit template definition (so the template will not be merged into build/templates-app or build/templates-common.js) one solution is to use the template property on your directive and provide the template inline. A better way to achieve the same is to use $templateCache to include template.
Refering to the documentation of $templateCache
First you must configure the run() section of your module as the following:
app.run(function($templateCache) {
$templateCache.put('facebook-button.html', 'Content of facebook-button.html');
});
Now you can use the standard templateUrl way to include facebook-button.html into your directive!
app.directive('facebookButton', function() {
return {
restrict : 'E',
templateUrl : 'facebook-button.html'
};
});
You can get cleaner code if you separate the function and give just reference to run()
(function(){
'use strict'
angular
.module('app',[...])
.run(Template);
.directive('facebookButton',Directive);
function Directive(){
return {
restrict : 'E',
templateUrl : 'facebook-button.html'
};
}
function Template($templateCache) {
$templateCache.put('facebook-button.html',
'...'+
'Content of facebook-button.html'+
'...'
);
}
})();
Upon learning Angular Route Styles, It's easier to apply different styles on different templates.
Since it makes it so dynamic, I was wondering if there's a library to append scripts file(s) dynamically within the route configuration on a particular template like Angular Route Styles for stylesheet?
More like this (focusing more on js: "app/controller/template.js")
$routeProvider.when("/",
{
templateUrl: "template.html",
controller: "TemplateCtrl",
css: "css/template.css",
js: "app/controller/template.js"
});
I was planning to write an external js file for the controller of the template. Thus of course, removing the property controller: "TemplateCtrl" on the configuration file. But this would make things more easier for code management.
Can I link to a specific file within a Plunker? Specifically, I'd like to use Angular's "templateUrl" within a directive to externalize the HTML for a directive I'm building:
myApp.directive('groupedlist', function() {
return {
restrict: 'E',
scope: true,
templateUrl: '/groupedList.html',
link: function() {}
};
});
I have a file called "groupedList.html" that contains a HTML template, but it seems like these are logical files within a Plunker project - my browser complains because it can't find groupedList.html. Is it possible to do what I'm trying to do using Plunker? I'd rather not use the "template" attribute because there is a not-insignificant amount of HTML content I'd like to externalize.
templateUrl doesnt work with absolute URLs, use relative URL instead (like './page.html' or '../templates/page.html'). If u need to load cross domain page to template, u can do a request (XMLHttpRequest) and set STRING HTML as a template.
Like what Rafael said, but just to add...if you put your files in a subfolder like i did, use:
templateUrl: 'app/home.html',
styleUrls: ['app/home.css'],
You would think './home.html' would work but it doesn't even though my component is in the same folder.
I've got a repeater set up and can get data to display as long as there is no html within it.
I've included angular-sanitize.js and have tried using ng-bind-html
But nothing is displayed within the span, only within the ng-bind-html attribute. So it looks like sanitise isn't working,
I read that this needs to be added to the app dependencies but am not sure where to do so.
I've just been working through the tut on the angular site so only have a very basic controller set up at the minute.
You need to include the angular-sanitize.js
http://ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular-sanitize.js
Add 'ngSanitize' to you module dependencies
var myApp = angular.module('myApp', ['ngSanitize']);
Don't use the {{}} in the attribute
<h1 ng-bind-html="item.title"></h1>
Don't use $sce.trustAsHtml()
My solution to this was to download the js file from here
http://ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular-sanitize.js
I had been using the one I found in the angular git repo,
I experienced a similar issue but mine was a bit weird. Only input tags were not rendered while everything else including
<h3></h3>
<em></em>
did. After several hours i realised that apart from
angular-sanitize.min.js
I needed to add
textAngular-sanitize.min.js
to my project before the input tags worked. It was really frustrating so I hope this helps anyone in a similar situation
Encountered this issue when using a directive and the solution was not using "replace" in the code.
`ng-html-bind' was being used on a div in the templateUrl view
appDirectives.directive('helpText', [function () {
return {
restrict: 'E',
//replace: true, // With this uncommented it does not work!
scope: {
displayText: '='
},
templateUrl: '/web/form/helptext',
link: function (scope) {
}
};
}]);
My solution was the opposite of Seglespaan. It was to use the Bower version of Angular Sanitize.
bower install angular-sanitize
https://github.com/angular/bower-angular-sanitize