3

I'd like to create a ToDo app in AngularJS that uses nested ToDos. As part of this, I'd like the ability to indent or outdent a ToDo with a click (ultimately, it will react to a 'tab' or 'shift-tab' keypress). When indenting, the function should also indent any child ToDos. This is where I'm having trouble. I'm not sure how to implement a recursive function in a directive. If anyone has seen this done or could offer any help, i would appreciate it. I've created a working JSFiddle that indents a single ToDo but doesn't indent it's children. JS Fiddle is here https://jsfiddle.net/t1ba50k6/16/

Also, please offer any best practices on coding convention or to clean up the directive.

Thanks!

My HTML:

<ul id=Todos ng-app="app" ng-controller="todos">
    <div ng-repeat='todo in model' ng-init="todoIndex = $index">
       <todo-item content="todo"></todo-item>
    </div>

My javascript:

var app = angular.module('app', []);

app.controller("todos", function ($scope) {

    $scope.model = [{
        "title": "Task item one",
            "indentLevel": 1
    }, {
        "title": "Task item two",
            "indentLevel": 2
    }, {
        "title": "Task item three",
            "indentLevel": 2
    }];

});


app.directive('todoItem', function ($compile) {

    var getTemplate = function (content) {
        var startStr = '';
        var endStr = '';

        if (content.indentLevel == 1) {
            startStr = '<li class="todolist"><table><tr><td><div class="checkboxpadding"><img width="16" height="16" class="checkbox"></div></td><td><div ng-click="indent()">';
            endStr = '</div></td></tr></table></li>';

            return startStr + content.title + endStr;
        } else if (content.indentLevel == 2) {

            startStr = '<li class="todolist indent_2""><table><tr><td><div class="checkboxpadding"><img width="16" height="16" class="checkbox"></div></td><td><div ng-click="indent()">';
            endStr = '</div></td></tr></table></li>';
            return startStr + content.title + endStr;
        }


    };

    var linker = function (scope, element, attrs) {

        element.html(getTemplate(scope.content)).show();
        $compile(element.contents())(scope);


        scope.indent = function () {
            var childElem = angular.element(element.children()[0]);

            if (scope.content.indentLevel < 3) {
                childElem.removeClass("indent_" + scope.content.indentLevel);
                childElem.addClass("indent_" + (scope.content.indentLevel + 1));
                scope.content.indentLevel++;
                // update Database
                // indent child nodes?
                // for (var i=0; i < nodes; i++) {                      }

            }
        };


    };

    return {
        restrict: "E",
        link: linker,
        scope: {
            content: '='
        }
    };
});

2 Answers 2

1

Mapping your data to a nested structure would greatly simplify this.

Always use the same property names for the child arrays:

$scope.model = [{
        "title": "Task item one",
        "indentLevel": 1,
        "children": [
            {
              "title": "Task item two",
              "indentLevel": 2,
               "children":[]
            }, {
               "title": "Task item three",
               "indentLevel": 2,
                "children":[]
            }
        ]
}];
Sign up to request clarification or add additional context in comments.

2 Comments

Agreed. I can use a structure like that. But how do I call a function within the directive that would reference the children?
just use ng-repeat on the children. google angular recursive directive will find lots of results
0

One solution is using $broadcast(name, args) and $on(name, listener) of scope.

when cliked fire an event:

scope.$broadcast('indent');

in child directives,

scope.$on('indent', scope.indent);

1 Comment

thanks. I'll try that and update my fiddle if it works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.