9

我发现您可以使用 template 或 templateUrl 作为这样的功能

.when('/:controller/:action',{
   templateUrl:function(params){
     return: '/'+params.controller+'/'+params.action
  }
})

然后我想知道是否可以延迟加载模板,但我无法做到这一点

.when('/:ctrl/:action',{
   template:function(params){
      injector = angular.injector(['ng']);
      $q = injector.get('$q');
      var dfrd = $q.defer();

      // fetch template from server
      // dfrd.resolve()

      return dfrd.promise;      
   }
});

请告诉我有一种方法 - 我想通过向服务器发出 ajax 请求来获取整个模板

4

5 回答 5

19

所以,我看到你是一个 .NET MVC 开发人员......

让我们看一下 Actions 在 .NET MVC 中做了什么:它们返回 ActionResults……这确实是应该运行并从体系结构返回的视图和模型的清单。MVC 中的“控制器”是此类操作的集合,并且可能包含这些操作之间的一些共享逻辑,这些逻辑以私有方法或对该类的共享依赖项的形式存在。

现在让我们看看 Angular 在做什么:Angular 有一次调用控制器函数,作为构造函数,通常是为了设置一个 $scope 对象,该对象将充当(某种)作为你的“模型”。Angular 中的每个控制器(一般来说)都与一种且唯一一种设置 $scope** 的方法相关联。一旦该控制器被处理,$digest 会在它改变的 $scope 上调用,然后将其应用于绑定到范围的视图......这是由元素与您的 ng-controller 封装的 html(或ng-view) 属性。

所以..问题,你可以根据路由参数动态加载模板吗?是的。你绝对可以。最简单的方法是将您的请求路由到一个模板,该模板只包含一个ng-include您更改的 div 和一个模板。

在您的路线中:

$routeProvider.when('/:controller/:action', { 
    controller: 'DynamicCtrl', 
    template: '<div ng-include="include"></div>' 
});

然后你的动态控制器声明:

app.controller('DynamicCtrl', function($scope, $routeParams) {
    $scope.include = $routeParams.controller + '/' + $routeParams.action;
});

MyController/MyAction(我假设您可能使用 Razor 生成)应该返回如下内容:

<div ng-controller="MyActionCtrl">
   do stuff!
</div>

...从那里您将自己定义 MyActionCtrl 控制器。

你能弯曲架构使其成为“ASP.Net MVC-esque”,因为“一个控制器”中有一大堆“动作”函数来决定你的视图的整个行为吗?是的......但不是没有让你的应用程序真的很傻,使用 switch 语句等......所以你可能不想这样做。

最后,您将不得不摆脱 ASP.Net MVC 使用 Angular 的“控制器和动作”的思维定势。这是一个 MVC 架构,但是 MVC != "Controllers && actions"。


** Angular 也会创建控制器实例并将其保存为对象,但该功能在 Angular 开发中很少使用,而且我在这里不谈论它。)

于 2013-06-20T21:54:13.223 回答
3

正如所指出的,由 templateUrl 加载的模板在正常情况下将被延迟加载,如果您需要非标准的东西,还有一些方法可以使用缓存。

这条评论似乎是问题的症结所在:

我想通过向服务器发出 ajax 请求来获取整个模板

这不一定是使用 Angular 的正常方式。它可以有它的用处,但它是人迹罕至的。通常模板不受上下文敏感的所有内容的影响,因为它们表示从 $scope 或某种参数获取其关键状态信息的代码。那么为什么要使用ajax?

您的模板想要/需要来自 ajax 请求的什么?该问题的答案可能有助于最终决定如何在正确的地方最有效地实现这一目标。

可能是您希望或需要一些服务器端动态作为系统的一部分,或者除了让 ajax 返回定义模板之外,还有其他方法可以做到这一点。

更新:所以你说过“在路由更改时,我需要从服务器获取模板,异步使用 $http”。但这都是 templateUrl 内置的。@wmluke 似乎提出了一些有趣的替代方案。

如果我们只是接受您需要 ajax 来获取您的模板,那么这里还有另一种可能性。使用ui-router您可以使用 templateProvider - 它可以调用您自己的自定义服务来执行 ajax 以及您想要的任何其他内容。

这个例子只是异步返回 Hello world,但是你可以在这里调用你自己的服务,或者如果你想直接执行 ajax 请求。

templateProvider:
 [        '$timeout',
  function ($timeout) {
   return $timeout(function () { return "Hello world" }, 100);
 }],

购买 ui-router 是一个潜在的更大的承诺,但它可能会产生比仅仅能够编写代码来生成模板的回报。祝你好运!

于 2013-06-20T21:58:14.697 回答
2

为什么不templateURL一起绕过并让您的控制器拦截请求?

  • 您将能够通过 URL 动态延迟加载页面

  • 可选择截取部分。

配置.js

$routeProvider.when('/contact', {
  template: '/views/contact.html'
});

控制器.js

controller('AppController', ['$scope' function($scope) {    
  //Do whatever you want here
  $scope.$on("$routeChangeSuccess",function( $currentRoute, $previousRoute ){
    console.log($route.current.template);
    $scope.page = $route.current.template;
  });

  //Optionally intercept partials
  $scope.returnView = function(partial){
    console.log(partial);
    return partial;
  }  
}]).

索引.html

<html lang="en" ng-app="myApp" ng-controller="AppController">
<body>
<ng-include src="returnView('/views/global.header.html')"></ng-include>
<ng-include src="page"></ng-include>
<ng-include src="returnView('/views/global.footer.html')"></ng-include>
</body>
</html>
于 2013-06-23T15:56:07.657 回答
1

默认情况下,Angular 模板是延迟加载的。具体来说,在需要模板之前不会获取模板,然后将它们缓存在$templateCache中。

但是,根据您的示例,我怀疑您正在$routeProviderresolve中寻找路由定义的属性。此属性允许您将承诺依赖项传递给控制器​​。请参阅$route中的延迟示例...

$routeProvider.when('/Book/:bookId', {
    templateUrl: 'book.html',
    controller: BookCntl,
    resolve: {
        // I will cause a 1 second delay
        delay: function($q, $timeout) {
            var delay = $q.defer();
            $timeout(delay.resolve, 1000);
            return delay.promise;
        }
    }
});

此外,您可能有兴趣预加载一些模板但延迟加载其他模板。在这种情况下,您应该检查...

于 2013-06-20T19:29:38.210 回答
0

您可以在角度文档站点ngInclude-Example Paragraph上看到基于参数动态加载的两个模板的工作示例。

这是Plunker 示例

<!-- index.html -->
<select ng-model="template" ng-options="t.name for t in templates">
    <option value="">(blank)</option>
</select>
<div class="slide-animate" ng-include="template.url"></div>


// controller
$scope.templates = [ 
    { name: 'template1.html', url: 'template1.html'},
    { name: 'template2.html', url: 'template2.html'} 
];
$scope.template = $scope.templates[0];
于 2015-06-15T11:15:24.920 回答