Catching temlpateUrl path errors - angularjs

I'm implementing a custom template inside a directive, like this:
.directive('card', function() {
return {
restrict: 'E',
replace: true,
templateUrl: function(element, attrs) {
return '/app/templates/' + attrs.cardtype + '.html';
}
};
});
The main template where the directive is generated looks like this:
<card ng-repeat="card in cards" cardtype="{{card.cardtype}}"></card>
Notice I'm using the "cardtype" attribute to select an appropriate template, and then assuming a template name in the directive.
This works fine as long as the cardtype attribute resolves to an html file in the template. However, if the file doesn't exist I get the error:
Error: [$compile:tpload] Failed to load template: /app/templates/{{card.cardtype}}.html
What's the best way to catch this error in order to render a default template?

I would try and ask $templateCache, whether this template exists. If you don't use template cache I highly recommend using it. You can set up a grunt task to scan all your .tpl.html files and set up a template-cache for use. In this way no real HTTP requests are going to get fired in order to fetch the templates.
For a nice example how to use templateCache see ng-boilerplate (ngbp)

Related

Using html file in angular directive template url in mvc 5 project

I'm creating an angularJs application in MVC 5. I've created a directive as given below.
app.directive('clusterButton', function () {
return {
restrict: 'E',
scope: {
clusterInfo: '=info'
},
templateUrl: function(elem, attr){
return 'ClusterButtonTemplate';
}
};
});
I have .cshtml file named ClusterButtonTemplate.cshtml and I created a partial view method in the controller class to return this view. So the angular js directive is binding the template.
I need to remove the method in mvc controller class and need to refer the template file directly. I don't want to use a cshtml file. I need a html file for template. I have created a ClusterButtonTemplate.html file. But while setting the template as below the browser shows a 404 error.
app.directive('clusterButton', function () {
return {
restrict: 'E',
scope: {
clusterInfo: '=info'
},
templateUrl: function(elem, attr){
return 'ClusterButtonTemplate.html';
}
};
});
I didn't use angular js routing in my project. Everything is managed using the MVC routing. How can I fix this issue. Do I need to use Angular routing and MVC routing?
You'll need to put in in a place where MVC will not try to map the URL to a controller. By default, the /Content folder is ignored, so you could create a folder under it called "Templates" and use that for the URL.
templateUrl: function(elem, attr){
return '/Content/Templates/ClusterButtonTemplate.html';
You may try to use a leading slash since it's loaded using a relative path.
templateUrl: function(elem, attr){
return '/ClusterButtonTemplate.html';
}
That's very simple! Just put an html file template (as content) in the folder that you prefer (ie. app/phone-list/ in project root) then assign
templateUrl: '/app/phone-list/phone-list.template.html'
to controller templateUrl property.
Avoid the views, model or controller folders...

How to insert template in html using angular?

Scenario:-
I have html page rendering as angular template/view. Now there are big number of such template.
Now these templates has div in header part that is fixed through out the templates, now is there some-way that we can define one sub-template at one place and just insert that sub-template in all pages.
So that if there are any modification to be made, I will make in sub-template and that will be reflected in all the page.
Its like UserControls or Partials that we have in ASP.Net.
I am using AgularJS
Agreed that there are ui-routing for nested hosting but currently I am not looking for that.
Try
<div ng-include="path/to/template"></div>
you can create a seperate html file as template for header if it includes complex or considerable amount of elements. create a directive for this template and use it as an attribute/customTag or include it in your html using ng-include.
app.directive('header',function(){
return {
restrict: 'E', //'E': element /'A': attribute
templateUrl : 'templates/header.html'
}
});
use as attribute
<div header></div> // as Attribute
<header></header> // as element
if your header involves lot of functioning on it then you can also create a separate controller (which will act as a child controller) and add the controller to the above tags. such as
<header ng-controller="headerController"></header>
You probably want to use a directive template. This is a very simple directive with only the template information.
Eg:
<top-header></top-header>
module.directive('topHeader', function() {
return {
templateUrl: 'path',
// append
replace: true,
// attribute restriction
restrict: 'E'
}
});

Jade templates for Angular directives

In my MEAN app, I use jade as my template engine. My problem is, when I call an angular directive, jade code is not working but html code is working. My code is given below:
index.jade
div(ng-repeat="num in addDir")
admin-collection
directive.js
var formDir = angular.module("formDirective", []);
formDir.directive('adminCollection', function() {
return {
restrict: 'E',
transclude: true,
// call jade template url
templateUrl: '../_template/_formTemplate/_adminCollection.jade'
};
});
_adminCollection.jade
h1 from _adminCollection templateUrl
If I use jade format code in _adminCollection.jade, it just show a plain text, not text inside h1 tag
But following code is working:
directive.js
var formDir = angular.module("formDirective", []);
formDir.directive('adminCollection', function() {
return {
restrict: 'E',
transclude: true,
// call jade template url
templateUrl: '../_template/_formTemplate/_adminCollection.html'
};
});
_adminCollection.html code::
<h1> from _adminCollection templateUrl </h1>
How can I solve this problem?
Jade is a template engine. Browser has only built-in html parser, so it does not understand what jade code means and treats it as plaintext.
To make it work you need to convert it to html. You can use some task manager to do it. Two most popular task managers for node.js are gulp and grunt. Each of them has a working jade plugin which you can use right away.
Jade is something like less - it must be convert to another format, because browser can't understand that. When you use less, you have to transform it to css. And if you use jade - to html.
If you use grunt, you should look on it: https://github.com/gruntjs/grunt-contrib-jade
Otherwise you can check if your IDE can transform jade to html. For example PhpStorm can do this in automatic way.
Then in your directives you should specify path to html template, no jade.
You can use following directory structure:
app/
src/
js/
less/
jade/
dist/
templates/ <-- here you can put your htmls
styles/ <-- and here put css
js/ <-- if you want, you can put this minimalized app.js
that will contain all of your project,
see grunt-contrib-uglify for more info
EDIT: here is really great article about grunt: http://anthonydel.com/my-personal-gruntfile-for-front-end-experiments/ There is much more then you need, but maybe it will help you
.... Or you can to use webpack to do the work.
then you can load the template like this:
angular.module('app').component('myComponent', {
bindings: {},
template: require('./mytemplate.jade')()
});
You can to note that I'm invoking the returned function.
Another option is to keep the HTML templates in your DOM, but hidden:
div(ng-non-bindable, style="display: none")
#adminCollectionTemplate
div(ng-repeat="num in addDir")
admin-collection
#anotherTemplate
//- Alternatively, pull in the template from another file
include ./_formTemplate/_adminCollection.jade
and then use jQuery to fetch the HTML out of the DOM, and give it to angular:
formDir.directive('adminCollection', function() {
return {
restrict: 'E',
transclude: true,
// fetch template from DOM
template: $('#adminCollectionTemplate').html()
};
});
This will just work, without any Ajax or any task runners. But it will clutter up the DOM with templates that could otherwise be hidden away in the JS. And it is an extra step to place every new template into that div.
ng-non-bindable is needed to tell Angular to leave the template elements alone (don't manipulate them or bind to them), until their clones are actually used by the directive.

Resolving relative template urls with angularJS and asp.net MVC

I searched through many posts already, but still can't make run a very basic custom directive since the templateUrl is not resolved correctly.
I've got an AngularJSController with an Index - action (asp.net MVC), calling View/AngularJS/Index.cshtml, very basic. In there, I call a custom directive:
<product-title></product-title>
which is outlined liked that:
app.directive('productTitle', function () {
return {
restrict: 'E',
// ends up with wrong url '{root-path}/AngularJS/AngularJSTemplates/ProductTitle'
templateUrl: 'AngularJSTemplates/ProductTitle'
}
});
As you can see, it should call the controller AngularJSTemplatesController (asp.net MVC) with the action method ProductTitle. This will return my partial for angularJS. And here is the problem: AngularJS calls {root-path}/AngularJS/AngularJSTemplates/ProductTitle instead of {root-path}/AngularJSTemplates/ProductTitle...
What I am missing here? Do I really need to define the root-path somewhere as a javascript-global and use it for absolute paths?
You may need to define the base url, see the documentation on using Relative links here
just replace directive with follwing directive :
app.directive('productTitle', function () {
return {
restrict: 'E',
// ends up with wrong url '{root-path}/AngularJS/AngularJSTemplates/ProductTitle'
templateUrl: 'AngularJS/AngularJSTemplates/ProductTitle'
}
});
i think directive cant find your template. AngularJS/AngularJSTemplates/ProductTitle is the relative url for your template. i think it wil work.

loading the angularJs directive through partial

I am new to AngularJs and struck with an issue. I have "index.html" where I need to have the main section loaded via the <div data-ng-view=""></div>. Now, the data inside the view will be populated by the controller using the below code
.when('/',
{
controller:'controllers.IndexCtrl',
templateUrl:'/partials/index-partial.html'
})
Inside the index-partial.html file I have used the custom directive linke below:
<custom-carousel/>
The code for the carousel is below:
myApp.directive('customCarousel', function() {
return {
restrict: 'E',
replace:'true',
templateUrl: "/partials/carousel.html",
link: function(scope, element, attrs) {
$('.my-list').click(function(){
$('.my-list').removeClass('active');
$(this).addClass('active');
});
}
};
});
The issue with the above approach is that the jquery code inside the directive gets called twice and hence the toggling of the selected li does not work.
I have below questions:
Is the jquery function inside the directive called twice because its called from the partial and once again during the ng-view?
Whats the reccommended way of handling this scenarios?
Whats the best approach to fix this issue. If I remove the templateUrl from the controller and directly use the custom-carousel inside the html, this works perfectly but I want to load the directive using the ng-view and not directly in the index.html file.
Please let me know the best approach to solve this issue.

Resources