AngularJS刷新插值

AngularJS refresh interpolated value

我想知道如何更新 Angular 模板中的插值 - 如果值本身没有改变。

我有这样的陈述(例如翻译):

<div>{{ 'SOME_TAG' | lang }}</div>

这将启动一个过滤器

app.filter('lang', function(Locale) {
    return function(val) {
        return Locale.translate(val);
    }
});

Locale 是一种具有字段 lang 的服务,这取决于将值翻译成不同的语言。当我更改此字段的值时,翻译的值也应更改。

类似

<select ng-model="lang" ng-change="changeLang()">
    <option value="de">Deutsch</option>
    <option value="en">English</option>
</select>

...

$scope.changeLang = function() {
    Locale.changeLanguage($scope.lang);
};

在较旧的 AngularJS 版本(例如 1.1.5,不确定有多远)中,这很好地完成了这个技巧。如果我更新 Locale.lang 值并运行 $digest() 循环,则会更新内插模板值。在最新版本(1.4.6 以及 1.3.xx)中,这不再有效。 我认为这是某些优化的一部分 - 值 ('SOME_TAG') 没有改变,所以为什么要重新运行插值。

我见过这个 http://angular-translate.github.io/ 它工作正常。 是否有 "trick" 来更新这些值?

谢谢。

我也对此感兴趣,所以研究了angular-翻译代码。

在他们的代码中,特别是在 src/service/translate.jssrc/filter/translate.js 中,您会看到他们跟踪插值 ID 并在 $translate.setLanguage() 之后更新插值对象。这确实是您的代码与他们的代码之间的唯一区别。

我的猜测是 angular 将在摘要周期和重新 运行 之间跟踪对插值对象的更改,尽管它们的上下文没有改变,但我不碰巧非常了解 angular 代码库,我可以证明这一点。这对我来说很有意义,因为除了 angular-translate 的代码之外,我没有看到任何 'trickery'。

在关于过滤器的 angular docs 中有一个叫做 stateful 的东西。添加它是为了提高过滤器的性能。

有一个非常好的blog post关于状态过滤器的详细描述。

简而言之,'SOME_TAG' 是一个字符串,永远不会改变,过滤器正在添加的 $watch 永远不会被调用。但是对于$stateful,它还会检查你的过滤器的注入依赖项是否有变化。

因此您需要 $stateful 或者您可以将您的语言范围变量传递给服务以使其正常工作。 我认为最好避免使用 $stateful 过滤器(如文档中所建议的那样),因为它们 运行 比没有过滤器更频繁。所以在这里通过语言范围会更好。

请查看下面或此 fiddle 中的演示。

angular.module('demoApp', [])
 .factory('Locale', Locale)
 .filter('langStateful', LangFilterState)
 .filter('lang', LangFilter)
 .controller('MainController', MainController);

function MainController($scope, $timeout, Locale) {
 $scope.changeLang = function() {
        Locale.changeLanguage($scope.lang);
    };
}

function LangFilter(Locale) {
    function LangFilter(val, lang) {
        return Locale.translateLang(val, lang);
    }
    
    return LangFilter;
}

function LangFilterState(Locale) {
    function LangFilter(val) {
        return Locale.translate(val);
    }
    
    LangFilter.$stateful = true;
    
    return LangFilter;
}

function Locale() {
 var localeFactory = {
        language: 'de',
        changeLanguage: changeLanguage,
        translate: translate,
        translateLang: translateLang,
        tags: {
            'title': {
             de: 'Titel',
                en: 'title'
            },
            'help': {
                de: 'Hilfe',
                en: 'help'
            }
        }
    };
    
    return localeFactory;
    
    function changeLanguage(lang) {
        this.language = lang;
    }
    
    function translate(tag) {
        return this.tags[tag][this.language];
    }
    
    function translateLang(tag, lang) {
        return this.tags[tag][lang];
    }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.js"></script>
<div ng-app="demoApp" ng-controller="MainController">
<select ng-model="lang" ng-change="changeLang()" ng-init="lang='de'">
    <option value="de">Deutsch</option>
    <option value="en">English</option>
</select>
    
    {{'help' | langStateful}}
    {{'title' | lang: lang}}
</div>