Tuesday, March 10, 2015

Responsive Data Tables

Having trouble fitting your tables into a responsive site?
They look great on a desktop layout, but look miserable on mobile.

The Basics

First remove any fixed widths from your markup.
Before:
<table width="540">
  <tr>
    <td width="300">Header 1</td>
    <td width="60">Header 2</td>
    <td>Header 3</td>
    <td>Header 4</td>
  </tr>
</table>
After:
<table>
  <tr>
    <td>Header 1</td>
    <td>Header 2</td>
    <td>Header 3</td>
    <td>Header 4</td>
  </tr>
</table>
The width attribute is deprecated – better to let the browser size the columns. If you don’t know much about tables, have a read through this massive guide to tables at css tricks.

Basic Styling

First some padding and borders.
table {
    border-collapse: collapse;
    border-spacing: 0;
    border: 1px solid #bbb;
}
td,th {
    border-top: 1px solid #ddd;
    padding: 4px 8px;
}
Then some striped rows (nth-child is not supported by IE8).
tbody tr:nth-child(even)  td { background-color: #eee; }

Mobile-Friendly Table

As the viewport gets smaller, the table width will shrink. However depending on how many columns you have the table which reach a minimum size. This will probably wider than a mobile viewport, and your layout will be broken.
You could allow the table to horizontal scroll, without breaking your layout. First we have to change the display: to block; and set overflow-x: toauto; – You may want to use a media query to only do this for small devices.
Note: It’s better syntax to wrap the table in a DIV that has overflow-x: scroll;
@media screen and (max-width: 640px) {
 table {
  overflow-x: auto;
  display: block;
 }
}
And here’s what we get (this is the amount of caffeine in Starbucks coffee via my site Caffeine Informer). Note that if you have a table that has only a few columns, display: block means they will not resize fit across the full width of the table (if the table is set to 100% width).
DESKTOP
BeverageShort (8 oz)Tall (12 oz)Grande(16 oz)Venti (20-24 oz)Trenta(31oz)
Brewed Coffee180mg260mg330mg415mg-
Brewed Decaf Coffee15mg20mg25mg30mg-
Caffè Americano75mg150mg225mg300mg-

MOBILE (scroll to the right)
This is what happens in mobile (320px wide). The user can swipe right and left to horizontal scroll the table.
The trouble is, the user has no indication that they can swipe to the right.
BeverageShort(8 oz)Tall(12 oz)Grande(16 oz)Venti(20-24 oz)Trenta(31oz)
Brewed Coffee180mg260mg330mg415mg-
Brewed Decaf Coffee15mg20mg25mg30mg-
Caffè Americano75mg150mg225mg300mg-

ALTERNATIVE MOBILE LAYOUT
If you resize this page (or you are viewing it on a mobile device), you will notice a third layout where the columns have been translated into a single column.
vert-table
Here, I’ve combined the table cell data with its column header.
Now to other much more powerful options…

1. Footable – jQuery

respt1-d
Mobile - 2nd row clicked.
Mobile – 2nd row clicked.
This excellent plugin allows will hide columns of your choosing. When the row is clicked (or tapped) the columns will fold out below the row.
I’ve used an early version of this on Caffeine Informer, and it works well. More recent versions have substantially more features added.
  1. Give your tables the appropriate data attributes (which columns should be hidden by default).
  2. Ensure the breakpoints are correct (default 480px and 1024px).
  3. Call the footable() function for the appropriate tables.

 2. Foundation Zurb – Lock first column

respt2-d
Mobile - first column is locked.
Mobile – first column is locked.
The solution from the Zurb framework is to lock or pin the first column and make the rest of the table scrollable.
To accomplish this they use a small piece of jQuery to manipulate the DOM, and some CSS.
Also see an interesting tutorial on how to add visual cue when the table is going to scroll: design4lifeblog.com/responsive-tables/ — site seems to have disappeared – James.

3. Stacktable

respt3-d
Mobile - everything is one column.
Mobile – everything is one column.
This piece of jQuery will take a table and turn it into one long column of data.

4. Responsive Tables

respt4-d
respt4-m
Mobile – Fonts are scaled
This rather intriguing jQuery script will scale font size of the table according to data attributes.
In the above example, the table tag contains two attributes data-max="30"and data-min="11" indicating a minimum and maximum pixel font size.

5. Filament Group – Tablesaw

swipe-minimap
This jQuery solution offers all kinds of different options for table display.
fgmode-switch
From selectable columns, to swipable columns. As well as prioritizing columns.
There’s a lot of different options in their github repository. This is truly the kitchen sink of responsive tables.

6. TablePress – WordPress

respt6-d
respt6-m
Mobile view, header column is locked.
TablePress is a WordPress plugin that utilizes the powerful Datatables jQuery plugin. Datatables is one of the most feature-rich plugins for tables (sorting, filtering, paging, etc).
TablePress has a responsive extension which turns the table on its side, locking the header column in place. Datatables.js is very powerful, but does add considerably to page weight.

7. ngResponsiveTable

respt7-d
Mobile - data is presented vertically.
Mobile – data is presented vertically.
This small jQuery script will turn each row into its own vertical list. Rather than manipulate the DOM (by adding and removing table cells), it puts the header info as a data attribute (data-content) into each td element. The stylesheet then displays this using content: attr(data-content). Quite a clever idea.

8. Codepen by Charlie Cathcart

This clever example uses CSS to accomplish the save as previous but without any JavaScript.

9. Codepen (Dudley Story)

This uses a short (non-jQuery) Javascript to create data attributes into table cells. Then utilizing a CSS media query takes the attributes to format a mobile display.
Desktop layout
Desktop layout
Mobile
Mobile
Nice work.

11. Codepen (Geoff Yuen)

No Javascript, but requires data attributes to be entered into each cell.
resp11d
Desktop Layout
Mobile LAyout
Mobile Layout


Using DataPager in ListView

if the DataSource is not known statically at design time, the DataPager may not work correctly. The following error could be expected to happen when you click on the link provided by DataPager at the second time:
Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate during the previous request. For example, when adding controls dynamically, the controls added during a post-back must match the type and position of the controls added during the initial request.
This problem occurs because the DataPager has no idea how to perform or calculate paging for you without knowing what page is supposed to display (i.e., StartIndex, and MaximuumRows in the page) when the DataSource is only known at runtime. Thus, you need to provide this missing piece of information to the DataPager before databinding.
Under Google search, you may find that quite a few people implemented the PreRender event of DataPager to perform databinding. Unfortunately, it doesn't work for this scenario. You can bind the data at DataPager's PreRender event but you are unable to supply paging properties to DataPager as mentioned above. Both StartRowIndex and MaximumRows properties are needed to set for paging before databinding. This problem took me a few hours to resolve. It turns out that the solution is very simple.
The Solution: You should add and implement the PagePropertiesChanging event of ListView. ThePagePropertiesChangingEventArgs from the event argument will provide all your needy paging properties (StartRowIndex and MaximumRows) so that you can supply them to the DataPager.
    protected void ListView1_PagePropertiesChanging(object sender, PagePropertiesChangingEventArgs e) {     
      this.DataPage1.SetPageProperties(e.StartRowIndex, e.MaximumRows, false);
      BindData();  // set DataSource to ListView and call DataBind() of ListView
    }
If the DataPager is placed inside the ListView, do this:
    protected void ListView1_PagePropertiesChanging(object sender, PagePropertiesChangingEventArgs e) {
      ListView lv = sender as ListView;
      DataPager pager = lv.FindControl("DataPage1") as DataPager;
      pager.SetPageProperties(e.StartRowIndex, e.MaximumRows, false);
      BindData();  // set DataSource to ListView and call DataBind() of ListView
    }

Editing ASP.NET ListView Control using JQuery AJAX and Web Services

http://www.ezzylearning.com/tutorial/editing-asp-net-listview-control-using-jquery-ajax-and-web-services
JQuery is growing in stature day by day and so as the number of interesting scenarios in which it can be used in modern web applications. One of the very common UI requirements is to display the tabular data on page in controls such as ASP.NET GridView or ListView and then provides record editing facility using a popup dialog through which user can update data in the backend database as well as in the front end control asynchronously without a full server post back. There are very few tutorials online, which shows how to put together a complete example of using ASP.NET ListView control to display data, JQuery code to display Popup Dialog, AJAX code to send asynchronous calls to the server, ADO.NET code to select/update backend database and ASP.NET web service. In this tutorial, I will show you how to use all these pieces of the jigsaw puzzle together to implement a complete online record editing scenario.
Before you start reading this tutorial I am making a silly assumption that you know the basics of ASP.NET ListView control and also know how to call web services using JQurey AJAX. If you don’t then I recommend that you must read my other tutorials on ListView control, JQuery, AJAX and Web services before reading this tutorial. Even if you are not fully familiar with all these technologies than don’t stop reading, just follow this tutorial from the start to end, and you will be able to understand everything quite easily without losing too many hairs on your head.
Editable Listview using JQuery

To get started, create an ASP.NET website and drag the ListView control on the page from the toolbox. ASP.NET ListView control is introduced in ASP.NET 3.5 and it enables you to bind and display data items individually or as a group. It supports paging, sorting, selections, editing, insertions, deletions and many other cool features. It also gives developers full control on the HTML markup rendered on the page with the help of templates. In this tutorial, we will use LayoutTemplate which defines the main layout of the control andItemTemplate which defines the data bound content to display for a single item. The following markup shows ListView control used in this tutorial. 

  
     
        
           
           
           
           
        
        
           
        

     
IDNameFee

  

  
     
        
            Edit                onclick="EditStudent(this);" />                    
        
        
            <%# Eval("ID") %>
        
        
            <%# Eval("Name")%>
        
        
            <%# Eval("Fee")%>
        
     
  

In the markup above, the ListView control LayoutTemplate is defining the main layout of the control using the HTML table element. The other noticeable thing is the use of onclick event for the img element which is callingEditStudent JavaScript function. The EditStudent function will display the following edit form in a popup dialog each time user will click the Edit Icon. Define the following editForm div element just below to the ListView control in your page HTML markup. 
editForm
" class="editForm">
  
     
        
        
Edit Student
            onclick="CloseEditStudentDialog();"
 style="cursor: pointer;">Close
        
     
     
         ID:
        
     
     
         Name:
        
     
     
         Fee:
        
     
     
        
        
            
        
     
  


You may have noticed that two more JavaScript functions CloseEditStudentDialog and UpdateStudent are being used in the edit form HTML markup above. I will show you the JavaScript code of all these functions later in this tutorial. 

Next step is to create an ASP.NET web service that will be responsible to fetch student records from the database table and will also provide a method to update the record. Add an ASP.NET web service in your project with the name StudentWebService.asmx and define two methods GetStudents and UpdateStudentin the code behind file of the web service. Here is the complete code for the web service.

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class StudentWebService : System.Web.Services.WebService {

    public StudentWebService () {

        //Uncomment the following line if using designed components 
        //InitializeComponent(); 
    }

    [WebMethod]
    public DataTable GetStudents()
    {
        string constr = @"Server=TestServer; Database=SampleDB; uid=waqas; pwd=123";
        string query = "SELECT ID, Name, Fee FROM Students";
        SqlDataAdapter da = new SqlDataAdapter(query, constr);
        DataTable table = new DataTable();
        da.Fill(table);
        return table;
    }


    [WebMethod]    
    public int UpdateStudent(int id, string name, decimal fee)
    {
        SqlConnection con = null;
        string constr = @"Server=TestServer; Database=SampleDB; uid=waqas; pwd=123";
        string query = "UPDATE Students SET Name = @Name, Fee = @Fee WHERE ID = @ID";

        con = new SqlConnection(constr);
        SqlCommand command = new SqlCommand(query, con);
        command.Parameters.Add("@Name", SqlDbType.NVarChar).Value = name;
        command.Parameters.Add("@Fee", SqlDbType.Decimal).Value = fee;
        command.Parameters.Add("@ID", SqlDbType.Int).Value = id;

        int result = -1;
        try
        {
            con.Open();
            result = command.ExecuteNonQuery();
        }
        catch (Exception)
        { }
        finally
        {
            con.Close();
        }
        return result;
    }
    
}

In the above code, notice the use of ScriptService attribute on top of the class definition. This attribute is required to communicate with the web service from JavaScript. For brevity, I used hard coded connection strings in the methods above. You can store connection strings in web.config in your web application. You may also need to change connection string parameters such as serverdatabaseuser id or password according to your machine environment. I used a simple database table Student with three columns ID, Name and Fee in this tutorial. You can create this table in your SQL Server database for the implementation of this tutorial. The code is using basic ADO.NET SqlConnection, SqlCommand, SqlAdapter and DataTable objects to retrieve and update data in the database. We need to call GetStudents method on the page load event to display student records on ListView control. Following code shows how to use the web service in Page Load event.
protected void Page_Load(object sender, EventArgs e)
{
   if (!Page.IsPostBack)
   {
      StudentWebService service = new StudentWebService();
      ListView1.DataSource = service.GetStudents();
      ListView1.DataBind(); 
   }
}

Add the following CSS styles in the head section of your page and run the application. You will see the ListView control showing student records as shown in the figure below.


Editable Listview using JQuery

Now is the time to make small edit icon working and showing user the popup dialog form to edit student records. For this we need to write some JavaScript functions and JQuery code in the page. Add the following JQuery library reference in the head section of the page. 

Next add the HTML script block and declare some variables to keep track of the editable row and to store the current student data as shown below:


Inside ListView control, the edit icon image has defined onclick event, which calls EditStudent JavaScript function. So this is the first function you need to define in JavaScript code block. 
function EditStudent(editButton) 
{
   row = $(editButton).parent().parent();
   id = $("#id", row).text();
   name = $("#name", row).text();
   fee = $("#fee", row).text();
   row.addClass("highlightRow");
   DisplayEditStudentDialog();
   return false;
}

The EditStudent function is storing the reference of the current row in the row variable declared above. Then it finds the idname and fee span elements in the current row and stores their text in other three variables. Finally, it calls DisplayEditStudentDialog function to show the popup dialog.

function DisplayEditStudentDialog() 
{
   $("#spnID").text(id);
   $("#txtName").val(name);
   $("#txtFee").val(fee);
   $("#editForm").show();
}

The DisplayEditStudentDialog first stores the values of idname and fee variables in span and text boxes in the dialog box and then calls JQuery show method to display the following editForm on the screen.

Editable Listview using JQuery

When user clicks update button, the following UpdateStudent function is called that used JQuery AJAX function to call UpdateStudent method defined in Web Service code. It passes idname and fee as parameters in JSON format to the web service and on the success execution of the web service method it updates span elements in the ListView control and calls CloseEditStudentDialog. If you are not familiar with JQuery AJAX, JSON and Web Service calls and want to learn more about them then I will recommend you to read my other JQuery tutorials on this website. 
function UpdateStudent(e) 
{
   name = $("#txtName").val();
   fee = $("#txtFee").val();

   $.ajax({
      type: "POST",
      url: "StudentWebService.asmx/UpdateStudent",
      data: "{'id':'" + id + "', 'name':'" + name + "', 'fee':'" + fee + "'}",
      contentType: "application/json; charset=utf-8",
      dataType: "json",
      success: function(response) 
      {
         var result = response.d;
         if (result > 0) 
         {
            $("#name", row).text(name);
            $("#fee", row).text(fee);
            row.removeClass("highlightRow");
            CloseEditStudentDialog();
         }
         else 
         {
            alert('There is some error during update');
         }
      },
      failure: function(msg) 
      {
         alert(msg);
      }
   }); 
   return false;
}

Finally, we need CloseEditStudentDialog function to hide the popup dialog from the screen on successful update.
function CloseEditStudentDialog() 
{
   $("#editForm").hide();
   row.removeClass("highlightRow");
}

I hope you have learned many new techniques in this tutorial, and you have implemented the complete tutorial successfully. . 

Popular Posts

Recent Posts

Unordered List

Text Widget