2014-01-17 102 views
4

我希望能够从promise加载指令的模板。例如加载角度指令模板异步

template: templateRepo.get('myTemplate') 

templateRepo.get返回一个承诺,即在解析时将模板的内容包含在字符串中。

任何想法?

回答

13

你可以加载指令中的HTML应用到你的元素和编译。

.directive('myDirective', function ($compile) { 
    return { 
     restrict: 'A', 
     link: function (scope, element, attrs) { 
      //Some arbitrary promise. 
      fetchHtml() 
      .then(function(result){ 
       element.html(result); 
       $compile(element.contents())(scope); 
       }, function(error){ 

       }); 
     } 
    } 
}); 
+0

嘿罗布任何机会,你可以解释为什么这种情况? – prasanthv

2

这是一个非常有趣的问题,它带有不同复杂性的几个答案。正如其他人已经建议的那样,您可以将指令加载到指令中,并且在加载模板时将被替换。

看到,因为你想更通用的负荷指标的解决方案,应该适用于其他的事情,我建议:

  1. 创建通用服务控制指标与。
  2. 手动加载链接函数中的模板,根据请求显示指示符发送和隐藏响应。

这里是非常简单的例子,你可以开始:

<button ng-click="more()">more</button> 
<div test="item" ng-repeat="item in items"></div> 
.throbber { 
    position: absolute; 
    top: calc(50% - 16px); 
    left: calc(50% - 16px); 
} 
angular 
.module("app", []) 
.run(function ($rootScope) { 
    $rootScope.items = ["One", "Two"]; 
    $rootScope.more = function() { 
     $rootScope.items.push(Math.random()); 
    }; 
}) 
.factory("throbber", function() { 
    var visible = false; 
    var throbber = document.createElement("img"); 
    throbber.src = "http://upload.wikimedia.org/wikipedia/en/2/29/Throbber-Loadinfo-292929-ffffff.gif"; 
    throbber.classList.add("throbber"); 
    function show() { 
     document.body.appendChild(throbber); 
    } 
    function hide() { 
     document.body.removeChild(throbber); 
    } 
    return { 
     show: show, 
     hide: hide 
    }; 
}) 
.directive("test", function ($templateCache, $timeout, $compile, $q, throbber) { 
    var template = "<div>{{text}}</div>"; 
    var templateUrl = "templateUrl"; 

    return { 
     link: function (scope, el, attr) { 
      var tmpl = $templateCache.get(templateUrl); 

      if (!tmpl) { 
       throbber.show(); 
       tmpl = $timeout(function() { 
        return template; 
       }, 1000); 
      } 

      $q.when(tmpl).then(function (value) { 
       $templateCache.put(templateUrl, value); 
       el.html(value); 
       $compile(el.contents())(scope); 
       throbber.hide(); 
      }); 
     }, 
     scope: { 
      text: "=test" 
     } 
    }; 
}); 

JSBin example

在实时代码中,您必须将$timeout替换为$http.get(templateUrl),我用前者来说明异步加载。

如何模板载入作品在我的例子:

  1. 检查,如果有我们在$templateCache模板。
  2. 如果否,从URL获取并显示指示符。
  3. 手动将模板放入元素内部并且[$compile][2]它。
  4. 隐藏指标。

如果你不知道什么是$templateCacheread the docs。 AngularJS默认使用templateUrl,所以我也这样做了。

模板加载可能会移动到装饰器,但我缺乏相关经验。这将进一步分离担忧,因为指令不需要了解指示器,并摆脱了样板代码。

我也添加了ng-repeatrun东西来演示如果模板已经加载,它不触发指标。

-1
```` 
/** 
* async load template 
* eg : 
* <div class="ui-header"> 
*  {{data.name}} 
*  <ng-transclude></ng-transclude> 
* </div> 
*/ 
Spa.Service.factory("RequireTpl", [ 
    '$q', 
    '$templateCache', 
    'DataRequest', 
    'TplConfig', 
function(
    $q, 
    $templateCache, 
    DataRequest, 
    TplConfig 
) { 
    function getTemplate(tplName) { 
     var name = TplConfig[tplName]; 
     var tpl = ""; 
     if(!name) { 
      return $q.reject(tpl); 
     } else { 
      tpl = $templateCache.get(name) || ""; 
     } 
     if(!!tpl) { 
      return $q.resolve(tpl); 
     } 
     //加载还未获得的模板 
     return new $q(function(resolve, reject) { 
      DataRequest.get({ 
       url : "/template/", 
       action : "components", 
       responseType : "text", 
       components : name 
      }).success(function(tpl) { 
       $templateCache.put(name, tpl); 
       resolve(tpl); 
      }).error(function() { 
       reject(null); 
      }); 
     }); 
    } 
    return getTemplate; 
}]); 
/** 
* usage: 
* <component template="table" data="info"> 
*  <span>{{info.name}}{{name}}</span> 
* </component> 
*/ 
Spa.Directive.directive("component", [ 
    "$compile", 
    "RequireTpl", 
function(
    $compile, 
    RequireTpl 
) { 
    var directive = { 
     restrict : 'E', 
     scope : { 
      data : '=' 
     }, 
     transclude : true, 
     link: function ($scope, element, attrs, $controller, $transclude) { 
      var linkFn = $compile(element.contents()); 
      element.empty(); 
      var tpl = attrs.template || ""; 
      RequireTpl(tpl) 
      .then(function(rs) { 
       var tplElem = angular.element(rs); 
       element.replaceWith(tplElem); 
       $transclude(function(clone, transcludedScope) { 
        if(clone.length) { 
         tplElem.find("ng-transclude").replaceWith(clone); 
         linkFn($scope); 
        } else { 
         transcludedScope.$destroy() 
        } 
        $compile(tplElem.contents())($scope); 
       }, null, ""); 
      }) 
      .catch(function() { 
       element.remove(); 
       console.log("%c component tpl isn't exist : " + tpl, "color:red") 
      }); 
     } 
    }; 
    return directive; 
}]); 
```` 
+0

请也描述你的答案,不只是发布一些代码。 –