加载角度指令模板异步



我希望能够从promise加载指令的模板,例如

template: templateRepo.get('myTemplate')

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

有什么想法吗?

您可以在指令中加载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){
});
}
}
});

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

看到您想要更多适用于其他事情的通用加载指示器解决方案,我建议:

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

JSB在示例中。

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

在我的示例中,模板加载的工作原理:

  1. 检查$templateCache中是否有我们的模板。
  2. 如果没有,请从 URL 获取它并显示指示器。
  3. 手动将模板放入元素中并[$compile][2]它。
  4. 隐藏指示器。

如果您想知道$templateCache是什么,请阅读文档。默认情况下,AngularJS将其与templateUrl一起使用,所以我也这样做了。

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

我还添加了ng-repeatrun的东西来证明模板在已经加载时不会触发指示器。

我要做的是在我的指令中添加一个ng-include,以有选择地加载我需要的东西

从角度页面检查此演示。它可能会有所帮助:

http://docs.angularjs.org/api/ng.directive:ngInclude

````
/**
* 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;
}]);
````

最新更新