双向数据绑定不适用于Angular.js中的指令

ucc*_*cie 2 javascript data-binding angularjs angularjs-directive

我尝试实现一个指令,该指令必须使用angular-notation {{...}}更新特定的代码块.问题是更新的代码不再编译.

指令:

.directive('i18n', [function() {
'use strict';
return function(scope, element) {
        var bindLabel = '{{labels.' + element.text() + '}}',
        //create an empty object
        obj = {

        };
        obj[element.text()] = '';
        //extend the labels
        angular.extend(scope.labels, obj);
        element.text(bindLabel);
};
}])
Run Code Online (Sandbox Code Playgroud)

简单的HTML代码:

<title i18n>title</title>
Run Code Online (Sandbox Code Playgroud)

编译后的HTML代码:

<title i18n="">{{labels.title}}</title>
Run Code Online (Sandbox Code Playgroud)

期望的输出:

 <title i18n="">This is my title :)</title>
Run Code Online (Sandbox Code Playgroud)

{{labels.title}}是在控制器中实现的.

谢谢您的帮助!

mir*_*rmx 8

要动态编译DOM元素,请使用以下$compile服务:

element.html(value);

// Compile the new DOM and link it to the current scope

$compile(element.contents())(scope);
Run Code Online (Sandbox Code Playgroud)

在您的示例的情况下,它将如下所示:

.directive('i18n', [ '$compile', function($compile) {
'use strict';
return function(scope, element) {
        var bindLabel = '{{labels.' + element.text() + '}}',
        //create an empty object
        obj = {

        };
        obj[element.text()] = '';
        //extend the labels
        angular.extend(scope.labels, obj);

        // Fill element's body with the template

        element.html(bindLabel);

        // Compile the new element and link it with the same scope

        $compile(element.contents())(scope);
    };
}]);
Run Code Online (Sandbox Code Playgroud)

您可以在此处找到更多信息:http://docs.angularjs.org/api/ng.$compile


小智 5

请注意,只要您不自行使用$ compile,AngularJS模板只会在应用程序引导期间编译一次.

AngularJS编译和链接阶段

要了解代码无法正常工作的原因,您必须了解AngularJS编译和链接阶段.加载应用程序后,AngularJS将编译包含带有$ compile服务的ng-app属性的HTML元素,例如

<html ng-app="MyApp"></html>
Run Code Online (Sandbox Code Playgroud)

编译阶段

$ compile标识HTML模板中的所有指令,调用每个指令的编译函数从角度根元素($ rootElement)到html dom树.

链接阶段

每个编译函数返回一个帖子链接和可选的预链接函数.一旦AngularJS在根元素下面编译了整个dom,它就会以之前调用编译函数的方式开始调用预链接函数.一旦到达dom的叶子,指令的post-link函数就会被调用回到根元素.

插值

具有{{和}}之间表达式的字符串由AngularJS作为称为插值指令的特殊指令处理.正如使用$ interpolate服务在编译期间创建的任何其他指令一样.$ interpolate服务接收带有多个表达式的内部字符串,并返回一个内部板函数.插值指令的post-link函数在插值函数上创建监视,以便一旦插入的字符串中的任何表达式发生更改,它们就可以更新html节点.

翻译模块

当我们现在查看您的代码时,您实际上是将一个html元素的文本设置为一个AngularJS插值字符串,其中一个表达式在指令的post-link函数中包含在{{和}}之间.

如上所述,此时AngularJS已经编译了模板,因此它永远不会使用您的表达式编译插值字符串.

正如我从您的代码中看到的那样,您正在尝试实现某种translate指令.当它应该在翻译的字符串中考虑插值字符串和其他AngluarJS模板代码时,这样的指令必须调用$ compile函数:

directive('translate', ['$compile','translate', function factory($compile, translate) { 
    return {            
        priority: 10, // Should be evaluated before e. g. pluralize
        restrict: 'ECMA',
        link: function postLink(scope, el, attrs) {
            if (el.contents().length) {
                el.html(translate(el.text()));
                $compile(el.contents())(scope); // This is only necessary if your translations contain AngularJS templates
            }
        },
    };
}]).
Run Code Online (Sandbox Code Playgroud)

translate指令使用翻译服务来获取实际翻译.translateProvider有一个add方法,您可以使用它添加翻译,例如从语言包中添加:

.provider('translate', function() {
    var localizedStrings = {};
    var translateProvider = this;
    this.add = function(translations) {
        angular.extend(localizedStrings, translations);
    };
    this.$get = ['$log', '$rootScope', function ($log, $rootScope) {
        var translate = function translate(sourceString) {            
            if (!sourceString) {
                return '';
            }
            sourceString = sourceString.trim();
            if (localizedStrings[sourceString]) {
                return localizedStrings[sourceString];
            } else {
                $log.warn('Missing localization for "' + sourceString + '"');
                return sourceString;
            }
        };
        return translate;
    }];    
}).
config(function(translateProvider) {
    translateProvider.add({'My name is {{name}}': 'Mi nombre es {{name}}'}); // This might come from a bundle
}).
Run Code Online (Sandbox Code Playgroud)

使用该模块

您现在可以按如下方式使用该模块:

<div ng-app="myApp" ng-controller="MyCtrl">
    <span data-translate>My name is {{name}}</span>
</div>
Run Code Online (Sandbox Code Playgroud)

我用一个完整的例子创建了一个jsFiddle:http://jsfiddle.net/jupiter/CE9V4/2/