让我们从了解为什么原始代码不起作用开始。我已经稍微简化了原始问题以使其更清楚:
angular.module('angularApp').filter('pathToName', function(Service) {
return function(input) {
return Service.getCorresp().then(function(response) {
return response;
});
});
}
基本上,过滤器调用一个异步函数来返回承诺,然后返回它的值。角度过滤器希望您返回一个可以轻松打印的值,例如字符串或数字。然而,在这种情况下,即使我们似乎返回了 getCorresp 的 response,我们实际上返回了一个 新的承诺 - 返回值任何then() 或catch() 函数都是promise。
Angular 正在尝试通过强制转换将一个 Promise 对象转换为一个字符串,但没有得到任何合理的回报并显示一个空字符串。
所以我们需要做的是,返回一个临时的 string 值并异步更改它,如下所示:
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 尝试执行过滤器时,它都会检查翻译是否已经被提取,如果没有,它会返回“正在加载...”值。我们还使用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;
});