esafwan
esafwan

Reputation: 18029

Toggling through values of a Json object using Jquery

I have a list of tasks which can have 4 possible states taken from a json object.

"Not Done", "Done", "Doing", "Later"

This states are stored in an object which is basically loaded via json.

var states = {  status: ['doing','done', 'later' ]  };

Tasks are loaded from another json object.

var tasks = [
    {id: 1, text: 'Do something.', status: 'doing'},
    {id: 2, text: 'Undo that thing.', status: 'done'},
    {id: 3, text: 'Redo it again.', status: 'started'},
    {id: 4, text: 'Responsive', status:'later'}
  ];

The html would be something like this.

<ul>
<li><a href="#1">Do something - <span class="status">Doing</span> </a></li>
<li><a href="#2">Undo that thing - <span class="status">Done</span> </a></li>
<li><a href="#2">Redo it again. - <span class="status">Started</span> </a></li>
</ul>

Each time user clicks on the link the status should toggle the value from the states object and loop through them. For example, when use click on a task with status Done, its should become later and when they click again it should become Not Done. This should keep looping each time the user clicks.

What is the best way to do this. I felt if else won't be the right way to do as if the values of states increase or reduce that code will have to be revisited again.

Upvotes: 0

Views: 534

Answers (2)

Kai
Kai

Reputation: 1240

Edit:

I didn't understand 100% of your question. But i think i do now. You want the code to work even on all cases at all time. I've made code a little safer now:

  • if a state contain a faulty entered text (like 'dOne') it will still compare.
  • if a task has a faulty (=non-existent) state, it will just reset itself to the first state available.

Here's an explosion of code, i'm a little tired so you might need to refactor some parts. Also thought it would be easier for you with the documentation included.

If you have more things to say, leave it in the comments and i will try again....!

Working jsfiddle: http://jsfiddle.net/kychan/62sUX/2/

//
//    Retrieve the data with $.get()/AJAX or with an inline
//    echo through PHP/ASP.
//

//    Get states. Make the code extra fuzzy.
var states = {  status: ['doing','dOne', 'Later' ]  };

//    Get the tasks.
//    In this example we do it more quickly.
var tasks = [
    {id: 1, text: 'Do something.',     status: 'doing'},
    {id: 2, text: 'Undo that thing.',  status: 'done'},
    {id: 3, text: 'Redo it again.',    status: 'started'},
    {id: 4, text: 'Responsive',        status: 'later'}
];

//    prepare the retrieved JSON data for fuzzy input.
states.status.forEach(function(e,i,a) {
    states.status[i]=e.toUpperCase();
});
tasks.forEach(function(e,i,a) {
    tasks[i].status=e.status.toUpperCase();
});

//    create the li's.
for (var i in tasks) {
    var item = '<li>'
             + '<a href="#" id="{id}">{text} - '
             + '<span class="status">{status}</span>'
             + '</a>'
             + '</li>'
    ;

    item    = item.replace(/{(\w+)}/g, function (m, n) {
        return (typeof (tasks[i][n]) !== 'undefined') ? tasks[i][n] : '';
    });

    $('ul').append(item);
}

//    Override the states with the button; will make it harder
//    for the code and test it for future proofness.
$('.replace').click(function() {
    //    we will keep 'done' for testing.
    states = {
        status:['CONCEPT', 'ELABORATION', 'CONSTRUCTION', 'TESTING', 'PRODUCTION', 'DONE']
    };
    //    remove the replace link, because after press it's useless.
    $('.replace').detach();
});

//
//    actual code.
//

//    create listeners on the a tags of tag ul.
$('ul a').click(function (e) {
    //    fetch status DOM object and its text before.
    var status = $(this).children('.status');
    var text   = status.html();

    //    iterate through states array.
    for (var i in states.status) {
        //    if the task matches your text, then update it to the next.
        if (text==states.status[i]) {
            //    get next status.
            if ((i++)>=states.status.length-1)  i=0;

            //    update. Don't forget to push the update to the database.
            status.html(states.status[i]);
            return;
        }
    }
    //    state not found. reset it to first. Don't forget to push the update to the DB.
    status.html(states.status[0]);
});

Upvotes: 1

Djizeus
Djizeus

Reputation: 4175

How about something like this?

$('a').click(function(){
  var id = parseInt($(this).attr('href').substring(1));
  var task = tasks.filter(function(t){t.id == id});
  if (task.length) {
    var status = task[0].status;
    var indexStatus = states.status.indexOf(status);
    var nextStatus = null;
    if (indexStatus === states.status.length-1) {
      nextStatus = states.status[0];
    } else if (indexStatus !== -1) {
      nextStatus = states.status[indexStatus+1];
    }
    if (nextStatus !== null) {
      task[0].status = nextStatus;
      $(this).children('.status').text(nextStatus);
    }
  }
});

The idea is to look for the current status in the list, and just reset the index to 0 if it is the last one, otherwise increment it.

I have updated both JSON and HTML, as you did not precise if you want them in sync. The code can be made simpler if you don't need to sync data and view. Also I made all necessary bound checks, I don't know how robust you want the code to be and how much you trust the json data.

Upvotes: 0

Related Questions