元のコードが機能しない理由を理解することから始めましょう。より明確にするために、元の質問を少し単純化しました。
angular.module('angularApp').filter('pathToName', function(Service) {
return function(input) {
return Service.getCorresp().then(function(response) {
return response;
});
});
}
基本的に、フィルターは promise を返す async 関数を呼び出してから、その値を返します。angular のフィルターは、文字列や数値など、簡単に印刷できる値を返すことを期待しています。response
ただし、この場合、 ofgetCorresp
を返しているように見えますが、実際には新しい promise をthen()
返しています。いずれかまたはcatch()
関数の戻り値はpromiseです。
Angular は、キャストによって promise オブジェクトを文字列に変換しようとしていますが、見返りとして何も得られず、空の文字列が表示されます。
したがって、次のように、一時的な文字列値を返し、非同期に変更する必要があります。
JSFiddle
HTML:
<div ng-app="app" ng-controller="TestCtrl">
<div>{{'WelcomeTo' | translate}}</div>
<div>{{'GoodBye' | translate}}</div>
</div>
Javascript:
app.filter("translate", function($timeout, translationService) {
var isWaiting = false;
var translations = null;
function myFilter(input) {
var translationValue = "Loading...";
if(translations)
{
translationValue = translations[input];
} else {
if(isWaiting === false) {
isWaiting = true;
translationService.getTranslation(input).then(function(translationData) {
console.log("GetTranslation done");
translations = translationData;
isWaiting = false;
});
}
}
return translationValue;
};
return myFilter;
});
Angular がフィルターを実行しようとするたびに、翻訳が既にフェッチされているかどうかを確認し、そうでない場合は "Loading..." 値を返します。また、この値を使用してisWaiting
、サービスが複数回呼び出されるのを防ぎます。
上記の例は Angular 1.2 で問題なく動作しますが、Angular 1.3 での変更の中で、フィルターの動作を変更するパフォーマンスの改善があります。以前は、フィルター関数はダイジェスト サイクルごとに呼び出されていました。ただし、1.3 以降では、値が変更された場合にのみフィルターが呼び出されます。最後のサンプルでは、フィルターが再度呼び出されることはあり'WelcomeTo'
ません。変更されることはありません。
幸いなことに、修正は非常に簡単です。フィルターに次を追加するだけです。
JSFiddle
myFilter.$stateful = true;
最後に、この問題に対処しているときに、別の問題が発生しました。フィルターを使用して、変更される可能性のある非同期値を取得する必要がありました。具体的には、単一の言語の翻訳を取得する必要がありましたが、ユーザーが言語を変更したら、新しい言語セットを取得します。コンセプトは同じですが、それを行うと、もう少しトリッキーであることがわかりました. これはそのコードです:
JSFiddle
var app = angular.module("app",[]);
debugger;
app.controller("TestCtrl", function($scope, translationService) {
$scope.changeLanguage = function() {
translationService.currentLanguage = "ru";
}
});
app.service("translationService", function($timeout) {
var self = this;
var translations = {"en": {"WelcomeTo": "Welcome!!", "GoodBye": "BYE"},
"ru": {"WelcomeTo": "POZHALUSTA!!", "GoodBye": "DOSVIDANYA"} };
this.currentLanguage = "en";
this.getTranslation = function(placeholder) {
return $timeout(function() {
return translations[self.currentLanguage][placeholder];
}, 2000);
}
})
app.filter("translate", function($timeout, translationService) {
// Sample object: {"en": {"WelcomeTo": {translation: "Welcome!!", processing: false } } }
var translated = {};
var isWaiting = false;
myFilter.$stateful = true;
function myFilter(input) {
if(!translated[translationService.currentLanguage]) {
translated[translationService.currentLanguage] = {}
}
var currentLanguageData = translated[translationService.currentLanguage];
if(!currentLanguageData[input]) {
currentLanguageData[input] = { translation: "", processing: false };
}
var translationData = currentLanguageData[input];
if(!translationData.translation && translationData.processing === false)
{
translationData.processing = true;
translationService.getTranslation(input).then(function(translation) {
console.log("GetTranslation done");
translationData.translation = translation;
translationData.processing = false;
});
}
var translation = translationData.translation;
console.log("Translation for language: '" + translationService.currentLanguage + "'. translation = " + translation);
return translation;
};
return myFilter;
});