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с div и якорем не оценивает. Как заставить его работать?

Амитава
источник
3
Посмотрите мой ответ здесь stackoverflow.com/questions/17343696/…
Чандермани 02
@Chandermani не совсем использует директиву внутри ng-bind-html-unsafe, но использует фильтр. Но подойдет, я просто создал фильтр и передал директиву. Спасибо!
Amitava
@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
В строке №2, т.е. function(scope, element, attrs), откуда вы взяли эти три аргумента: область видимости , элемент и атрибуты ?
spaffy
1
@spaffy - они являются частью подписи Angular framework для linkсвойства. Они будут передаваться автоматически каждый раз, когда linkвызывается фреймворком Angular. Они всегда будут доступны.
Бен
1
Отлично сработано. Вы сэкономили мне те же часы поисков. Я извлекаю контент из REST API представления SharePoint, который сам содержит разметку Angular, такую ​​как ng-repeat. Ваша директива заставила все это работать. Спасибо!
Фил Николас
Спасибо за вашу директиву, она устранила мои проблемы. Теперь код angular компилируется, но слишком много раз. Повторение ng-repeat с 3 объектами превращается в одинаковые значения только в 3 раза каждое. Что здесь не так?
Джейсон
2
Если вы использовали $sce.trustAsHtmlдругую функцию для создания HTML, который будет «скомпилирован» с помощью этой директивы, вам следует удалить его. Спасибо @apoplexy
Бурак Токак
36

Спасибо за отличный ответ vkammerer. Одна оптимизация, которую я бы порекомендовал, - это не смотреть после того, как компиляция выполняется один раз. $ Eval в выражении watch может повлиять на производительность.

    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();
            }
        );
    };
}]);

Вот раздвоенная и обновленная скрипка.

пользователь3075469
источник
Могу ли я сделать наоборот?
Саньям Джайн
это не работа в ответ на ajax, но принятая ответная работа
foozhan 05
1
Предупреждение: скрипт для этого ответа работает, но .directive()код в коде, опубликованном в ответе, нет.
Фил Николас
это сработало для меня. выбранный ответ вызовет «Error: $ rootScope: infdig Infinite $ digest Loop»
Габриэль Андрей
Вы не должны нуждаться в явном $eval- вы можете просто использовать attrs.compileнепосредственно вместо наблюдаемой анонимной функции. Если вы просто предоставите строковое выражение, angular все $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>

Действительно просто :)

Joël
источник
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.

MStrutt
источник
-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>
юстме
источник