Get original transcluded content within angular directive
The $element.innerHTML
should contain the original HTML. I am showing that it contains
<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><h1>Hello</h1><p>some text</p><clock></clock></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>
Related videos on Youtube
prototype
Updated on February 20, 2020Comments
-
prototype over 4 years
My goal is to create an
editable
directive that allows a user to edit HTML of any element to which the attribute is attached (see Plunker: http://plnkr.co/edit/nIrr9Lu0PZN2PdnhQOC6)This almost works except I can't get the original raw HTML of the transcluded content to initialize the text area. I can get the text of it from
clone.text()
, but that's missing the HTML tags like<H1>
,<div>
, etc. so clicking apply with no edits is not idempotent.The method
clone.html()
throws an error,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; } } } });
(This question is essentially a wholesale rewrite of the question and code after an earlier attempt to frame the question, Get original transcluded content in Angular directive)
-
Nathaniel Johnson over 10 years
clone
is a collection of elements. Have you been able to inspect it in a debugger? -
prototype over 10 yearsAha! Iterating over them and appending outerHTML is much closer:
var text = ""; for (var i=0; i<clone.length; i++) {text += clone[i].outerHTML||'';}
. However, one remaining gap is the HTML of the nested directives is expanded, e.g. instead of just<clock></clock>
it shows<clock><span class="clock"><div class="btn btn-success"><h1>Clock</h1><p>{{time}}</p></div></span></clock>
. In this example, the clock doesn't transclude content, so the net effect is the same. I wonder if it's possible to get the original HTML? -
Nathaniel Johnson over 10 yearsI suspected it might be the case. Good deal. The original HTML might be sitting in the $element object in the outer scope. Transclusion is not my strong suit.
-
charlietfl over 10 yearswhy aren't you wrapping original content in an element with a class that you can use to find it and keep it isolated in one container?
-
charlietfl over 10 yearsif it was me would just add textarea/editor on demand like with doubleclcik. Append when needed.
-
manikanta about 10 years@user645715 Did you able to figure how to get the 'original transcluded markup'?
-
prototype about 10 yearsSorry, no, despite a fair effort. I then implemented the properties editor using JSON, which mapped directly to jQuery "data-" properties. (And because the project had lots of nested views, ended up porting it to Backbone.js for simple control over how/when it was rendered)
-
-
prototype over 10 yearsVery helpful. That contains the template text. Your answer did spark me to add the method
compile(element, attrs)
which has the transcluded HTML in itsinnerHTML
. But it's after Angular expanded it into new DOM elements using the template. That'll break if any sub-elements havereplace:true
or transclude content themselves. I suspect there's no way to get Angular to give the HTML from before Angular processed it, and thus the starting content would need to be bootstrapped not via transclusion but passed say via an attribute or ajax. -
Nathaniel Johnson over 10 yearsThis gets into the guts of the digest cycle. By setting the priority arbitrarily high, you might be able to ensure that it is evaluated first.
-
pery mimon almost 9 yearsHow to get the uncompiled transclude content of an Angular directive if I using
replace:true
with template. it's meanelement
not contain the raw orginal content beacuseelement
is template element not orginal element