Implement sorting functions for Requests

One of the goals for this OBS Mobile Project to make the list of requests sortable, by date/time, requester, target project/package, and request state.

Basically, there are two options:

1. Do the sorting on the client side with JavaScript (mobile_views/home/requests.html.erb). In other words, simply rearrange the UI elements in JavaScript. This option sends the list of available requests to the client browser, and the sorting happens there without sending further requests to the server on changing the ordering criteria.

2. Do the sorting on the server side in the controller (request_controller) and make the mobile view render only that list. This option requires a round-trip to the server with a parameter indicating how the list should get rendered. The controller prepares the new list, which then gets rendered by the mobile view.

The first option is apparently preferred over the second one.

In the OBS webui, we use the jquery.tablesorter.js plugin to do client side sorting with JavaScript. So I opened up the standard HTML web-browser version of the request list http://localhost:3000/home/requests?force_view=normal to see how the tablesorter.js works in action. I could understand how it worked in the HTML web browser, but in the end I couldn’t figure out how to use the tablesorter.js in mobile view, since the list of request is not really a table.

Then, I attempted to make the list sortable with the help of an acts_as_list plugin. In theory, it looked like it would work. First of all, I tried to create a position column to the request list so as to construct a table:

generate migration add_position_to_requests
rake db:migrate

Next, I created a <ul> of requests that belong to a given user. Each <li> contains a request, and I just have to “stage” the element’s IDs when I serialize the list using jQuery.

I also created a span with a class of “handle”, which is where the user sorts the requests.

Then, I used jQuery’s sortable() function and wired in JavaScript in the view:


<% content_for :javascript do %>

 <% javascript_tag do %>
 axis: 'y',
 handle: '.handle',
 cursor: 'move',
 items: 'li',
 opacity: 0.4,
 scroll: true,
 update: function(){
 type: 'post', 
 data: $('#requests-list').sortable('serialize') + '&id=<>',
 dataType: 'script',
 complete: function(request){
 url: '/list_request/sortby'})
 <% end %>
<% end %>

This  didn’t work, either. The class that has this extension specified needs to have a +position+ column defined as an integer on the mapped database table, like this:


  class TodoList < ActiveRecord::Base
    has_many :todo_items, :order => "position"

  class TodoItem < ActiveRecord::Base
    belongs_to :todo_list
    acts_as_list :scope => :todo_list


However, this seemed to be an overkill for this project, as there is no request table. The list of requests is directly loaded from the API, not stored on the webclient.

I checked out a few Android apps to see how they implemented sortable lists. I found Zaarly (a local community marketplace, launched in Chicago, US). It has a neat UI for sorting items and looks pretty much like what I want to achieve:

Looks like this app has a list of items (perhaps ordered by item ID or just randomly), and each item in the list has 3 elements / attributes:

  • distance from where the user is;
  • date/time the item is posted;
  • price of the item.

There are 3 sorting buttons at the top:

  • distance
  • time
  • price

Whenever a uses taps a sorting button, it’s calling a sorting function to rearrange the list of items based on element values. I don’t think there is a round-trip call to the server, because sorting in this app takes only the blink of an eye. So how is this implemented? Inset lists?

Maybe I could do the same with the requests: list the requests by request_id, and give each request 4 elements: date/time, requester, target project/package, and state. Then implement a function to rearrange the list based on an element’s value whenever that element is called. In that way, the server doesn’t need to be called, and changes take place in the mobile UI only. Looks like it might work, in theory.

On another note, I’m not sure if there would be much difference in implementing sorting functions between native apps and browser-based apps, but I’ll look into that. Maybe the algorithms are different, but the results will be the same.

To achieve same sorting function in the OBS mobile app, it seems we have to write the JavaScript methods on our own, as the tablesorter.js doesn’t work in mobile view.

Basically, we’ll need to create a list in JavaScript containing the request items and their properties. Then, we’ll need a method that reorders the list based on a given sorting criterion and then re-renders the list. The buttons on top of the page would trigger the reordering and the immediate re-rendering of the list.

A prototype of this concept looks like this:

<script type="text/javascript">

 // build up a javascript array from the request list
 var requestlist = [
<% @requests.each do |req|
 ae = req.submit if req.has_element? :submit
 ae = req.action if req.has_element? :action
 target = ""
 if ae.has_element?(:target)
 target = elide(, 20)
 target += "/ #{elide(, 12)}"
 {"id": "<%= req.value(:id) %>", "target": "<%= target %>", "who": "<%= elide(req.state.who, 12) %>",
 "when": "<%= fuzzy_time_string( req.state.value "when" ) %>", "state": "<%= %>"},
<% end -%>

// render the request list based on given sorting criterion
 function render_list(criteria) {
 console.debug("rendering list, ordered by: " + criteria);
 var list = $("#request_list");

 var requests = requestlist.sort(function(a, b) {
 switch (criteria) {
 case 'date':
 return <;
 case 'requester':
 return a.who > b.who;
 case 'target':
 return <;
 case 'state':
 return a.state < b.state;
 return >;

 list.append("<li data-role=\"list-divider\">Your requests</li>");
 $.each(requests, function() {
 list.append("<a href='<%= url_for :controller => :request, :action => :show %>/" + + "'><li>#" + + " to " + + "<br/>from " + this.who + ", <i>" + this.when + "</i> </a></li>");

 // initial rendering after page load
 $(document).ready(function() {


More polishments need to be done, e.g., highlighting the button of the current ordering, showing the request state, and checking if the sorting has bugs…

I will continue working on this implementation, and update the post when I get some results.