0

I have the following HTML:

<my-dom attri="something 01">content 01</my-dom>
<my-dom attri="something 02">content 02</my-dom>
<my-dom attri="something 03">content 03</my-dom>

And now I want this to be replaced in runtime with:

<div>something 01: content 01</div>
<div>something 02: content 02</div>
<div>something 03: content 03</div>

Therefore I created this AngularJS directive:

app.directive('myDom', function() {
    var content;

    return {
        restrict: 'EA',
        replace: true,

        scope : true,
        // scope : false,
        // scope: {},

        template: function(elem, attr){
            content = elem.clone();
            return '<div>{{myContent}}: {{oldContent}}</div>';
        },

        controller: function(){
        },
        link: {
            pre: function(scope, elem, attr){
                scope.myContent = content.attr("attri"); // could also use "attr"
                scope.oldContent= content.html(); // could not use "elem" or "attr"
            },
            post: function(scope, elem, attr){
            },
        }
    };
});

Here I first clone the originale DOM element in the private variable "content" and then replacing the DOM element with the new one. In this new HTML Tag I insert the attribute data from the old code. But here it's getting mixed up:

The output code is:

<div>something 03: content 03</div>
<div>something 03: content 03</div>
<div>something 03: content 03</div>

So there is something wrong with the scope. But what?
From the documentation the scope : true is creating a new scope for the directive by inheriting the parent scope.
Changes in the parent scope does affect the directive scope but changes in the directive scope does NOT change the parent scope.

The only thing I can imagine:
This one directive only has one scope. So all three usages of <my-dom> share one and the same scope.
Is that correct? And how can I manage to get the result I want?

toddeTV
  • 1,447
  • 3
  • 20
  • 36
  • You have `var content;` global variable that is shared between all directive instances. So it is replaced with the element of the "last" directive instance. In `pre`, you are using `function(scope, elem, attr)`, so you can access attributes with the 3rd argument `attr`, so why do you actually need `content` variable? – Stanislav Kvitash Jun 04 '18 at 11:50
  • In my original code I also want to access the inner html of the original dom element that will be replaced. And therefore I have to cache the old element before it gets lost. – toddeTV Jun 04 '18 at 11:54
  • ok, updated my example. sry, was too short to show that problem. – toddeTV Jun 04 '18 at 11:57

1 Answers1

2

As I've mentioned in my comment, your content is shared between all the directive instances, so it is overwritten in each template function.

To achieve desired behavior you can use transcludeFn together with transclude: true to access the element that was wrapped with your directive, see the example below:

angular.module('plunker', [])
    .controller('MainCtrl', function ($scope) {

    })
    .directive('myDom', function () {
        return {
            restrict: 'EA',
            replace: true,
            transclude: true,
            scope: true,
            template: '<div>{{myContent}}: {{oldContent}}</div>',
            controller: function () {
            },
            link: {
                pre: function (scope, elem, attr, ctrl, transclude) {
                    transclude(function (clone) {
                        scope.myContent = attr["attri"];
                        scope.oldContent = clone.text();
                    });
                }
            }
        };
    });
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.min.js"></script>
<body ng-app="plunker">

    <div ng-controller="MainCtrl">
        <my-dom attri="something 01">content 01</my-dom>
        <my-dom attri="something 02">content 02</my-dom>
        <my-dom attri="something 03">content 03</my-dom>
    </div>

</body>

Some more interesting answers and examples in this SO question.

Stanislav Kvitash
  • 4,614
  • 18
  • 29