AngularJS — Как вызвать директивную функцию в динамическом контенте из ng-bind-html?

#angularjs

#angularjs

Вопрос:

Если вы создаете директиву, которая динамически загружает содержимое HTML, то, похоже, вы не можете вызывать функции этой директивы из этого сгенерированного HTML. Я предполагаю, что контент должен быть связан ПОСЛЕ его создания в директиве. Я пытаюсь скомпилировать элемент после изменения динамического содержимого, но это не помогает. Функция никогда не вызывается. Есть ли способ сделать это? (Заранее большое спасибо!)

В приведенном ниже коде вы можете видеть, что существует статический вызов функции doIt() из шаблона директивы. Это работает. Но вызов той же функции из динамического содержимого не работает.

Вот элемент, который вызывает мою директиву:

 <issue obj="obj" label="Make Dynamic Content"></issue>
 

Вот моя директива:

 (function () {
angular.module('myModule').directive('issue', function ($compile, $sce) {
    return {
        restrict: 'EA',
        scope: {
            label: '@',
            obj: '='
        },
        templateUrl: 'components/docs/docs.issue.html',
        link: function (scope, element, attrs){

            scope.theLabel = attrs.label;

            scope.doIt = function() {
                alert("DOIT CALLED FROM WITHIN ISSUE");
            };

            scope.showIssue = function() {
                // THIS CALL TO doIt() FAILS -- NEVER GETS CALLED...
                var s = '<p>Dynamic content: <br><a href="" ng-click="doIt()">Click Me</a></p>';
                scope.obj = {content: $sce.trustAsHtml(s)};
                jQuery('#issue-panel').show();
                $compile(element)(scope);
            };
        }
    };
});
}).call(this);
 

И вот шаблон HTML для директивы… {{theLabel}} скажет «Создать динамический контент». Когда вы нажимаете на это, он генерирует динамический контент в obj.content. У меня есть статический вызов doIt(), который отображается над сгенерированным контентом.

 <div id="win-container">
<a href="" ng-click="showIssue()">
    {{theLabel}}
</a>
<div id="issue-panel">
    <div class="topicWin-content">
        <!-- THIS CALL TO doIt() WORKS... -->
        <p>Static content:<br> <a href="" ng-click="doIt()">Static Click</a></p>
        <div ng-bind-html="obj.content"></div>
    </div>
</div>
</div>
 

Комментарии:

1. Я также попытался обернуть сгенерированный контент в applyAsync() — по-прежнему без радости.

2. это еще один из длинной череды вопросов о том, как создавать динамический HTML-код из строк в angular. Практика хранения HTML в строках противоречит тому, как работает angular, и, как правило, в любом случае не нужна. единственная причина хранить HTML в строках, а не в реальных шаблонах, — это пользовательский контент, который представляет собой совершенно другой вид управления контентом.

3. @Claies В моем случае речь не обязательно идет о строках — источником данных может быть процесс, может быть результат API, может быть строка в файле в каком-то другом формате… Суть в том, чтобы интегрировать контент в графический интерфейс приложения. Если содержимое получает приложение angular, то, если для содержимого требуется ссылка, эта ссылка должна вызывать приложение angular. Есть ли что-то присущее angular, что говорит о том, что представление приложения не должно доставлять текстовый контент?

4. Нет, я хочу сказать, что angular плохо работает с HTML-шаблонами, которые создаются как данные, из-за того, что он сосредоточен на разделении проблем. Данные — это данные, html — это html, а хранение данных в html или html как данных противоречит проблеме, для решения которой была разработана платформа.

5. Достаточно справедливо, но факт в том, что я не сохраняю данные в html или наоборот. Я конвертирую данные в HTML, и иногда я хочу, чтобы этот HTML вел себя как HTML, который мы знаем и любим… Нажмите здесь и т. Д.

Ответ №1:

Я думаю, что смогу обойти проблему. Я просто предоставляю функцию, которую хочу вызвать в своей директиве, а затем реализую произвольную функцию в шаблоне, которая вызывает нужную мне функцию. Тогда мои функции в сгенерированном контенте просто вызывают эту произвольную функцию. Технически, это не то, что я просил сделать, но это позволяет выполнить свою работу… Я могу сгенерировать контент, а затем вызвать свою директиву из этого сгенерированного контента.

Чтобы вызвать directiveI, сделайте это — обратите внимание на атрибут func:

 <issue id="cudTest" obj="obj" func="func" label="Make Dynamic Content"></issue>
 

Тогда директива выглядит так:

 (function () {
angular.module('myModule').directive('issue', function ($compile, $sce) {
    return {
        restrict: 'EA',
        scope: {
            label: '@',
            func: '=',
            obj: '='
        },
        templateUrl: 'components/docs/docs.issue.html',
        link: function (scope, element, attrs){

            scope.obj = {};

            scope.theLabel = attrs.label;

            scope.doIt = function(s) {
                alert("DOIT CALLED FROM WITHIN ISSUE: " s);
            };

            scope.func = scope.doIt;

            scope.showIssue = function() {
                // THIS CALL TO doIt() WORKS!!!
                var arg = "'This is a template call from dynamically generated content!'";
                var s = s '<p>TEST content: <br><a onclick="javascript:templateCall(' arg ')">TEST Click Me 2!</a></p>';
                scope.obj.content = $sce.trustAsHtml(s);
                jQuery('#issue-panel').show();
            };
        }
    };
});
}).call(this);
 

И, наконец, шаблон выглядит так… Я могу быть более умным в поиске директивного элемента, но для этого я использую идентификатор:

 <script type="text/javascript">

var templateCall = function(s) {
    var thisElem = document.getElementById("cudTest");
    var myScope = angular.element(thisElem).scope();
    myScope.$apply(function() {
        myScope.func(s);
    });
}
</script>

<a href="" ng-click="showIssue()">{{theLabel}}</a>
<!-- THIS CALL TO doIt() WORKS... -->
<p>Static content:<br>
<a ng-click="doIt('This is a static call')">Static Click</a></p>
<div ng-bind-html="obj.content"></div>