Hãy bắt đầu với sự hiểu biết tại sao mã gốc không hoạt động. Tôi đã đơn giản hóa câu hỏi ban đầu một chút để làm cho nó rõ ràng hơn:
angular.module('angularApp').filter('pathToName', function(Service) {
return function(input) {
return Service.getCorresp().then(function(response) {
return response;
});
});
}
Về cơ bản, bộ lọc gọi hàm async trả về lời hứa, sau đó trả về giá trị của nó. Bộ lọc trong góc dự kiến bạn trả về một giá trị có thể in dễ dàng, ví dụ: chuỗi hoặc số. Tuy nhiên, trong trường hợp này, mặc dù nó có vẻ như chúng ta đang trả lại response
của getCorresp
, chúng tôi đang thực sự trả lại một lời hứa mới - Giá trị trả về của bất kỳ then()
hoặc catch()
chức năng là một lời hứa .
Góc đang cố gắng chuyển đổi đối tượng lời hứa thành chuỗi thông qua truyền, không nhận được gì hợp lý để trả lại và hiển thị chuỗi rỗng.
Vì vậy, những gì chúng ta cần làm là, trả lại một tạm thời chuỗi giá trị và thay đổi nó asynchroniously, như vậy:
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;
});
Mỗi lần Angular cố thực thi bộ lọc, nó sẽ kiểm tra xem bản dịch đã được tải chưa và nếu không, nó sẽ trả về giá trị "Đang tải ...". Chúng tôi cũng sử dụng giá trị isWaiting
để ngăn việc gọi dịch vụ nhiều lần.
Ví dụ ở trên hoạt động tốt cho Angular 1.2, tuy nhiên, trong số các thay đổi trong Góc 1.3, có cải thiện hiệu suất làm thay đổi hành vi của bộ lọc. Trước đây, chức năng lọc được gọi là mỗi chu kỳ tiêu hóa. Tuy nhiên, kể từ 1.3, nó chỉ gọi bộ lọc nếu giá trị được thay đổi, trong mẫu cuối cùng của chúng tôi, nó sẽ không bao giờ gọi lại bộ lọc - 'WelcomeTo'
sẽ không bao giờ thay đổi.
May mắn việc sửa chữa rất đơn giản, bạn sẽ chỉ cần thêm vào các bộ lọc như sau:
JSFiddle
myFilter.$stateful = true;
Cuối cùng, trong khi đối phó với vấn đề này, tôi có vấn đề khác - Tôi cần sử dụng bộ lọc để nhận các giá trị không đồng bộ mà có thể thay đổi - Cụ thể, tôi cần tìm nạp bản dịch cho một ngôn ngữ, nhưng sau khi người dùng đã thay đổi ngôn ngữ, tôi cần tìm nạp bộ ngôn ngữ mới. Làm điều đó, tỏ ra phức tạp hơn một chút, mặc dù khái niệm là như nhau. Đây là mã rằng:
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;
});
Còn bây giờ các bộ lọc fetchs dữ liệu correspondance, và đặt nó trong một var bên trong bộ lọc. Cuộc chiến này sau đó được sử dụng để dịch những thứ. Điều này không hoàn hảo, nếu phản hồi của máy chủ mất nhiều thời gian, bộ lọc sẽ không có dữ liệu sửa đổi, trong trường hợp đó nó không dịch. – Davounet
Bạn có thể trả lời lời hứa về chức năng: http://docs.angularjs.org/api/ng.$q –