Angular $templateCache在绑定相对templateUrls后出现404错误

Angular $templateCache 404 error for relative templateUrls after bundling

本文关键字:错误 templateUrls 相对 templateCache 绑定 Angular      更新时间:2023-09-26

我使用的是Grails 3和AngularJS配置文件以及Angular Toastr插件。
当我在开发模式下运行应用程序时,一切都运行得很好,但当我捆绑应用程序(没有缩小)时,插件中的模板无法再加载,我得到以下错误:

Error: [$compile:tpload] Failed to load template: directives/toast/toast.html (HTTP status: 404 Not Found)

我检查了捆绑的代码,发现了以下行:

angular.module('toastr')
    .constant('toastrConfig', {
      allowHtml: false,
      autoDismiss: false,
      closeButton: false,
      closeHtml: '<button>&times;</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'
    });

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");}]);

所以看起来模板在模板缓存中被正确初始化了。

我尝试在控制器中注入$templateCache并称为$templateCache.get("directives/toast/toast.html"),这将返回我正确的模板。

绑定模板时没有正确加载的原因是什么,尽管我可以使用$templateCache.get(...)访问它?
是否有什么我错过了正确使用$templateCache?

PS:我注意到angular引导模板也有同样的问题

编辑我发现,一切工作,当我使用绝对templateUrls,所以显然,我不完全理解,相对templateUrls是如何工作的。
当绑定应用程序时,所有JS代码都被连接到一个具有不同路径的文件中,这似乎会通过$templateCache中断加载。现在,使所有的templateUrl绝对将是一个解决方案,但我不能这样做的插件,使用相对templateUrl,不改变他们的代码。

所以,谁能解释给我到底发生了什么,我怎么能解决这个问题,而不触及插件代码?

我发现,在为Angular生成Grails应用程序时,它会自动在index.gsp中包含以下几行:

<script type="text/javascript">
    window.contextPath = "${request.contextPath}";
</script>

在应用被绑定到生产环境时设置window.contextPath,这会破坏Angular的$templateCache。

换句话说:设置window.contextPath = ""或者从$templateCache中解析模板会失败