Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJs To Do list Directive

Tags:

angularjs

Edit JS Fiddle added JSFiddle

I'm trying to learn AngularJs and so I'm trying to take the "To Do" application to the next level.

Instead of an item being done or not, I want to have three states: (status)

  • 0 = Waiting
  • 1 = Working
  • 2 = Completed

I also want to have a priority:

  • 1 = High
  • 2 = Medium
  • 3 = Low

Here is my data:

[
  {"taskId":1,"description":"Test 1.","priority":1,"status":0}
  {"taskId":2,"description":"Test 2.","priority":1,"status":0}
  {"taskId":3,"description":"Test 3.","priority":1,"status":1}
]

I've got three lists that displays each status wonderfully. When I move an item from one status to another, it goes away from the original list and appears in the appropriate list for the new status.

However, I am now working with directives and I want to turn those three separate lists into a single directive and it's really kicking my butt.

This is the hard-coded version of my To-Do list that displays the To-Do items in a 'Waiting' status.

<h3 style="display: inline-block;">Waiting</h3>
<div class="label" style="display: inline-block;" ng-hide="getStatusCount(0) == 0">{{getStatusCount(0)}}</div>
    <div class="infoTableWrap">
    <table class="infoTable">
        <thead>
            <tr>
                <th style="text-align: left">Description</th>
                <th style="text-align: right">Priority</th>
                <th style="text-align: right">Status</th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="task in tasks.items | filter:{status:0}">
                <td style="text-align: left">{{task.description}}</td>
                <td style="text-align: right">
                    <select name="ddlPriority" ng-model="task.priority" ng-options="option.id as option.name for option in priorityOptions"></select>
                </td>
                <td style="text-align: right">
                    <select name="ddlStatus" ng-model="task.status" ng-options="option.id as option.name for option in statusOptions"></select>
                </td>
            </tr>
        </tbody>
    </table>
</div>

Here is my attempt at making that a directive

<script type="text/template" id="taskListTemplate">
    <h3 style="display: inline-block;">{{header}}</h3>
    <div class="label" style="display: inline-block;" ng-hide="getStatusCount(2) == 0">{{getStatusCount(2)}}</div>
    <div class="infoTableWrap">
        <table class="infoTable">
            <thead>
                <tr>
                    <th style="text-align: left">Description</th>
                    <th style="text-align: right">Priority</th>
                    <th style="text-align: right">Status</th>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="task in taskList | filter:{status:2}">
                    <td style="text-align: left">{{task.description}}</td>
                    <td style="text-align: right">
                        <select name="ddlPriority" ng-model="task.priority" ng-options="option.id as option.name for option in priorityOptions"></select>
                    </td>
                    <td style="text-align: right">
                        <select name="ddlStatus" ng-model="task.status" ng-options="option.id as option.name for option in statusOptions"></select>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</script>

Here is how I'm calling it:

div task-list-directive header="Completed Tasks" status-type="2" task-list="tasks.items"></div>

And here is the directive code

.directive("taskListDirective", function() {
return {
    restrict: "EA",
    scope: {
        header: "@",
        taskList: "=",
        statusType: "@"
    },
    template: function () {
    return angular.element(document.querySelector("#taskListTemplate")).html();
    }
};
})

What works:

  • Header (the header is coming across just fine)
  • taskList (the task list is coming across just fine)

What doesn't work in the directive:

  • Setting the statusType so I don't have to hard-code the 2 in the template
  • The lists come up empty, but I figure that's a scope thing and I was going to turn those into directives as well.

Thanks, Duane

Here is my JSFiddle

I included the form to add new items...and there are two hard coded lists for "Waiting" and "Working"...and I commented out the html for the directive as I couldn't get that to work in JSFiddle.

like image 411
Duane Haworth Avatar asked Jun 10 '26 09:06

Duane Haworth


1 Answers

You should be able to reference statusType in your directive and use it to filter on.

ng-repeat="task in taskList | filter:{status:statusType}"

and

{{getStatusCount(statusType)}}

Since the directive uses isolated scope, you can't reference priorityOptions and statusOptions that are in the controller. You could pass them in the same way you do with taskList. But you could also define a controller for the directive and put those things there. Here I've done both. Since you also use priorityOptions in your form, I kept it in the controller and passed it in to the directive. Since statusOptions is only used in the directive, I moved it out of the controller.

.directive("taskListDirective", function () {
    return {
        restrict: "EAC",
        scope: {
            header: "@",
            taskList: "=",
            priorityOptions: "=",
            statusType: "@"
        },
        template: function () {
            return angular.element(document.querySelector("#taskListTemplate")).html();
        },
        controller: function ($scope) {
            $scope.getStatusCount = function (statusType) {
                return countStatusTypes(statusType);
            }

            //Private Methods
            function countStatusTypes(statusType) {
                var count = 0;
                angular.forEach($scope.taskList, function (item) {
                    if (item.status === statusType * 1) {
                        count++;
                    }
                });
                return count;
            }               

            $scope.statusOptions = [{
                name: 'Waiting',
                id: 0
            }, {
                name: 'Working',
                id: 1
            }, {
                name: 'Completed',
                id: 2
            }];
        }
    };
});

Here's your JSFiddle updated to use the directly exclusively.

like image 119
Jerrad Avatar answered Jun 13 '26 05:06

Jerrad



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!