- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在编写一个函数,可以根据 HTML 模板和给定的一些信息创建电子邮件模板。为此,我使用 Angular 的 $compile
函数。
只有一个问题我似乎无法解决。该模板由一个基本模板和无限量的 ng-include
组成。当我使用“最佳实践”$timeout
( advised here ) 时,它在我删除所有 ng-include
时起作用。所以这不是我想要的。
$超时示例:
return this.$http.get(templatePath)
.then((response) => {
let template = response.data;
let scope = this.$rootScope.$new();
angular.extend(scope, processScope);
let generatedTemplate = this.$compile(jQuery(template))(scope);
return this.$timeout(() => {
return generatedTemplate[0].innerHTML;
});
})
.catch((exception) => {
this.logger.error(
TemplateParser.getOnderdeel(process),
"Email template creation",
(<Error>exception).message
);
return null;
});
当我开始向模板添加 ng-include
时,此函数开始返回尚未完全编译的模板(解决方法是嵌套 $timeout
函数).我相信这是因为 ng-include
的异步特性。
工作代码
此代码在完成渲染后返回 html 模板(现在可以重用函数,see this question for the problem)。但是这个解决方案是一个大问题,因为它使用 Angular 私有(private) $$phase
来检查是否有任何正在进行的 $digest
。所以我想知道是否还有其他解决方案?
return this.$http.get(templatePath)
.then((response) => {
let template = response.data;
let scope = this.$rootScope.$new();
angular.extend(scope, processScope);
let generatedTemplate = this.$compile(jQuery(template))(scope);
let waitForRenderAndPrint = () => {
if (scope.$$phase || this.$http.pendingRequests.length) {
return this.$timeout(waitForRenderAndPrint);
} else {
return generatedTemplate[0].innerHTML;
}
};
return waitForRenderAndPrint();
})
.catch((exception) => {
this.logger.error(
TemplateParser.getOnderdeel(process),
"Email template creation",
(<Error>exception).message
);
return null;
});
我想要什么
我希望有一个功能可以处理无限量的 ng-inlude
,并且只在成功创建模板时返回。我没有渲染这个模板,需要返回完全编译的模板。
解决方案
在尝试@estus 的回答后,我终于找到了另一种检查 $compile 何时完成的方法。这导致了下面的代码。我使用 $q.defer()
的原因是模板是在事件中解析的。因此,我无法像正常 promise 那样返回结果(我无法执行 return scope.$on()
)。这段代码中唯一的问题是它严重依赖于 ng-include
。如果您为该函数提供一个没有 ng-include
的模板,则永远不会解析 $q.defer
。
/**
* Using the $compile function, this function generates a full HTML page based on the given process and template
* It does this by binding the given process to the template $scope and uses $compile to generate a HTML page
* @param {Process} process - The data that can bind to the template
* @param {string} templatePath - The location of the template that should be used
* @param {boolean} [useCtrlCall=true] - Whether or not the process should be a sub part of a $ctrl object. If the template is used
* for more then only an email template this could be the case (EXAMPLE: $ctrl.<process name>.timestamp)
* @return {IPromise<string>} A full HTML page
*/
public parseHTMLTemplate(process: Process, templatePath: string, useCtrlCall = true): ng.IPromise<string> {
let scope = this.$rootScope.$new(); //Do NOT use angular.extend. This breaks the events
if (useCtrlCall) {
const controller = "$ctrl"; //Create scope object | Most templates are called with $ctrl.<process name>
scope[controller] = {};
scope[controller][process.__className.toLowerCase()] = process;
} else {
scope[process.__className.toLowerCase()] = process;
}
let defer = this.$q.defer(); //use defer since events cannot be returned as promises
this.$http.get(templatePath)
.then((response) => {
let template = response.data;
let includeCounts = {};
let generatedTemplate = this.$compile(jQuery(template))(scope); //Compile the template
scope.$on('$includeContentRequested', (e, currentTemplateUrl) => {
includeCounts[currentTemplateUrl] = includeCounts[currentTemplateUrl] || 0;
includeCounts[currentTemplateUrl]++; //On request add "template is loading" indicator
});
scope.$on('$includeContentLoaded', (e, currentTemplateUrl) => {
includeCounts[currentTemplateUrl]--; //On load remove the "template is loading" indicator
//Wait for the Angular bindings to be resolved
this.$timeout(() => {
let totalCount = Object.keys(includeCounts) //Count the number of templates that are still loading/requested
.map(templateUrl => includeCounts[templateUrl])
.reduce((counts, count) => counts + count);
if (!totalCount) { //If no requests are left the template compiling is done.
defer.resolve(generatedTemplate.html());
}
});
});
})
.catch((exception) => {
defer.reject(exception);
});
return defer.promise;
}
最佳答案
$compile
是同步 函数。它只是同步编译给定的 DOM,并不关心嵌套指令中发生了什么。如果嵌套指令具有异步加载的模板或其他阻止其内容在同一时刻可用的东西,则这不是父指令的问题。
由于数据绑定(bind)和 Angular 编译器的工作方式,没有明显的时刻可以将 DOM 视为肯定“完整”,因为变化可能在任何地方、任何时间发生。 ng-include
也可能涉及绑定(bind),并且包含的模板可能随时更改和加载。
这里的实际问题是没有考虑以后如何管理的决定。使用随机模板的 ng-include
可以用于原型(prototype)制作,但会导致设计问题,这就是其中之一。
处理这种情况的一种方法是确定涉及哪些模板;设计良好的应用程序不能在其部分上过于松散。实际的解决方案取决于此模板的来源以及它包含随机嵌套模板的原因。但想法是,使用过的模板应该在使用前放入模板缓存中。这可以通过 gulp-angular-templates
等构建工具来完成。或者通过在 ng-include
编译之前使用 $templateRequest
进行请求(本质上是执行 $http
请求并将其放入 $templateCache
) - $templateRequest
基本上就是 ng-include
所做的。
虽然 $compile
和 $templateRequest
在模板被缓存时是同步的,但是 ng-include
不是——它在下一次被完全编译打勾,即零延迟的 $timeout
(a plunk ):
var templateUrls = ['foo.html', 'bar.html', 'baz.html'];
$q.all(templateUrls.map(templateUrl => $templateRequest(templateUrl)))
.then(templates => {
var fooElement = $compile('<div><ng-include src="\'foo.html\'"></ng-include></div>')($scope);
$timeout(() => {
console.log(fooElement.html());
})
});
通常,将模板用于缓存是消除 Angular 模板为编译生命周期带来的异步性的首选方法 - 不仅适用于 ng-include
,而且适用于任何指令。
另一种方法是使用 ng-include
events .这样,应用程序变得更加松散和基于事件(有时这是一件好事,但大多数时候不是)。由于每个 ng-include
都会发出一个事件,因此需要对事件进行计数,当它们被计数时,这意味着 ng-include
指令的层次结构已被完全编译(一个 plunk ):
var includeCounts = {};
var fooElement = $compile('<div><ng-include src="\'foo.html\'"></ng-include></div>')($scope);
$scope.$on('$includeContentRequested', (e, currentTemplateUrl) => {
includeCounts[currentTemplateUrl] = includeCounts[currentTemplateUrl] || 0;
includeCounts[currentTemplateUrl]++;
})
// should be done for $includeContentError as well
$scope.$on('$includeContentLoaded', (e, currentTemplateUrl) => {
includeCounts[currentTemplateUrl]--;
// wait for a nested template to begin a request
$timeout(() => {
var totalCount = Object.keys(includeCounts)
.map(templateUrl => includeCounts[templateUrl])
.reduce((counts, count) => counts + count);
if (!totalCount) {
console.log(fooElement.html());
}
});
})
请注意,这两个选项都只会处理由异步模板请求引起的异步性。
关于javascript - 如何检查 $compile 是否已经完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44492990/
我有一个 if 语句,如下所示 if (not(fullpath.lower().endswith(".pdf")) or not (fullpath.lower().endswith(tup
然而,在 PHP 中,可以: only appears if $foo is true. only appears if $foo is false. 在 Javascript 中,能否在一个脚
XML有很多好处。它既是机器可读的,也是人类可读的,它具有标准化的格式,并且用途广泛。 它也有一些缺点。它是冗长的,不是传输大量数据的非常有效的方法。 XML最有用的方面之一是模式语言。使用模式,您可
由于长期使用 SQL2000,我并没有真正深入了解公用表表达式。 我给出的答案here (#4025380)和 here (#4018793)违背了潮流,因为他们没有使用 CTE。 我很欣赏它们对于递
我有一个应用程序: void deleteObj(id){ MyObj obj = getObjById(id); if (obj == null) { throw n
我的代码如下。可能我以类似的方式多次使用它,即简单地说,我正在以这种方式管理 session 和事务: List users= null; try{ sess
在开发J2EE Web应用程序时,我通常会按以下方式组织我的包结构 com.jameselsey.. 控制器-控制器/操作转到此处 服务-事务服务类,由控制器调用 域-应用程序使用的我的域类/对象 D
这更多是出于好奇而不是任何重要问题,但我只是想知道 memmove 中的以下片段文档: Copying takes place as if an intermediate buffer were us
路径压缩涉及将根指定为路径上每个节点的新父节点——这可能会降低根的等级,并可能降低路径上所有节点的等级。有办法解决这个问题吗?有必要处理这个吗?或者,也许可以将等级视为树高的上限而不是确切的高度? 谢
我有两个类,A 和 B。A 是 B 的父类,我有一个函数接收指向 A 类型类的指针,检查它是否也是 B 类型,如果是将调用另一个函数,该函数接受一个指向类型 B 的类的指针。当函数调用另一个函数时,我
有没有办法让 valgrind 使用多个处理器? 我正在使用 valgrind 的 callgrind 进行一些瓶颈分析,并注意到我的应用程序中的资源使用行为与在 valgrind/callgrind
假设我们要使用 ReaderT [(a,b)]超过 Maybe monad,然后我们想在列表中进行查找。 现在,一个简单且不常见的方法是: 第一种可能性 find a = ReaderT (looku
我的代码似乎有问题。我需要说的是: if ( $('html').attr('lang').val() == 'fr-FR' ) { // do this } else { // do
根据this文章(2018 年 4 月)AKS 在可用性集中运行时能够跨故障域智能放置 Pod,但尚不考虑更新域。很快就会使用更新域将 Pod 放入 AKS 中吗? 最佳答案 当您设置集群时,它已经自
course | section | type comart2 : bsit201 : lec comart2 :
我正在开发自己的 SDK,而这又依赖于某些第 3 方 SDK。例如 - OkHttp。 我应该将 OkHttp 添加到我的 build.gradle 中,还是让我的 SDK 用户包含它?在这种情况下,
随着 Rust 越来越充实,我对它的兴趣开始激起。我喜欢它支持代数数据类型,尤其是那些匹配的事实,但是对其他功能习语有什么想法吗? 例如标准库中是否有标准过滤器/映射/归约函数的集合,更重要的是,您能
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 关闭 9 年前。 Improve
我一直在研究 PHP 中的对象。我见过的所有示例甚至在它们自己的对象上都使用了对象构造函数。 PHP 会强制您这样做吗?如果是,为什么? 例如: firstname = $firstname;
...比关联数组? 关联数组会占用更多内存吗? $arr = array(1, 1, 1); $arr[10] = 1; $arr[] = 1; // <- index is 11; does the
我是一名优秀的程序员,十分优秀!