angular ng-bind-html та директива всередині нього


96

Plunker Link

У мене є елемент, який я хотів би прив’язати до нього html.

<div ng-bind-html="details" upper></div>

Це працює. Тепер, поряд з нею, у мене також є директива, яка пов'язана з пов'язаним html:

$scope.details = 'Success! <a href="#/details/12" upper>details</a>'

Але директиву upperз дівом та якорем не оцінюють. Як змусити його працювати?


3
Подивіться на мою відповідь тут stackoverflow.com/questions/17343696 / ...
Chandermani

@Chandermani не зовсім використовує директиву всередині ng-bind-html-небезпечно, але використовує фільтр. Але все буде, я просто створив фільтр і перейшов до директиви. Дякую!
Амітава

@SamSerious Чи можете ви показати, як ви робили те, що робили для фільтрів?
CMCDragonkai

вищевказані рішення не обробляють багаторазових змін значення краще рішення stackoverflow.com/a/25516311/3343425
fghibellini

Відповіді:


188

Я також стикався з цією проблемою, і після години пошуку в Інтернеті я прочитав коментар @ Chandermani, який виявився рішенням. Вам потрібно викликати директиву 'compile' з таким шаблоном:

HTML:

<div compile="details"></div>

JS:

.directive('compile', ['$compile', function ($compile) {
    return function(scope, element, attrs) {
        scope.$watch(
            function(scope) {
                // watch the 'compile' expression for changes
                return scope.$eval(attrs.compile);
            },
            function(value) {
                // when the 'compile' expression changes
                // assign it into the current DOM
                element.html(value);

                // compile the new DOM and link it to the current
                // scope.
                // NOTE: we only compile .childNodes so that
                // we don't get into infinite loop compiling ourselves
                $compile(element.contents())(scope);
            }
        );
    };
}])

Ви можете побачити його робочу скрипку тут


1
У рядку No2, тобто. function(scope, element, attrs), звідки ви взяли ці три аргументи, сферу дії , елемент та атрибути ?
spaffy

1
@spaffy - вони є частиною підпису Angular framework для linkвласності. Вони передаються автоматично кожного разу, коли linkїх викликає фреймворк Angular. Вони завжди будуть доступні.
Бен,

1
Молодці. Ти врятував мене ті самі години пошуків. Я перетягую вміст з SharePoint view REST API, який сам містить кутову розмітку, наприклад ng-повтор. Ваша директива змусила все це працювати. Дякую!
Філ Ніколас

Дякую за вашу директиву, вона вирішила проблеми, які виникали у мене. Тепер кутовий код компілюється, але занадто багато разів. Повторення ng з 3 об’єктами перетворюється на ті самі значення, що в 3 рази більше кожного. Що тут не так?
Джейсон

2
Якщо ви використовували $sce.trustAsHtmlіншу функцію для створення HTML, який буде "компільований" з цією директивою, вам слід видалити його. Завдяки @apoplexy
Burak Tokak 01

36

Дякую за чудову відповідь vkammerer. Однією з оптимізацій, яку я б рекомендував, є відмова від перегляду після того, як компіляція запускається один раз. $ Eval у виразі годинника може мати наслідки для продуктивності.

    angular.module('vkApp')
  .directive('compile', ['$compile', function ($compile) {
      return function(scope, element, attrs) {
          var ensureCompileRunsOnce = scope.$watch(
            function(scope) {
               // watch the 'compile' expression for changes
              return scope.$eval(attrs.compile);
            },
            function(value) {
              // when the 'compile' expression changes
              // assign it into the current DOM
              element.html(value);

              // compile the new DOM and link it to the current
              // scope.
              // NOTE: we only compile .childNodes so that
              // we don't get into infinite loop compiling ourselves
              $compile(element.contents())(scope);

              // Use un-watch feature to ensure compilation happens only once.
              ensureCompileRunsOnce();
            }
        );
    };
}]);

Ось розгалужена та оновлена ​​скрипка.


Чи можу я отримати навпаки?
Саньям Джайн

це не робота у відповідь ajax, але прийнята робота з відповідями
foozhan

1
Попередження: Скрипка для цієї відповіді працює, але .directive()код у коді, розміщеному у відповіді, ні.
Філ Ніколас

цей працював у мене. обрана відповідь спричинить "Помилка: $ rootScope: infdig Infinite $ digest Loop"
Габріель Андрій

Вам не знадобиться експлікація $eval- ви можете просто використовувати attrs.compileбезпосередньо замість переглянутої анонімної функції. Якщо ви просто надаєте рядковий вираз, кутовий буде зателефонувати $evalпо ньому все одно.
Дан Кінг

28

Додайте цю директиву angular-bind-html-compile

.directive('bindHtmlCompile', ['$compile', function ($compile) {
  return {
    restrict: 'A',
    link: function (scope, element, attrs) {
      scope.$watch(function () {
        return scope.$eval(attrs.bindHtmlCompile);
      }, function (value) {
        // Incase value is a TrustedValueHolderType, sometimes it
        // needs to be explicitly called into a string in order to
        // get the HTML string.
        element.html(value && value.toString());
        // If scope is provided use it, otherwise use parent scope
        var compileScope = scope;
        if (attrs.bindHtmlScope) {
          compileScope = scope.$eval(attrs.bindHtmlScope);
        }
        $compile(element.contents())(compileScope);
      });
    }
  };
}]);

Використовуйте його так:

<div bind-html-compile="data.content"></div>

Дійсно легко :)


1
Будьте обережні, якщо ви передасте щось на зразок цього: "$ scope.loadContent = function () {return $ sce.trustAsHtml (require ('html / main-content.html'));};" до нього ви можете отримати нескінченний цикл перетравлення. Без trustAsHtml він працює.
Лакатос Гюла

13

На жаль, у мене недостатньо репутації для коментарів.

Я не міг змусити це працювати віками. Я змінив свій ng-bind-htmlкод, щоб використовувати цю власну директиву, але не зміг видалити те, $scope.html = $sce.trustAsHtml($scope.html)що було потрібно для роботи ng-bind-html. Як тільки я видалив це, функція компіляції почала працювати.


6

Для тих, хто має справу зі змістом, який уже проходив $sce.trustAsHtmlтут, я повинен був зробити інакше

function(scope, element, attrs) {
    var ensureCompileRunsOnce = scope.$watch(function(scope) {
            return $sce.parseAsHtml(attrs.compile)(scope);
        },
        function(value) {
            // when the parsed expression changes assign it into the current DOM
            element.html(value);

            // compile the new DOM and link it to the current scope.
            $compile(element.contents())(scope);

            // Use un-watch feature to ensure compilation happens only once.
            ensureCompileRunsOnce();
        });
}

Це лише linkчастина директиви, оскільки я використовую інший макет. Вам також потрібно буде вколоти $sceпослугу $compile.


-2

Найкраще рішення, що я знайшов! Я скопіював це, і воно працює саме так, як мені потрібно. Спасибі, дякую, дякую ...

у функції посилання директиви у мене є

app.directive('element',function($compile){
  .
  .
     var addXml = function(){
     var el = $compile('<xml-definitions definitions="definitions" />')($scope);
     $scope.renderingElement = el.html();
     }
  .
  .

та у шаблоні директиви:

<span compile="renderingElement"></span>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.