[英]Two-way data binding does not work with directives in Angular.js
I try to implement a directive, which has to update specific code block with angular-notation {{...}}. 我尝试实现一个指令,它必须使用angular-notation {{...}}更新特定的代码块。 The problem is that the updated code is not compiled anymore. 问题是更新的代码不再编译。
The directive: 指令:
.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);
};
}])
Simple HTML code: 简单的HTML代码:
<title i18n>title</title>
HTML code after compilation: 编译后的HTML代码:
<title i18n="">{{labels.title}}</title>
Desired output: 期望的输出:
<title i18n="">This is my title :)</title>
The {{labels.title}}
is implemented in controller. {{labels.title}}
在控制器中实现。
Thank you for your help! 谢谢您的帮助!
To dynamically compile DOM elements use the $compile
service: 要动态编译DOM元素,请使用$compile
服务:
element.html(value);
// Compile the new DOM and link it to the current scope
$compile(element.contents())(scope);
In the case of your example it would look like this: 在您的示例的情况下,它将如下所示:
.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);
};
}]);
You can find more information here: http://docs.angularjs.org/api/ng.$compile 您可以在此处找到更多信息: http : //docs.angularjs.org/api/ng.$compile
Please not that AngularJS templates are only compiled once during application bootstrap as long as you don't use $compile on your own. 请注意,只要您不自行使用$ compile,AngularJS模板只会在应用程序引导期间编译一次。
To understand why your code is not working you must understand AngularJS compile and linking phases. 要了解代码无法正常工作的原因,您必须了解AngularJS编译和链接阶段。 Once you load your application AngularJS compiles the HTML element which contains a ng-app attribute with the $compile service, eg 加载应用程序后,AngularJS将编译包含带有$ compile服务的ng-app属性的HTML元素,例如
<html ng-app="MyApp"></html>
$compile identifies all directives in your HTML template calling each directive's compile function working its way up from your angular root element ($rootElement) through the html dom tree. $ compile标识HTML模板中的所有指令,调用每个指令的编译函数从角度根元素($ rootElement)到html dom树。
Each compile function returns a post linking and optionally a pre-linking function. 每个编译函数返回一个帖子链接和可选的预链接函数。 Once AngularJS has compiled the whole dom below the root element it starts to call the pre-link function in the same way has it has called the compile function before. 一旦AngularJS在根元素下面编译了整个dom,它就会以之前调用编译函数的方式开始调用预链接函数。 Once reached at the leaves of the dom the directive's post-link functions are called going back down to the root element. 一旦到达dom的叶子,指令的post-link函数就会被调用回到根元素。
Strings with expressions between {{ and }} are handled by AngularJS as special directives called interpolate directives. 具有{{和}}之间表达式的字符串由AngularJS作为称为插值指令的特殊指令处理。 Just as any other directive these are created during compilation using the $interpolate service. 正如使用$ interpolate服务在编译期间创建的任何其他指令一样。 The $interpolate service receives an interplated string with a number of expressions and returns an interplate function. $ interpolate服务接收带有多个表达式的内部字符串,并返回一个内部板函数。 The post-link function of the interpolate directives create a watch on the interpolate function so that they can update the html node once any expression in the interplated string changes. 插值指令的post-link函数在插值函数上创建监视,以便一旦插入的字符串中的任何表达式发生更改,它们就可以更新html节点。
When we now look at your code you are actually setting the text of an html element to an AngularJS interpolated string with an expression wrapped between {{ and }} in the post-link function of your directive. 当我们现在查看您的代码时,您实际上是将一个html元素的文本设置为一个AngularJS插值字符串,其中一个表达式在指令的post-link函数中包含在{{和}}之间。
As explained above at this time AngularJS has already compiled the template so that it will never compile the interpolated string with your expression. 如上所述,此时AngularJS已经编译了模板,因此它永远不会使用您的表达式编译插值字符串。
As I can see from your code you are trying to implement some kind of translate directive. 正如我从您的代码中看到的那样,您正在尝试实现某种translate指令。 Such directive must call the $compile function when it should consider interpolated strings and other AngluarJS template code in the translated string: 当它应该在翻译的字符串中考虑插值字符串和其他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
}
},
};
}]).
The translate directive uses a translate service to get the actual translation. translate指令使用翻译服务来获取实际翻译。 The translateProvider has an add method which you can use to add translations eg from a language bundle: 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
}).
You can now use the module as follows: 您现在可以按如下方式使用该模块:
<div ng-app="myApp" ng-controller="MyCtrl">
<span data-translate>My name is {{name}}</span>
</div>
I have created a jsFiddle with a full example: http://jsfiddle.net/jupiter/CE9V4/2/ 我用一个完整的例子创建了一个jsFiddle: http : //jsfiddle.net/jupiter/CE9V4/2/
另外,对于翻译,我建议http://github.com/pascalprecht/angular-translate 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.