Smart Grid Component
The smart grid component extends the [Grid Component] with a lot more dynamic behavior. While the [Grid Component] is suitable for cases where you want absolute control of the output, the Smart Grid Component is focused in providing a fast approach to building grid of collection of entities.
Because of that, the Smart Grid Component makes several assumptions about its usages, specifically, that you are using it to display entities (business objects) and that you want to easily get something working. As a result the Smart Grid Component offers many tweaking options, but somewhat limits what can be done.
Note: For the really complex cases, there is no escape from rolling your own grid. The Smart Grid Component can go for a long way, but always consider the maintainability of the end result. Often, when complexity demands it, it is much easier to roll a one time solution than try to manage using general approaches.
At the most basic level, you can use the Smart Grid Component (known as SGC from now on) like a WebForms' GridView with AutoGeneratedColumns = true:
component SmartGrid, {@source: users}
This will generate a grid of all the users in the data source, using all the user properties as the columns of the grid.
It will also try to transform "PascalCase" property names into "Pascal Case" column header names, if possible.
Ignoring certain properties:
You can choose to not display certain properties by passing parameters to the component:
component SmartGrid, {@source: users, @displayUserId: false}
The SGC will check for a "display[PropertyName]" parameter and will skip display it if it is false.
Columns ordering:
Since the SGC uses reflection in order to get the properties, the order of the columns in the grid is essentially random (it is likely to be source code order, but there is no guarantees). The SGC provide the columns parameters as a way to provide both ordering and filtering for the columns in the grid:
component SmartGrid, {@source: users,
@columns: [
@UserName,
@Email,
@FullName
]
}
The columns parameter accepts an array of properties names, in this case ( "UserName", "Email", "FullName" ), and will display only those columns, ignoring all the columns that are not mentioned in the columns parameter. It will also render the columns in the order that they appear in the columns array.
Overriding behaviors for column headers:
Often you will want to customize the behavior of certain columns headers, maybe to provide an image in the header, or a <select> with a list of options. This is possible by utilizing another section overriding technique. The SGC will look for a section called [PropertyName]Header when it is about to render the header of a column, and will render the section instead if it exists.
Let us assume that we want to display the "UserName" property with the "User" text, the SGC will try to render that as "User Name", so we need to override this behavior:
section UserNameHeader: %> <th>User</th> <% end
Note that you should supply the <th> tags as well.
Overriding behaviors for column content:
By default, the SGC will render the result of a ToString() call on the property value of the object. This is not a good idea if your property refer to another object. Let us say that our User class has a property called Manager, also of type User, by default the SGC will show it as: "Castle.MonoRail.ViewComponents.TestSite.User", which is probably not what we want. We can override this behavior using a section [PropertyName], like this:
section Manager:
%>
<td>${IgnoreNull(value).Name}</td>
<%
end
Note: we use the IgnoreNull() to avoid having to do explicit check for null values.
The parameters for overriding a property rendering are:
- value - the value that we want to render in this column, in the example above, this is the value of the Manager property of the user.
- item - the current object that is the source for the data in the current row. In the example above, the user who is managed by the manager.
Handling empty data sources
Just like the [Grid Component], we can override the empty behavior for the SGC by using the empty section.
Start & End cell/header overrides
By default, the SGC will render <th> and <td> tags for headers and cells, respectively. Occasionally, you may wish to override this behavior, as you can probably guess, you can override this behavior by using the following sections:
- startHeaderCell - default = "<th class='grid_header'>"
- endHeaderCell - default = "</th>"
- startCell - default = "<td>"
- endCell - default = "</td>"
As you noticed, this apply to the entire grid, if you wish to override the rendering of a specific cell/header start/end only, you need to override the entire cell. Note that overriding the startCell, for instance, has no affect on cells that has been individually overriden.
Start & End row overrides
By default, the SGC will render rows with css classes 'grid_item' and 'grid_alternateItem' respectively. You can override this behaviour to enabling an additional id attribute for each row with the following sections:
- startRow - default = "<tr class='grid_item'>"
- endRow - default = "</tr>"
- startAlternateRow - default = "<tr class='grid_alternateItem'>"
- endAlternateRow - default = "</tr>"
<% component SmartGrid, {@source: users, @columns: [ @Email, @Name ] } : section startRow: %> <tr id='user_${item.Id}' class='grid_item'> <% end section startAlternateRow: %> <tr id='user_${item.Id}' class='grid_alternateItem'> <% end end %>Theese sections can access the current row item using the item parameter.
Handling additional columns
Fairly often, we need to handle additional columns in the grid, columns such as remove/edit, for instance. The SGC supports this use case by the use of two sections. The moreHeader section will be render after all the header columns has been rendered and the more section will be render after all the columns in each row has been rendered.
<%
component SmartGrid, {@source: users,
@columns: [
@Email,
@Name
]
} :
section moreHeader:
%>
<th>edit</th>
<th>delete</th>
<%
end
section more:
%>
<td>Edit - ${item.Name}</td>
<td>Remove - ${item.Name}</td>
<%
end
end
%>
The moreHeader section has no parameters, but the more section can access the current row item using the item parameter.
