Question

To-do list in jQuery

I've followed this excellent tutorial on how to create a to-do list in jQuery:

http://www.youtube.com/watch?v=SkmF8eUOUrE

I've adapted it (and therefore simplified it) slightly by removing the ability to add and remove tasks. Instead the list will be populated by a database and updated every so often. Users will be able to view this task list and tick off which tasks they've done. So every user has the same task list but they can all check off their own personal progress on that task list.

Problem

The part that's missing is getting the browser to remember what tasks the user has done. When a user ticks an item on the list and refresh the page, the list refreshes and the completed tasks are forgotten.

Question

What's the best way to resolve this? I'm thinking of using cookies, but would I need to have a different cookie for every task? The to-do list will be updated regularly so in theory we might need to create thousands of cookies. Is this ok or is there a better way?

Here is my jQuery:

function completeItem(){
if( jQuery(this).parent().css('textDecoration') == 'line-through' ){
    jQuery(this).parent().css('textDecoration', 'none').removeClass('due-linethrough');
}else{
    jQuery(this).parent().css('textDecoration', 'line-through').addClass('due-linethrough');
}
}

jQuery(function() {

jQuery(document).on('click', '.complete', completeItem); 

});

And here's the html

<ul id="noticeboard-list">
<li><label class="checkbox"><input type="checkbox" class="complete">Do task 1</label></li>
<li><label class="checkbox"><input type="checkbox" class="complete">Do task 2</label></li>
<li><label class="checkbox"><input type="checkbox" class="complete">Do task 3</label></li>
</ul>

Many thanks for your help!

Katie

Edits following suggestion to use jstorage from kri5t

Instead of cookies I'm trying to use jstorage. The following shows my new code:

jquery

function completeItem(){

        taskID=jQuery(this).attr('id');

        if( jQuery(this).parent().css('textDecoration') == 'line-through' ){
                jQuery(this).parent().css('textDecoration', 'none').removeClass('due-linethrough');
                jQuery.jStorage.set(taskID, 'done');
        }else{
            jQuery(this).parent().css('textDecoration', 'line-through').addClass('due-linethrough');
            jQuery.jStorage.deleteKey(taskID);

        }
    }

HTML

<ul id="noticeboard-list">
<li><label class="checkbox"><input type="checkbox" class="complete" id="HPtask1">Do task 1</label></li>
<li><label class="checkbox"><input type="checkbox" class="complete" id="HPtask2">Do task 2</label></li>
<li><label class="checkbox"><input type="checkbox" class="complete" id="HPtask3">Do task 3</label></li>
</ul>

When a user ticks the checkbox, the taskID is set to 'done'. When they untick it, it is deleted. But how do I use this information to set the text-decoration to line-through for all checkboxes which have Keys in jstorage (e.g. HPtask1) that correspond with the matching ID (e.g. HPtask1) where the value of the key is 'done'? (Hope that makes sense!).

Thanks again :D

Was it helpful?

Solution 2

Many thanks Kristian - I've managed to achieve what I wanted using jStorage. I've posted my code below for interest. It seems to work - thanks for your suggestion to use jStorage - I've learnt something new! The only thing that would be nice is to expire the individual tasks after 90 days, like a cookie, but I can only see how to expire stuff in units of minutes.

There's only likely to be 4 or 5 tasks on display at any one time as the tasks will expire. But there could be thousands of expired tasks stored in the jStorage data. Would this slow things down or have any negative effect for users? If so, does anyone have any suggestions on how to improve efficiency/expire the old data?

Many thanks again,

Katie

jQuery

function completeItem(){

var taskID=jQuery(this).attr('id');

/*Check whether the task clicked already has a line-through*/
if( jQuery(this).parent().css('textDecoration') == 'line-through' ){

        /*Remove the line through*/
        jQuery(this).parent().css('textDecoration', 'none').removeClass('done');
        jQuery(this).parent().parent().siblings().removeClass('done');

        /*Remove the current task from storage (i.e. forget that it was marked as done)*/
        jQuery.jStorage.deleteKey(taskID)
}else{

    /*Add a line through*/
    jQuery(this).parent().css('textDecoration', 'line-through').addClass('done');
    jQuery(this).parent().parent().siblings().addClass('done');

    /*Add the task to storage (i.e. remember that it has been marked as done)*/
    jQuery.jStorage.set(taskID, 'done');

}
}

jQuery(function() {

/*Create array from task list IDs*/
var taskListIDs = jQuery("ul#noticeboard-list li input").map(function() {return this.id; }).get(); 

//var taskArray = jQuery.jStorage.index();
var n;

/*loop through each item in the array of tasks visible on the page*/
for (n = 0; n < taskListIDs.length; ++n) {

    /*Get the ID of the nth item in the array*/ 
    var uniqueTask = taskListIDs[n];    

    /*Find out whether the current task has been marked as done*/
    var taskStatus = jQuery.jStorage.get(uniqueTask);

    /*Check if the current task in the array has been marked as done*/
    if (taskStatus == 'done'){

        /*Add a line-through and add class to override blue highlighting for an item that's due*/
        jQuery('#'+uniqueTask).parent().css('textDecoration', 'line-through').addClass('done');

        /*Add a tick in the checkbox*/
        jQuery('#'+uniqueTask).prop('checked', true);

        /*Add class to override highlighting*/
jQuery('#'+uniqueTask).parent().parent().siblings().addClass('done');

    }
}


/*every time user clicks on item, check if it has the class .complete. If yes, perform competeItem.*/
jQuery(document).on('click', '.complete', completeItem); 

});

HTML

        <ul id="noticeboard-list">
            <li><div class="task"><label class="checkbox due"><input type="checkbox" class="complete" id="HPtask24">Task 1</label></div><div class="due-date due">Feb<br><span>27</span></div></li>
            <li><div class="task"><label class="checkbox"><input type="checkbox" class="complete" id="HPtask31">Task 2</label></div><div class="due-date">Mar<br><span>19</span></div></li>
            <li><div class="task"><label class="checkbox"><input type="checkbox" class="complete" id="HPtask54">Task 3</label></div><div class="due-date">May<br><span>06</span></div></li>
        </ul>

OTHER TIPS

This framework is excellent for storing data locally: http://www.jstorage.info/

You can add elements with key/value for each of your tasks for example

key = ID of element

value = if it has been done or not

Then each time you load your application you check if data is present. If there is some data locally stored you check all the tasks done.

EDIT TO ANSWER EDIT:

There is a couple of things you have to consider when doing this. First of all if you wish to add dynamic questions I think the best way would to turn your radio button into JSON objects. This way you can save the JSON object in the local storage and when the user revisits the page you load all the check boxes dynamically. You should look into how to turn a checkbox into a json object and how you reload it. It is quite a simple technique.

For example you could store the text of the checkbox and whether it was checked or not in a json object. When you reload the entire page you run through every element stored and the recreate new checkboxes with the text and the boolean stored.

You can load everything in the local storage by using the index() method. It gives you all the keys that are stored in the local storage. Then you can loop through all these keys and load the booleans that you have saved and then act accordingly.

I hope this makes sense or else let me know.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top