Получить исходный включенный контент в директиве angular

Моя цель — создать директиву editable, которая позволит пользователю редактировать HTML любого элемента, к которому прикреплен атрибут (см. Plunker: http://plnkr.co/edit/nIrr9Lu0PZN2PdnhQOC6)

Это почти работает, за исключением того, что я не могу получить исходный необработанный HTML-код включенного контента для инициализации текстовой области. Я могу получить его текст из clone.text(), но в нем отсутствуют теги HTML, такие как <H1>, <div> и т. д., поэтому нажатие кнопки «Применить» без изменений не является идемпотентным.

Метод clone.html() выдает ошибку, Cannot read property 'childNodes' of undefined

app.directive("editable", function($rootScope) {
  return {
    restrict: "A",
    templateUrl: "mytemplate.html",
    transclude: true,
    scope: {
      content: "=editContent"
    },

    controller: function($scope, $element, $compile, $transclude, $sce) {

      // Initialize the text area with the original transcluded HTML...
      $transclude(function(clone, scope) {

        // This almost works but strips out tags like <h1>, <div>, etc.
        // $scope.editContent = clone.text().trim();

        // this works much better per @Emmentaler, tho contains expanded HTML
        var html = ""; 
        for (var i=0; i<clone.length; i++) {
            html += clone[i].outerHTML||'';}
        });
        $scope.editContent = html;

      $scope.onEdit = function() {
        // HACK? Using jQuery to place compiled content 
        $(".editable-output",$element).html(
          // compiling is necessary to render nested directives
          $compile($scope.editContent)($rootScope)
        );
      }

      $scope.showEditor = false;

      $scope.toggleEditor = function() {
        $scope.showEditor = !$scope.showEditor;
      }         
    }
  }
});

(Этот вопрос, по сути, полностью переписывает вопрос и код после более ранней попытки сформулировать вопрос, Получить исходный включенный контент в директиве Angular)


person prototype    schedule 20.11.2013    source источник
comment
clone — это набор элементов. Вы смогли проверить это в отладчике?   -  person Nathaniel Johnson    schedule 20.11.2013
comment
Ага! Итерация по ним и добавление внешнего HTML намного ближе: var text = ""; for (var i=0; i<clone.length; i++) {text += clone[i].outerHTML||'';}. Однако один оставшийся пробел заключается в расширении HTML вложенных директив, например. вместо <clock></clock> показывает <clock><span class="clock"><div class="btn btn-success"><h1>Clock</h1><p>{{time}}</p></div></span></clock>. В этом примере часы не включают контент, поэтому общий эффект тот же. Интересно, можно ли получить исходный HTML?   -  person prototype    schedule 20.11.2013
comment
Я подозревал, что это может быть так. Хорошая сделка. Исходный HTML может находиться в объекте $element во внешней области видимости. Трансклюзия не моя сильная сторона.   -  person Nathaniel Johnson    schedule 20.11.2013
comment
почему вы не заключаете исходный контент в элемент с классом, который можно использовать для его поиска и хранения в одном контейнере?   -  person charlietfl    schedule 20.11.2013
comment
если бы это был я, я бы просто добавил текстовое поле/редактор по запросу, как с doubleclcik. Добавляйте по мере необходимости.   -  person charlietfl    schedule 20.11.2013
comment
@ user645715 Удалось ли вам понять, как получить «исходную включенную разметку»?   -  person manikanta    schedule 15.06.2014
comment
Извините, нет, несмотря на честные усилия. Затем я реализовал редактор свойств с помощью JSON, который напрямую сопоставлялся со свойствами данных jQuery. (И поскольку в проекте было много вложенных представлений, в итоге он был портирован на Backbone.js для простого контроля над тем, как и когда он будет отображаться)   -  person prototype    schedule 16.06.2014


Ответы (1)


$element.innerHTML должен содержать исходный HTML. Я показываю, что он содержит

  <div class="editable">
  <span class="glyphicon glyphicon-edit" ng-click="toggleEditor()"></span>

    <div class="editable-input" ng-show="showEditor">
       <b><p>Enter well-formed HTML content:</p></b>
       <p>E.g.<code>&lt;h1&gt;Hello&lt;/h1&gt;&lt;p&gt;some text&lt;/p&gt;&lt;clock&gt;&lt;/clock&gt;</code></p>
       <textarea ng-model="editContent"></textarea>
       <button class="btn btn-primary" ng-click="onEdit()">apply</button>
    </div>

    <div class="editable-output" ng-transclude=""></div>
  </div>
person Nathaniel Johnson    schedule 20.11.2013
comment
Очень полезно. Содержит текст шаблона. Ваш ответ побудил меня добавить метод compile(element, attrs), в котором есть включенный HTML в его innerHTML. Но это после того, как Angular расширил его до новых элементов DOM с помощью шаблона. Это сломается, если какие-либо подэлементы будут иметь replace:true или включать контент сами по себе. Я подозреваю, что нет способа заставить Angular предоставить HTML-код до того, как Angular его обработает, и поэтому начальный контент необходимо будет загружать не через трансклюзию, а передавать, скажем, через атрибут или ajax. - person prototype; 20.11.2013
comment
Это попадает в кишки цикла пищеварения. Установив произвольно высокий приоритет, вы можете гарантировать, что он будет оцениваться первым. - person Nathaniel Johnson; 20.11.2013
comment
Как получить нескомпилированное содержимое директивы Angular, если я использую replace:true с шаблоном. это означает, что element не содержит необработанного исходного контента, потому что elementявляется элементом шаблона, а не исходным элементом - person pery mimon; 07.09.2015