我正在寫一個函數,可以從HTML模板創建一個電子郵件模板並提供一些信息。爲此,我使用Angular的$compile
函數。
只有一個問題,我似乎無法解決。該模板包含一個無限量的基本模板ng-include
's。當我使用'最佳做法'$timeout
(advised here)它適用於我刪除所有ng-include
's。所以這不是我想要的。
的$超時例如:
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
的添加到這個功能開始返回尚未完全編譯模板(一workarround被嵌套$timeout
功能)的模板。我相信這是因爲ng-include
的異步性質。
工作代碼
此代碼返回,當它完成渲染(功能現在可以重複使用,see this question for the problem)HTML模板。但是這個解決方案是一個很大的問題,因爲它使用角度專用的$$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答案後試驗,我終於發現,當$編譯完成檢查的其他方式。這導致了下面的代碼。我使用$q.defer()
的原因是由於事件中模板已解決。由於這個原因,我不能像普通的承諾那樣返回結果(我不能這樣做)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;
}
謝謝你的回答。然而,我似乎無法找到將第二種解決方案整合到我的功能中的方法(請參閱我的主題問題)。問題是,當我在創建的作用域對象上設置事件監視時,事件從未觸發任何事件。你有一個例子,我應該如何將其整合到我的功能? 哦,你的plunkr不起作用。它不會給我任何html輸出。 –
龐克工程。它有'console.log'語句。檢查控制檯。我不確定你的整合意味着什麼。您需要在範圍上設置觀察者並調用$ compile,就是這樣。這裏的順序應該不重要,但是要先設置觀察者。考慮提供一個可以重新創建問題的plunk,如果這不適合你。無論如何,ng-include是1.0以來的傳統指令,如果可能的話應該避免,因爲它不符合當前的Angular最佳實踐。 – estus
我剛剛發現,由於我使用$ rootScope。$ new()(我在服務中沒有任何範圍)事件不會被觸發。你知道爲什麼,如果$ rootScope導致它,你知道任何解決方案嗎?請參閱http://plnkr.co/edit/ZEVSG7TBpYirR77UDxcF?p=preview –