story: mark a task as done

This is part of a series extending ionic todo example

learnings featured:

story description

as a user I wish to mark a task as done

This story allows the user to mark a task as done. The UX design is to use a check box to the left of the item in the list that a user can check to indicate the task is done. Also the user should be able to mark a task done when editing the task.

The information will persist in the following form:

[
   {
      "title":"first project",
      "tasks":[
         {
            "title":"go to funeral",
            "isDone":"YES"
         },
         {
            "title":"pick up sis",
            "isDone":"YES"
         },
         {
            "title":"another added task",
            "isDone":"YES"
         },
         {
            "title":"go shopping"
         }
      ]
   },
   {
      "title":"next project",
      "tasks":[
         {
            "title":"next project next task 1"
         },
         {
            "title":"next task 2",
            "isDone":"YES"
         }
      ]
   }
]

staring point modifying ‘index.html’

in the previous post I added an icon that when clicked would edit an item by opening a modal dialog.

...
<ion-list>
  <ion-item class="item" ng-repeat="task in activeProject.tasks">
  {{task.title}}
    <i class="icon ion-edit" ng-click="editTask($index, task)"></i>
  </ion-item>
</ion-list>
 ...

We will add a checkbox to the left to indicate the task is done

modify ‘index.html’ to add a checkbox

...
<ion-list>
  <ion-item class="item" ng-repeat="task in activeProject.tasks">
    <ion-checkbox class="item-text-wrap" style="border:none;" ng-model="task.isDone"  ng-model="task.isDone" ng-click="doneClicked($index, task)" ng-true-value="'YES'" ng-false-value="'NO'"><span>{{task.title}}</span></ion-checkbox>
    <i class="icon ion-edit" ng-click="editTask($index, task)"></i>
  </ion-item>
</ion-list>
 ...

The ion-checkbox directive came to mind first (see the ionic documentation), but it did not look correct since there was a box around the input that clashed with the display of the item. I finally used a style='boder:none;' to remove this. Also, i noticed that if the task was too long it used elipse, but I thought wrap would be better so I added the class ‘item-text-wrap’ and that did the trick.

Also, notice that I am explicitly setting the value of isDone to ‘YES’ or ‘NO’ using the ng-true-value and ng-false-value to match the persisted json described above.

When the check box is checked I wanted to assure that the change was persisted so I added an ng-click event to call doneClicked($index, task) as usual I am passing $index variable indicating the index of the tasks array that will be modified. I am also passing task to be consistent (but not necessary).

I then added the doneClicked method to ‘app.js’ to persist the changes

added after the editTask method

// Make sure to persist the change after is done is toggled
  $scope.doneClicked = function(i, task) {
    //alert("toggle done task "+task.isDone)
    if (!$scope.activeProject || !task) {
      return;
    }
    Projects.save($scope.projects);
  }

this method simply checks if the parameters are correct and if so, persistes the change to the projects using Projects.save method.

Alternate approach to a checkbox

Another approach I tried was to handle the graphics myself, rather than use a checkbox:

...
<ion-list>
  <ion-item class="item" ng-repeat="task in activeProject.tasks">
  <i class="icon ion-ios7-circle-outline " ng-hide="task.isDone=='YES'" ng-click="toggleDone($index, task)"></i>
  <i class="icon ion-checkmark-circled" ng-show="task.isDone=='YES'" ng-click="toggleDone($index, task)"></i>
  <span  ng-click="toggleDone($index, task)">{{task.title}}</span>
    <i class="icon ion-edit" ng-click="editTask($index, task)"></i>
  </ion-item>
</ion-list>
 ...

Notice in this version I am using two icons alternating between them depending on the state of task.isDone using the ng-show and ng-hide directives. I found the ionic icons to use (in the ionicons documentation). However, this forces a specific representation of a checkbox rather than leveraging the native selection of the underlying os. In this version I must change the value of the task.isDone as shown in the following toggleDone method (added to ‘app.js’):

// Make sure to persist the change after is done is toggled
  $scope.toggleDone = function(i, task) {
    //alert("toggle done task "+task.isDone)
    if (!$scope.activeProject || !task) {
      return;
    }
    $scope.activeProject.tasks[i].isDone = ($scope.activeProject.tasks[i].isDone=="YES")?"NO":"YES";
    Projects.save($scope.projects);
  }

added the check box to the ‘edittask.html’ form script in ‘index.html’

added after the <label> tag

...
<form ng-submit="updateTask(taskIndex, task)">
  <div class="list">
  <label class="item item-input">
    <input type="text" placeholder="What do you need to do?" ng-model="task.title">
    </label>
    <ion-checkbox ng-model="task.isDone"  ng-model="task.isDone" ng-true-value="'YES'" ng-false-value="'NO'">task is done</ion-checkbox>
  </div>
  <div class="padding">
    <button type="submit" class="button button-block button-positive">Update Task</button>
  </div>
</form>
...

the <ion-checkbox> directive is used here to set the state of done to ‘YES’ or ‘NO’ value once again.

the code sample can be found on my github page

next article in series