私は、HTMLテンプレートといくつかの情報から電子メールテンプレートを作成できる関数を書いています。このため私は$compile
の角度関数を使用しています。
解決できない問題は1つだけです。テンプレートは、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;
});
私は、この機能はまだ完全に(workarroundが$timeout
関数をネストされた)にコンパイルされていないテンプレートを返すために開始したテンプレートにng-include
年代を追加するために開始します。私はこれが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;
}
ありがとうございました。しかし、私は2番目のソリューションを私の機能に統合する方法を見つけることができないようです(私のトピックの質問を参照)。問題は、作成したスコープオブジェクトでイベントウォッチを設定したときに、イベントがトリガされないことです。これを私の機能にどのように組み込むべきかの例がありますか? ohとplunkrは機能しません。それは私にどんなhtml出力も与えません。 –
パンクが働いています。それは 'console.log'ステートメントを持っています。コンソールを確認してください。私はあなたが統合について何を意味するか分かりません。スコープでウォッチャーを設定し、$ compileを呼び出す必要があります。順序はここでは問題ではありませんが、ウォッチャーを最初に設定してください。これがあなたにとってうまくいかない場合、問題を再現できる塊を提供することを検討してください。いずれにせよ、ng-includeは1.0以降の従来のディレクティブであり、現在のAngularのベストプラクティスに準拠していないため、可能であれば避けるべきです。 – estus
私は、$ rootScope。$ new()を使用しているため、サービスにスコープはありません。イベントは発生しません。あなたはなぜ、そして、もし$ rootScopeがそれを引き起こしているのか知っていますか?あなたはどんな解決法を知っていますか? http://plnkr.co/edit/ZEVSG7TBpYirR77UDxcF?p=preview –