pQuestions123
pQuestions123

Reputation: 4611

Angular directive not recognizing attribute

Here is the html:

<body ng-app="myCatApp">
        <div ng-controller="catagoryController">
            <add-remove-lister list="catagories"></add-remove-lister>
        </div>
    </body>

Here is the JS:

    app.controller('catagoryController', ['catagoryList', '$scope', function(catagoryList, $scope) {
      $scope.catagories = catagoryList.catagoryList;
    }]);

    app.directive('addRemoveLister', [function () {
        return {
            scope: {
                list: '='
            },
template: function(tElement, tAttrs, scope) {
            templateHTML = '<ul>';
            var list = scope.list;
            for (o = 0; o < list.length; o++) {
                var curObject = scope.list[o];
                templateHTML +='<li ng-repeat="listItem in list"><button type="button" ng-hide="listItem.userSelected" ng-click="addToList()">Add</button>';
                templateHTML +='<button type="button" ng-hide="listItem.userSelected" ng-click="removeFromList()">Remove</button>{{listItem.text}}';
                for (var prop in curObject) {
                    if (curObject.hasOwnProperty(prop) && prop.constructor === Array) {
                        templateHTML += '<add-remove-lister list="listItem.'+ prop +'"></add-remove-lister>';
                    }
                }
                templateHTML += '</li>';
            }
            templateHTML += '<ul>';
            return templateHTML;
        }
        }
    }]);

The code is not working correctly. When I set a breakpoint in the directive, I can see that list is just the string "catagories". I would like it to be the categories object that is on the controller scope...

Let me expand a little bit on what I am trying to do:

I am trying to build a directive that will take any array and produce a list from it. The assumptions are: 1) That all elements in the array will be objects having at least the properties {text : 'text', userSelected: 'bool'}

When the directive encounters an object in the list that has a property with that is itself an array (which is also assumed to contain objects with the above two properties), it needs to recursively call itself on that array.

The directive also needs to display buttons next to each list item to allow the user to change the userSelected property on the object (thereby adding it to the users "options")

Upvotes: 0

Views: 1087

Answers (2)

Joe Enzminger
Joe Enzminger

Reputation: 11190

Try this for your template function

template: function(tElement, tAttrs, scope) {
        templateHTML = '<ul>';
        templateHTML +='<li ng-repeat="listItem in list"><button type="button" ng-hide="listItem.userSelected" ng-click="addToList()">Add</button>';
        templateHTML +='<button type="button" ng-hide="listItem.userSelected" ng-click="removeFromList()">Remove</button>{{listItem.text}}';
        templateHTML += '<add-remove-lister ng-repeat="(key, val) in listItem" ng-if="val.length" list="val"></add-remove-lister>';
        templateHTML += '</li>';
        templateHTML += '<ul>';
        return templateHTML;
}

Note that you can probably do the above with just a template, the template function is not really necessary.

The main reason for a template function is to allow you to modify the DOM of the original HTML, or to pull sections from the original element to do manual transclusion.

Also, there are a few problems I can see already in your directive (the functions you reference in your template have to be defined on your directive's scope, and since you are using an isolated scope, you can't reference functions on your parent scope. You'll have to pass those methods in as attributes of the directive as well, or use some other mechanism to add or remove elements.

Here is a Working Plunk.

Upvotes: 1

Rebornix
Rebornix

Reputation: 5270

You can access list in following ways

app.directive('addRemoveLister', [function () {
    return {
        restrict: 'E',
        scope: {
            list: '='
        },
        template: "test {{list}}",
        link: function (scope, element, attrs) {
          console.log(scope.list);
        },
        controller: function (scope) {
          console.log(scope.list);
        }
    }
});

Or you can compile your dynamic template in linking phase

app.directive('addRemoveLister', function ($compile) {
  var getTemplate = function(list) {
        var templateHTML = '<ul>';
        for (o = 0; o < list.length; o++) {
            var curObject = scope.list[o];
            templateHTML +='<li ng-repeat="listItem in list"><button type="button" ng-hide="listItem.userSelected" ng-click="addToList()">Add</button>';
            templateHTML +='<button type="button" ng-hide="listItem.userSelected" ng-click="removeFromList()">Remove</button>{{listItem.text}}';
            for (var prop in curObject) {
                if (curObject.hasOwnProperty(prop) && prop.constructor === Array) {
                    templateHTML += '<add-remove-lister list="listItem.'+ prop +'"></add-remove-lister>';
                }
            }
            templateHTML += '</li>';
        }
        templateHTML += '<ul>';
        return templateHTML;
  }

    return {
        restrict: 'E',
        scope: {
            list: '='
        },
        link: function(scope, element, attrs) {
            var el = $compile(getTemplate(scope.list))(scope);
            element.replaceWith(el);
        }
    };
});

Upvotes: 0

Related Questions