如何捕获Angular中ng-include的错误?

8

当我将ng-include用作标题时,如果地址(文件路径)不存在,该如何捕捉错误?

我在一个带有ng-routeng-view中完成了一个ng-include 路由器,它看起来有点像这样:

ContentCtrl:

var content = $route.current.params.content,
    tmplArr = content.split("_"),
    tmpl = {},
    personId=$route.current.params.personId||$scope.persons[0].id;
$scope.personId=personId;
tmpl.url = "content/";
for (var i = 0, len = tmplArr.length; i < len; i++) {
    tmpl.url += tmplArr[i] + "/";
}
tmpl.url = tmpl.url.substring(0, tmpl.url.length - 1) + ".html";
$scope.template = tmpl;

ContentView:

<div ng-include="template.url" class="ng-animate"></div>

当我使用不存在的地址时,比如:/home/#/content/profile_asdfa,angular就会在循环中获取资源。所以我需要捕捉ng-include错误,当哈希中没有模板文件时。有人可以帮我吗?谢谢!


与您的问题无关,但最好不要在元素中包含 ng-animate 类。当 Angular 执行其进入/离开动画时,这会自动添加(+删除),因此可能会导致稍微不可预测的行为。 - Michal Charemza
1个回答

13

查看ngInclude的源代码,似乎没有钩子或直接检测模板不存在时出现的404(或其他)错误的方法。您可以考虑发起功能请求以添加此功能,因为这听起来是一个有用的功能。

然而,现在您可以使用http响应拦截器来解决问题。如果有一种方法可以告诉http请求是否为模板,比如它在“content”目录中,您可以拦截错误,并对其进行处理。例如,您可以用自定义指令替换数据,然后发出事件,以便控制器可以对其作出响应。

拦截器可以编写如下:

app.config(function ($httpProvider) {
    $httpProvider.interceptors.push('templateInterceptor');
});

// register the interceptor as a service
app.factory('templateInterceptor', function($q) {
  return {
    'responseError': function(rejection) {
       var isTemplate = !!rejection.config.url.match(/^content/g);
       if (isTemplate) {
         rejection.data = '<div><template-error url="\''+ (rejection.config.url) + '\'"><strong>Error from interceptor.</strong></template-error></div>';
         return rejection;
       } else {
         return $q.reject(rejection);
       }
    }
  }
});

当从“content”指令中获取内容后出现错误时,它会在模板内容的位置添加一个元素<template-error>。当编译并链接时,它将发出自定义事件templateError,父控制器可以通过$scope.$on来响应该事件。因此,可以这样编写指令:

app.directive('templateError', function() {
  return {
    restrict: 'E',
    scope: {
      'url': '='
    },
    link: function(scope) {
      scope.$emit('templateError', {url:scope.url});
    }
  };
});

然后在原始的ngInclude的父控制器中,您可以对此事件作出反应:

$scope.$on('templateError', function(e, data) {
  $scope.templateError = true;
  $scope.templateErrorUrl = data.url;
})

你可以在这个 Plunker中看到完整的工作代码。虽然我认为这有点狡猾,但如果Angular团队决定向ngInclude的代码中添加一个$emit事件,在出现错误时,那么只需删除拦截器/自定义元素即可。

看起来你的方案可以解决我的问题,我稍后会试一下。非常感谢:) - Tyler.z.yang
当加载ng-view模板时,我可以假设相同的解决方案适用吗? - Ruben Decrop
@ruben 我不知道为什么不行... 你可以尝试一下看看 :-) - Michal Charemza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接