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'+
'...'
);
}
})();
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'm trying to update a custom directive in AngularJS - it currently has a fixed template specified within the code (using the template: attribute).
I'd like to allow the user to optionally provide their own template instead, using the templateUrl: attribute.
My problem is how to provide a fallback - I can't use both template and templateUrl in the same directive. This is required to allow backwards compatibility.
I've tried using a function for templateUrl, but returning HTML isn't a runner there.
Any other suggestions?
If you use function in templateUrl, you are suppose to provide "template identifier" Angular first looks into the template cache, if its not found it tries to do asynchroneous request for the resource of the same url.
So you can simply put your default template into the file and just return its identifier as default.
By the way, if you are using templateUrl and html in separate files, be sure to use some kind of tool like https://www.npmjs.com/package/ng-html2js in the build process.
If anybody had a such problem please help.
I use Angular + Webpack and trying to require HTML files to my JS with html-loader.
At first I have required html file to my directive
var templateUrl = require('./test.html');
Then I do webpack command and webpack says everything is fine and bundle all file without any problem.
Then I have an ERROR (it's in my console):
[$compile:tpload] Failed to load template: <div class="test">
<p>This is my TEST</p>
</div> (HTTP status: 404 Not Found)
As I understand it's sees my html, but before this it's says that can't GET it(a template), why is that?
Request in the network
GET http://127.0.0.1:7773/portal/%3Cdiv%20class=%22test%22.....
For example success requires:
Request URL:http://127.0.0.1:7773/portal/dev/bundle.js
As I understand webpack looking it in some another place. How to fix it?
For info my full path:
/home/darthjs/Documents/****/src/public/portal/app/components/navtop/test.html
Use template: require('./test.html') instead of templateUrl.
On your directives:
{ // directive definition object
restrict: 'A',
template: require('./file.html')
}
You are reading file contents and using it as URL. You should use ngtemplate-loader (or any other similar loader) to get what you want – it will put file contents in Angular's template cache.
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
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.