Tuesday 30 August 2011

Thoughts on UI – disable or hide..?

To guide the user on what he/she is expected to do gives a very high user experience. For instance, disable the save button until required fields are filled in and are validated. Maybe even make the button the user “should” click greenish to emphasize that it is the expected button to use. Sure, some things may take a while to validate and then it’s not suffice to let the user wait for the save button to be enabled, but that’s another story. User “errors” should be caught as early as possible! Because that’s what we  are used to in the real world – we are utterly bombarded with feedback all the time! E.g. try to open a door! You will instantly feel if it is locked or not. You don’t click the “open” button and cross your fingers that you did everything correct so the door will open…

And it works for more things then just a save button. To disable things the user is not supposed to touch until expected aids the user in a very good way.

But is it even better to hide things?

It’s a tough question. Here’s my thoughts.

It’s good to hide things if it confuses the user and isn’t relevant. If the user is presented with to much information at one time he/she doesn’t know what to do. That’s a known psychological phenomenon called choice overload phenomenon.

But at the same time, it’s good to know what to expect. To hide a save button would be terrible. If you see a form with no save you would probably leave it untouched. Then it’s better to disable instead of hiding.

But when do you know when things are confusing and should be hidden or when they should be disabled to let the user know what he/she is expected to do?

Simple. Talk to the users! Ask them! Show them the alternatives! “What do you think is better? This?”

mockup1

“Or this?”

mockup2

Thursday 11 August 2011

jqGrid MVC model

I really love jqGrid! If you haven’t used it before – try it! http://www.trirand.com/blog/
To be able to use it with ASP.NET MVC and JSON I created a generic model class to easier reuse it when passing it around in MVC actions in the controller.
To load jqGrid with data (JSON) I call an MVC action like this:
   1: $('#StoreGrid').jqGrid({
   2:         url: '<%=Url.Action("StoreList", "StoreController") %>',
   3:         datatype: 'json',
   4:         mtype: 'POST',
   5:         colNames: ['Store Name', 'Store Address'],
   6:         colModel: [
   7:             { name: 'Name', index: 'Name' },
   8:             { name: 'Address', index: 'Address'},
   9:         ]
  10: ...
Just an example, you get the point. Then in my action I do:
1: public JsonResult StoreList(string sidx, string sord, int page, int rows)
2: {
   3: ...
   4:     // Load data from repository
   5:     IQueryable<Store> stores = _repository.GetAllStores();
   6:     int totalRecords = stores.Count();
   7:     int totalPages = (int)Math.Ceiling(totalRecords/(double)rows);
   8:  
   9:     // Convert business model to view model
  10:     List<StoreListItem> storeListItems =
  11:         stores 
  12:         .Select(s => new StoreListItem(s.Id, s.Name, s.Address)
  13:         .ToList();
  14:  
  15:     // Create JSON data that jqGrid understands :-)
  16:     var jsonData = new JqGridJsonModelView<StoreListItem>
  17:        {
  18:          total = totalPages,
  19:          page = page,
  20:          records = totalRecords,
  21:          rows = storeListItems
  22:        };
  23:     return Json(jsonData, JsonRequestBehavior.AllowGet);
Ignore the repository stuff, paging and sorting is ignored here for simplicity – you shouldn’t – hence the totalPages calculation is redundant (but it wont be if you call e.g. GetStores() and pass paging and sorting parameters to it). Anyway, the key here is the JqGridJsonModelView<T> class. With it I can create any class (in this case StoreListItem) and it will create JSON data that jqGrid understands. Lovely! But what does it do? It’s really simple:
1: /// <summary>
2: /// See http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#json_data
   3: /// </summary>
   4: public class JqGridJsonModelView<T> where T : IHaveJqGridCells
   5: {
   6:     /// <summary>
   7:     /// Total number of pages
   8:     /// </summary>
   9:     public int total { get; set; }
  10:  
  11:     /// <summary>
  12:     /// Current page
  13:     /// </summary>
  14:     public int page { get; set; }
  15:  
  16:     /// <summary>
  17:     /// Total number of records
  18:     /// </summary>
  19:     public int records { get; set; }
  20:  
  21:     public IList<T> rows { get; set; }
  22: }
The property names has a bad naming here, but it must corrolate with jqGrid (http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#json_data). T here is the model, in this case StoreListItem. But what’s IHaveJqGridCells? Again, simple:
1: public interface IHaveJqGridCells
   2: {
   3:     string id { get; set; }
   4:  
   5:     string[] cell { get; }
   6: }
Bad naming, as said before, but it’s what jqGrid uses. So, all we have to do is let StoreListItem implement IHaveJqGridCells:
1: public class StoreListItem : IHaveJqGridCells
2: {
   3:     // Implement interface
   4:     public string id { get; set; }
   5:  
   6:     // Private properties to "disable" serialization (no need to be public anyway)
   7:     readonly string Name;
   8:     readonly string Address;
   9:  
  10:     public StoreListItem(int id, string name, string address)
  11:     {
  12:         this.id = id.ToString();
  13:         
  14:         Name = name;
  15:         Address = address;
  16:     }
  17:  
  18:     // Implement interface
  19:     public string[] cell
  20:     {
  21:         get
  22:         {
  23:             return new[] { Name, Address }
  24:         }
  25:     }
  26:  
Voila! We’re done! Now this class will be serialized into JSON (by MVC action). The serialized result will look like this:
1: {
   2:   "total" : "xxx", 
   3:   "page" : "yyy", 
   4:   "records" : "zzz",
   5:   "rows" : [
   6:     {"id" : "1", "cell" : ["Store 1", "Address 1"]},
   7:     {"id" : "2", "cell" : ["Store 2", "Address 2"]},
   8:       ...
   9:   ]
  10: }
Now it’s really easy to extend the model and/or reuse it.

Hope you like it!

Update (requested by danlimerick):
If you want to do sorting/paging. I usually use Dynamic Linq Query Library and make sure the naming in the jqGrid colModel corrolates to the naming in the repository:
1: IQueryable<Store> stores = _repository.GetStores(sidx, sord, (page - 1), rows);
   2:  
   3: ...
   4:  
   5: public IQueryable<Store> GetStores(string sortIndex, string sortOrder, int page, int rowsPerPage)
   6: {
   7:     return _context.Store
   8:                 .OrderBy(sortIndex + " " + sortOrder)
   9:                 .Skip(page * rowsPerPage)
  10:                 .Take(rowsPerPage);
  11: }
I wouldn’t call it elegant, but it’s a pretty convenient way.