Как сделать angular.js reevaluate/recompile inner html?
Я делаю директиву, которая изменяет его внутренний html. Код до сих пор:
.directive('autotranslate', function($interpolate) {
return function(scope, element, attr) {
var html = element.html();
debugger;
html = html.replace(/\[\[(\w+)\]\]/g, function(_, text) {
return '<span translate="' + text + '"></span>';
});
element.html(html);
}
})
Это работает, за исключением того, что внутренний html не оценивается angular. Я хочу вызвать переоценку поддерева element
. Есть ли способ сделать это?
Спасибо:)
Ответы
Ответ 1
Вам нужно $compile
ваш внутренний HTML-код, например
.directive('autotranslate', function($interpolate, $compile) {
return function(scope, element, attr) {
var html = element.html();
debugger;
html = html.replace(/\[\[(\w+)\]\]/g, function(_, text) {
return '<span translate="' + text + '"></span>';
});
element.html(html);
$compile(element.contents())(scope); //<---- recompilation
}
})
Ответ 2
Вот более общий метод который я разработал, чтобы решить эту проблему:
angular.module('kcd.directives').directive('kcdRecompile', function($compile, $parse) {
'use strict';
return {
scope: true, // required to be able to clear watchers safely
compile: function(el) {
var template = getElementAsHtml(el);
return function link(scope, $el, attrs) {
var stopWatching = scope.$parent.$watch(attrs.kcdRecompile, function(_new, _old) {
var useBoolean = attrs.hasOwnProperty('useBoolean');
if ((useBoolean && (!_new || _new === 'false')) || (!useBoolean && (!_new || _new === _old))) {
return;
}
// reset kcdRecompile to false if we're using a boolean
if (useBoolean) {
$parse(attrs.kcdRecompile).assign(scope.$parent, false);
}
// recompile
var newEl = $compile(template)(scope.$parent);
$el.replaceWith(newEl);
// Destroy old scope, reassign new scope.
stopWatching();
scope.$destroy();
});
};
}
};
function getElementAsHtml(el) {
return angular.element('<a></a>').append(el.clone()).html();
}
});
Вы используете его так:
HTML
<div kcd-recompile="recompile.things" use-boolean>
<div ng-repeat="thing in ::things">
<img ng-src="{{::thing.getImage()}}">
<span>{{::thing.name}}</span>
</div>
</div>
JavaScript
$scope.recompile = { things: false };
$scope.$on('things.changed', function() { // or some other notification mechanism that you need to recompile...
$scope.recompile.things = true;
});
Изменить
Если вы посмотрите на это, я серьезно рекомендую посмотреть версию на веб-сайте, поскольку это, скорее всего, будет более актуальным.
Ответ 3
Это оказалось более эффективным, чем решение @Reza
.directive('autotranslate', function() {
return {
compile: function(element, attrs) {
var html = element.html();
html = html.replace(/\[\[(\w+)\]\]/g, function(_, text) {
return '<span translate="' + text + '"></span>';
});
element.html(html);
}
};
})
Код Reza работает, когда scope
является областью для всех дочерних элементов. Однако, если в одном из дочерних элементов этой директивы имеется ng-контроллер или что-то еще, переменные области не найдены. Однако с этим решением ^ он просто работает!