Topic: Check boxes for a task list a-la Basecamp

I'm trying to figure out how I can reproduce the to-do list functionality in Basecamp. I have a Task model where status can be either be complete or ongoing. Here's how I retrieve tasks for a particular user in my task controller:

  def user
    @user = User.find(params[:id])
    @pending_tasks = @user.pending_tasks
    @completed_tasks = @user.completed_tasks
  end

In the view I do this:
[code=]<h2 class="title">Tasks for <%= @user.name %></h2>
<div id="project_tasks">
<% unless @user.tasks.empty? %>
<h3>On-going tasks</h3>
<dl id="pending_task_list">
<%= render :partial => 'user_pending_task', :collection => @pending_tasks %>
</dl>

<h3>Completed tasks</h3>
<dl id="completed_task_list">
<%= render :partial => 'user_completed_tasks', :collection => @completed_tasks %>
</dl>
<% else %>
<p><%= @user.first_name %> hasn

Last edited by gmacgregor (2007-01-27 16:53:13)

Re: Check boxes for a task list a-la Basecamp

onclick you would want to do an AJAX action. The remote_function is a great way to do this.

:onclick => remote_function(:action => 'complete_task', :id => user_pending_task)

Now to implement this action:

def complete_task
  @task = Task.find(params[:id])
  @task.complete!
end

It's up to you to implement this "complete!" method in the task model - it should mark the task as complete and save it.

Obviously we still need to update the view, you can do this with a little bit of RJS:

# views/task/complete_task.rjs
page[:pending_task_list].replace_html :partial => 'user_pending_task', :collection => @task.user.pending_tasks
page[:completed_task_list].replace_html :partial => 'user_completed_task', :collection => @task.user.completed_tasks

You need to do something similar for unchecking a completed action, but that will be a good exercise for you to use what you learned here. Bonus points if you can remove the duplication with that action. big_smile

Railscasts - Free Ruby on Rails Screencasts

Re: Check boxes for a task list a-la Basecamp

Thanks Ryan... I think I'm on the right track but the status never updates and the RJS never happens (I use firebug to look at the response and I just get ...loading):

#user_pending_task partial
<span id="<%= "task_#{user_pending_task.id}" %>">
<dt class="pending_task"><%= check_box "task", "pending_#{user_pending_task.id}", { :onclick => remote_function( :url => { :controller => 'task', :action => 'change_status', :id => user_pending_task , :status => 'complete' }) } %><%= user_pending_task.name %></dt>
</span>

#user_completed_task partial
<span id="<%= "task_#{user_completed_task.id}" %>">
<dt class="completed_task"><%= check_box "task", "completed_#{user_completed_task.id}", { :onclick => remote_function( :url => { :controller => 'task', :action => 'change_status', :id => user_completed_task , :status => 'ongoing' }) }, "complete" %><%= user_completed_task.name %></dt>
</span>

#change_status method in the task_controller
def change_status
  @task = Task.find(params[:id])
  @task.update_attribute(:status, params[:status])
end

#change_status.rjs
page[:pending_task_list].replace_html :partial => 'user_pending_task', :collection => @task.user.pending_tasks
page[:completed_task_list].replace_html :partial => 'user_completed_task', :collection => @task.user.completed_tasks
page.visual_effect :highlight, "task_#{@task.id}"


Ideas about what I'm doing wrong here?

Re: Check boxes for a task list a-la Basecamp

Check out the development log, is the server receiving any requests? Did you add the javascript files in the header?

<%= javascript_include_tag :defaults %>

Railscasts - Free Ruby on Rails Screencasts

Re: Check boxes for a task list a-la Basecamp

The problem was that I was using an undefined method in the view to evaluate whether or not a check box should be checked. This works:

#user_pending_task partial

<% @task = user_pending_task %>

<div id="<%= "task_#{@task.id}" %>">
<dt class="pending_task"><%= check_box "task", "status", { :onclick => remote_function( :url => { :controller => 'task', :action => 'change_status', :id => @task , :status => 'complete' }) }, "complete", "ongoing" %><%= @task.name %></dt>

#user_completed_task partial

<% @task = user_completed_task %>

<div id="<%= "task_#{@task.id}" %>">
<dt class="completed_task"><%= check_box "task", "status", { :onclick => remote_function( :url => { :controller => 'task', :action => 'change_status', :id => @task, :status => 'ongoing' }) },  "complete", "ongoing" %><%= @task.name %></dt>


Noe that I'm assigning an instance variable to the local partial variable name. After a lot of hair pulling I realized that the check box uses an instance variable to determine whether or not it is checked -- using a local in a partial won't work!