I am using Grails 3 with the AngularJS profile together with the Angular Toastr plugin.
When I run the application in development mode, everything works perfectly but when I bundle the app (without minification), the templates from the plugin can't be loaded anymore and I get the following error:
Error: [$compile:tpload] Failed to load template: directives/toast/toast.html (HTTP status: 404 Not Found)
I checked the bundled code and found the lines:
angular.module('toastr')
.constant('toastrConfig', {
allowHtml: false,
autoDismiss: false,
closeButton: false,
closeHtml: '<button>×</button>',
containerId: 'toast-container',
extendedTimeOut: 1000,
iconClasses: {
error: 'toast-error',
info: 'toast-info',
success: 'toast-success',
warning: 'toast-warning'
},
maxOpened: 0,
messageClass: 'toast-message',
newestOnTop: true,
onHidden: null,
onShown: null,
onTap: null,
positionClass: 'toast-top-right',
preventDuplicates: false,
preventOpenDuplicates: false,
progressBar: false,
tapToDismiss: true,
target: 'body',
templates: {
toast: 'directives/toast/toast.html',
progressbar: 'directives/progressbar/progressbar.html'
},
timeOut: 5000,
titleClass: 'toast-title',
toastClass: 'toast'
});
and
angular.module("toastr").run(["$templateCache", function($templateCache) {$templateCache.put("directives/progressbar/progressbar.html","<div class=\"toast-progress\"></div>\n");
$templateCache.put("directives/toast/toast.html","<div class=\"{{toastClass}} {{toastType}}\" ng-click=\"tapToast()\">\n <div ng-switch on=\"allowHtml\">\n <div ng-switch-default ng-if=\"title\" class=\"{{titleClass}}\" aria-label=\"{{title}}\">{{title}}</div>\n <div ng-switch-default class=\"{{messageClass}}\" aria-label=\"{{message}}\">{{message}}</div>\n <div ng-switch-when=\"true\" ng-if=\"title\" class=\"{{titleClass}}\" ng-bind-html=\"title\"></div>\n <div ng-switch-when=\"true\" class=\"{{messageClass}}\" ng-bind-html=\"message\"></div>\n </div>\n <progress-bar ng-if=\"progressBar\"></progress-bar>\n</div>\n");}]);
so it seems that the templates are initialized correctly in the template cache.
I tried injecting the $templateCache in a controller and called $templateCache.get("directives/toast/toast.html")
and this returns me the correct template.
What could be the reason that the template is not loaded correctly when bundled, although I can access it with $templateCache.get(...)
?
Is there anything I am missing about the correct usage of the $templateCache?
PS: I noted the same problem for angular-bootstrap templates
Edit I found out, that everything works, when I use absolute templateUrls, so apparently, I don't fully understand, how the relative templateUrls work.
When the app is bundled, all the JS code is concatenated to a single file with a different path, which seems to break the loading via the $templateCache. Now, making all the templateUrls absolute would be a solution, but I can not do that for plugins, which use a relative templateUrl, without changing their code.
So, can anybody explain to me what is actually happening here and how I could fix this, without touching the plugin code?
I found out, that when generating the Grails app for Angular, it automatically includes the following lines in the index.gsp:
<script type="text/javascript">
window.contextPath = "${request.contextPath}";
</script>
This sets the window.contextPath
when the app is bundled for production which breaks the Angular $templateCache.
In other words: Set window.contextPath = ""
or the template resolution from the $templateCache will fail.