Clearing out a DOM node in angularjs directive


I have the following directive. I usually don't like posting too much code so that those attempting to answer the question can focus on the important parts, but I'm not sure what I'm doing wrong here, so I have to.

It's a directive that should repeat all the children of the element. The initial rendering works, but when I modify the list, things get messed up. For a usage example, see this jsFiddle. Try removing an item to see what goes wrong.

bigblind = window.bigblind || angular.module("bigblind",[]);

bigblind.directive("repeatInside", function(){
    var makeChildScope = function(scope, index, key, val, keyIdentifier, valIdentifier){
        childScope = scope.$new();
        childScope.index = index
        if (keyIdentifier) childScope[keyIdentifier] = index;
        childScope[valIdentifier] = val;
        childScope.first = (index == 0);
        return childScope
    var ddo = {
        compile: function(element, attrs, transclude){
            return function($scope, $element, $attr){
                var expression = $attr.repeatInside;
                var match = expression.match(/^\s*(.+)\s+in\s+(.*?)$/)
                var lhs, rhs
                var keyIdentifier, valIdentifier, hashFnLocals = {};

                    throw "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got " + expression;

                lhs = match[1];
                rhs = match[2];

                match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
                if (!match) {
                    throw "bad left hand side in loop";
                valIdentifier = match[3] || match[1];
                keyIdentifier = match[2];

                $scope.$watch(rhs, function(newval, oldval) {
                    var childScope, index = 0

                    for (var child in $element.children){

                    if (angular.isArray(newval)){
                        for (index=0; index<newval.length; index++) {
                            childScope = makeChildScope($scope, index, index, newval[index], keyIdentifier, valIdentifier);
                            transclude(childScope, function(clone){
                                clone.scope = childScope;
                        for (key in newval){
                            if (newval.hasOwnProperty(key) && !key[0] == "$") {
                                childScope = makeChildScope($scope, index, key, newval[key], keyIdentifier, valIdentifier);
                                index += 1;
                                transclude(childScope, function(clone){
                                    clone.scope = childScope;
                }, true);
    return ddo
Problem courtesy of: bigblind


I was able to get the children and remove them by taking angular.element($element[0]).children()^

Solution courtesy of: bigblind


The problem is happening at child.remove();. You'll notice that your loop doesn't actually iterate over any children: for (var child in $element.children)

When I log the following expressions, I get some weird results

(a) console.log($element);
(b) console.log($element[0]);
(c) console.log(angular.element($element[0]));


(a) [dl, ready: function, toString: function, eq: function, push: function, sort: function…]
(b) <dl repeat-inside=​"word in dict">​…​</dl>​
(c) [dl, ready: function, toString: function, eq: function, push: function, sort: function…]

Furthermore, the API is actually angular.element.children() and not angular.element.children. But $element is an array and it has no DOM children. It's first element refers to the <dl> DOM element we are looking for though.

So I would expect $element[0] or angular.element($element[0]) to give this to us as a proper JQuery element. But as you can see from those console logs, we just end up going in circles.

I hope someone can shed some light on this.

Discussion courtesy of: tnunamak

This recipe can be found in it's original form on Stack Over Flow.